pain
This commit is contained in:
295
script.sql
295
script.sql
@@ -1,27 +1,5 @@
|
||||
|
||||
DROP VIEW studenten_veranstalter;
|
||||
|
||||
DROP TABLE Veranstalter_Veranstaltung_Uhrzeit;
|
||||
DROP TABLE Studenten;
|
||||
DROP TABLE Veranstalter;
|
||||
DROP TABLE Uhrzeit;
|
||||
DROP TABLE veranstaltung;
|
||||
DROP SEQUENCE global_id_seq;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE SEQUENCE global_id_seq START WITH 1000000 INCREMENT BY 1;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Studenten (
|
||||
matrikelnummer INTEGER PRIMARY KEY DEFAULT nextval('global_id_seq'),
|
||||
name VARCHAR(30) NOT NULL,
|
||||
email VARCHAR(30) NOT NULL,
|
||||
passwort VARCHAR(30) NOT NULL
|
||||
);
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION random_between_two()
|
||||
RETURNS VARCHAR AS $$
|
||||
BEGIN
|
||||
@@ -33,14 +11,28 @@ BEGIN
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION random_between_days()
|
||||
RETURNS INTEGER AS $$
|
||||
BEGIN
|
||||
RETURN floor(random() * 5 + 1)::INTEGER;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TABLE Uhrzeit (
|
||||
CREATE TABLE IF NOT EXISTS Uhrzeit (
|
||||
ID SERIAL PRIMARY KEY,
|
||||
anfangszeit TIME NOT NULL,
|
||||
endzeit TIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE Veranstalter (
|
||||
CREATE TABLE IF NOT EXISTS Veranstaltung(
|
||||
name VARCHAR(3) PRIMARY KEY,
|
||||
ort VARCHAR(1) DEFAULT random_between_two(),
|
||||
raum INTEGER NOT NULL,
|
||||
dauer INTEGER NOT NULL,
|
||||
used_in_plan INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Veranstalter(
|
||||
ID INTEGER PRIMARY KEY DEFAULT nextval('global_id_seq'),
|
||||
name VARCHAR(30),
|
||||
email VARCHAR(30),
|
||||
@@ -49,111 +41,196 @@ CREATE TABLE Veranstalter (
|
||||
admin BOOLEAN NOT NULL DEFAULT FALSE
|
||||
);
|
||||
|
||||
|
||||
CREATE VIEW studenten_veranstalter AS
|
||||
SELECT matrikelnummer AS id, passwort, NULL AS admin FROM Studenten
|
||||
UNION ALL
|
||||
SELECT ID, passwort, admin FROM Veranstalter;
|
||||
|
||||
|
||||
|
||||
CREATE TABLE Veranstaltung (
|
||||
ID SERIAL PRIMARY KEY,
|
||||
ort VARCHAR(1) DEFAULT random_between_two(),
|
||||
raum INTEGER NOT NULL,
|
||||
name VARCHAR(3) NOT NULL UNIQUE,
|
||||
dauer INTEGER NOT NULL,
|
||||
used INTEGER DEFAULT(0)
|
||||
);
|
||||
|
||||
CREATE TABLE StundenImPlan(
|
||||
uhrzeit_ID INTEGER REFERENCES Uhrzeit(ID),
|
||||
CREATE TABLE IF NOT EXISTS StundeImPlan (
|
||||
uhrzeit INTEGER REFERENCES Uhrzeit(ID),
|
||||
tag INTEGER NOT NULL,
|
||||
veranstalter_ID INTEGER REFERENCES Veranstalter(ID) ON DELETE CASCADE,
|
||||
veranstaltung_ID INTEGER REFERENCES Veranstaltung(ID) ON DELETE CASCADE,
|
||||
PRIMARY KEY(uhrzeit_ID, tag)
|
||||
veranstaltung VARCHAR(3) REFERENCES Veranstaltung(name),
|
||||
veranstalter INTEGER REFERENCES Veranstalter(ID),
|
||||
PRIMARY KEY(uhrzeit, tag)
|
||||
);
|
||||
|
||||
CREATE TABLE Krankmeldung(
|
||||
uhrzeit_id INTEGER REFERENCES StundenImPlan(uhrzeit_ID),
|
||||
tag INTEGER REFERENCES StundenImPlan(tag),
|
||||
veranstalter_id INTEGER REFERENCES StundenImPlan(veranstalter_ID) ON DELETE CASCADE,
|
||||
PRIMARY KEY (uhrzeit_ID,tag,veranstalter_id)
|
||||
)
|
||||
CREATE TABLE IF NOT EXISTS Krank(
|
||||
ID SERIAL PRIMARY KEY,
|
||||
stundeImPlan_uhrzeit INTEGER,
|
||||
stundeImPlan_tag INTEGER,
|
||||
veranstalter INTEGER REFERENCES Veranstalter(ID),
|
||||
krank BOOLEAN DEFAULT FALSE,
|
||||
FOREIGN KEY (stundeImPlan_uhrzeit, stundeImPlan_tag) REFERENCES StundeImPlan(uhrzeit, tag)
|
||||
);
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION handle_veranstalter_update() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
neuer_veranstalter INTEGER;
|
||||
-- Function to delete StundeImPlan when Veranstaltung is deleted
|
||||
CREATE OR REPLACE FUNCTION delete_stundeimplan_for_veranstaltung()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- Wenn die Veranstalter_ID auf NULL gesetzt wird oder ein Veranstalter gelöscht wird
|
||||
IF TG_OP = 'UPDATE' AND NEW.veranstalter_ID IS NULL THEN
|
||||
-- Eintrag in die Krankmeldung
|
||||
INSERT INTO Krankmeldung (uhrzeit_ID, tag, veranstalter_id)
|
||||
VALUES (OLD.uhrzeit_ID, OLD.tag, OLD.veranstalter_ID);
|
||||
ELSIF TG_OP = 'DELETE' THEN
|
||||
-- Eintrag in die Krankmeldung für jede betroffene Stunde
|
||||
INSERT INTO Krankmeldung (uhrzeit_ID, tag, veranstalter_id)
|
||||
SELECT uhrzeit_ID, tag, OLD.ID FROM StundenImPlan WHERE veranstalter_ID = OLD.ID;
|
||||
END IF;
|
||||
DELETE FROM StundeImPlan WHERE veranstaltung = OLD.name;
|
||||
RETURN OLD;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Finde den Veranstalter mit den wenigsten Arbeitsstunden,
|
||||
-- der am selben Tag keine Veranstaltung in einer anderen Uhrzeit an einem anderen Ort hat
|
||||
SELECT ID INTO neuer_veranstalter
|
||||
-- Trigger to call the above function
|
||||
CREATE TRIGGER trg_delete_stundeimplan_for_veranstaltung
|
||||
AFTER DELETE ON Veranstaltung
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION delete_stundeimplan_for_veranstaltung();
|
||||
|
||||
-- Function to update StundeImPlan when Veranstalter is deleted
|
||||
CREATE OR REPLACE FUNCTION update_stundeimplan_for_veranstalter()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
new_veranstalter_id INTEGER;
|
||||
BEGIN
|
||||
SELECT ID INTO new_veranstalter_id
|
||||
FROM Veranstalter
|
||||
WHERE ID NOT IN (
|
||||
SELECT veranstalter_ID FROM StundenImPlan
|
||||
WHERE tag = OLD.tag
|
||||
AND uhrzeit_ID != OLD.uhrzeit_ID
|
||||
AND veranstaltung_ID IN (
|
||||
SELECT ID FROM Veranstaltung WHERE ort != (
|
||||
SELECT ort FROM Veranstaltung WHERE ID = NEW.veranstaltung_ID
|
||||
)
|
||||
)
|
||||
)
|
||||
WHERE arbeitszeit < 18
|
||||
ORDER BY arbeitszeit ASC
|
||||
LIMIT 1;
|
||||
|
||||
-- Wenn ein neuer Veranstalter gefunden wurde
|
||||
IF neuer_veranstalter IS NOT NULL THEN
|
||||
IF TG_OP = 'UPDATE' THEN
|
||||
NEW.veranstalter_ID := neuer_veranstalter;
|
||||
ELSIF TG_OP = 'DELETE' THEN
|
||||
UPDATE StundenImPlan
|
||||
SET veranstalter_ID = neuer_veranstalter
|
||||
WHERE veranstalter_ID = OLD.ID;
|
||||
IF new_veranstalter_id IS NOT NULL THEN
|
||||
UPDATE StundeImPlan
|
||||
SET veranstalter = new_veranstalter_id
|
||||
WHERE veranstalter = OLD.ID;
|
||||
END IF;
|
||||
-- Update der Arbeitszeit des neuen Veranstalters
|
||||
|
||||
RETURN OLD;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger to call the above function
|
||||
CREATE TRIGGER trg_update_stundeimplan_for_veranstalter
|
||||
AFTER DELETE ON Veranstalter
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_stundeimplan_for_veranstalter();
|
||||
|
||||
-- Function to update arbeitszeit of Veranstalter when assigned to StundeImPlan
|
||||
CREATE OR REPLACE FUNCTION update_arbeitszeit_for_veranstalter()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
UPDATE Veranstalter
|
||||
SET arbeitszeit = arbeitszeit + (
|
||||
SELECT dauer FROM Veranstaltung WHERE ID = (
|
||||
CASE WHEN TG_OP = 'UPDATE' THEN NEW.veranstaltung_ID ELSE OLD.ID END
|
||||
)
|
||||
)
|
||||
WHERE ID = neuer_veranstalter;
|
||||
ELSE
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
UPDATE StundenImPlan
|
||||
SET veranstalter_ID = NULL
|
||||
WHERE veranstalter_ID = OLD.ID;
|
||||
SET arbeitszeit = arbeitszeit + (SELECT dauer FROM Veranstaltung WHERE name = NEW.veranstaltung)
|
||||
WHERE ID = NEW.veranstalter;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Trigger to call the above function
|
||||
CREATE TRIGGER trg_update_arbeitszeit_for_veranstalter
|
||||
AFTER INSERT ON StundeImPlan
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_arbeitszeit_for_veranstalter();
|
||||
|
||||
-- Function to generate the plan
|
||||
CREATE OR REPLACE FUNCTION generate_plan()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_row RECORD;
|
||||
u_row RECORD;
|
||||
available_veranstalter RECORD;
|
||||
random_day INTEGER;
|
||||
BEGIN
|
||||
-- Loop through each available time slot
|
||||
FOR u_row IN SELECT * FROM Uhrzeit LOOP
|
||||
-- Loop through each available Veranstaltung
|
||||
FOR v_row IN SELECT * FROM Veranstaltung WHERE used_in_plan = 0 LOOP
|
||||
-- Find an available Veranstalter
|
||||
SELECT * INTO available_veranstalter
|
||||
FROM Veranstalter
|
||||
WHERE arbeitszeit + v_row.dauer <= 18
|
||||
ORDER BY arbeitszeit ASC
|
||||
LIMIT 1;
|
||||
|
||||
IF FOUND THEN
|
||||
-- Check if there is already an event scheduled for this tag and uhrzeit combination
|
||||
|
||||
random_day = random_between_days();
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM StundeImPlan
|
||||
WHERE uhrzeit = u_row.ID AND tag = random_day
|
||||
) THEN
|
||||
-- If an available Veranstalter is found, insert into StundeImPlan
|
||||
INSERT INTO StundeImPlan (uhrzeit, tag, veranstaltung, veranstalter)
|
||||
VALUES (u_row.ID, random_day, v_row.name, available_veranstalter.ID);
|
||||
|
||||
-- Update the used_in_plan flag and arbeitszeit
|
||||
UPDATE Veranstaltung SET used_in_plan = used_in_plan + 1 WHERE name = v_row.name;
|
||||
UPDATE Veranstalter SET arbeitszeit = arbeitszeit + v_row.dauer WHERE ID = available_veranstalter.ID;
|
||||
END IF;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END LOOP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trg_generate_plan
|
||||
AFTER INSERT ON Veranstaltung
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION generate_plan();
|
||||
|
||||
CREATE OR REPLACE FUNCTION handle_krank_insert()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
new_veranstalter_id INTEGER;
|
||||
v_name VARCHAR(3);
|
||||
BEGIN
|
||||
-- Find a new veranstalter for the same stundeImPlan
|
||||
SELECT veranstaltung.name INTO v_name
|
||||
FROM Veranstaltung
|
||||
WHERE name = (SELECT veranstaltung FROM StundeImPlan WHERE uhrzeit = NEW.stundeImPlan_uhrzeit AND tag = NEW.stundeImPlan_tag);
|
||||
|
||||
WITH PreviousHour AS (
|
||||
SELECT sp.veranstalter, v.ort
|
||||
FROM StundeImPlan sp
|
||||
JOIN Veranstaltung v ON sp.veranstaltung = v.name
|
||||
WHERE sp.uhrzeit = NEW.stundeImPlan_uhrzeit - 1
|
||||
AND sp.tag = NEW.stundeImPlan_tag
|
||||
)
|
||||
SELECT ID INTO new_veranstalter_id
|
||||
FROM Veranstalter v
|
||||
JOIN StundeImPlan sp ON v.ID = sp.veranstalter
|
||||
JOIN Veranstaltung va ON sp.veranstaltung = va.name
|
||||
LEFT JOIN PreviousHour ph ON sp.uhrzeit = NEW.stundeImPlan_uhrzeit AND sp.tag = NEW.stundeImPlan_tag - 1
|
||||
WHERE arbeitszeit + (SELECT dauer FROM Veranstaltung WHERE name = v_name) <= 18
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM Krank k
|
||||
WHERE k.veranstalter = v.ID
|
||||
AND k.stundeImPlan_uhrzeit = NEW.stundeImPlan_uhrzeit
|
||||
AND k.stundeImPlan_tag = NEW.stundeImPlan_tag
|
||||
)
|
||||
AND (ph.veranstalter IS NULL OR v.ID <> ph.veranstalter OR va.ort = ph.ort)
|
||||
ORDER BY arbeitszeit ASC
|
||||
LIMIT 1;
|
||||
|
||||
SELECT ID INTO new_veranstalter_id
|
||||
FROM Veranstalter v
|
||||
WHERE arbeitszeit + (SELECT dauer FROM Veranstaltung WHERE name = v_name) <= 18
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM Krank k
|
||||
WHERE k.veranstalter = v.ID
|
||||
AND k.stundeImPlan_uhrzeit = NEW.stundeImPlan_uhrzeit
|
||||
AND k.stundeImPlan_tag = NEW.stundeImPlan_tag
|
||||
);
|
||||
|
||||
|
||||
UPDATE Veranstalter
|
||||
SET arbeitszeit = arbeitszeit + (SELECT dauer FROM Veranstaltung WHERE name = v_name)
|
||||
WHERE ID = new_veranstalter_id;
|
||||
|
||||
-- Update the StundeImPlan with the replacement or NULL
|
||||
UPDATE StundeImPlan
|
||||
SET veranstalter = COALESCE(new_veranstalter_id, NULL)
|
||||
WHERE uhrzeit = NEW.stundeImPlan_uhrzeit AND tag = NEW.stundeImPlan_tag;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trg_handle_veranstalter_update
|
||||
BEFORE UPDATE ON StundenImPlan
|
||||
CREATE TRIGGER trg_handle_krank_insert
|
||||
AFTER INSERT ON Krank
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION handle_veranstalter_update();
|
||||
|
||||
CREATE TRIGGER trg_handle_veranstalter_delete
|
||||
BEFORE DELETE ON Veranstalter
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION handle_veranstalter_update();
|
||||
|
||||
|
||||
EXECUTE FUNCTION handle_krank_insert();
|
||||
|
||||
INSERT INTO Uhrzeit (anfangszeit, endzeit) VALUES
|
||||
('08:00:00', '10:00:00'),
|
||||
|
||||
@@ -5,32 +5,28 @@ EinsatzplanFrameController::EinsatzplanFrameController(QString id, bool admin)
|
||||
m_admin(admin) {
|
||||
const std::map<std::string, std::string> config = load_config( );
|
||||
|
||||
m_connectionString = fmt::format(
|
||||
m_dbHandler = std::make_unique<DBHandler>(fmt::format(
|
||||
"host={} port={} dbname={} user={} password={}",
|
||||
config.at("DB_HOST"),
|
||||
config.at("DB_PORT"),
|
||||
config.at("DB_NAME"),
|
||||
config.at("DB_USER"),
|
||||
config.at("DB_PASSWORD")
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
void EinsatzplanFrameController::deleteMember(QString id) {
|
||||
DBHandler* db = new DBHandler(m_connectionString);
|
||||
db->deleteVeranstalter(id.toStdString( ));
|
||||
m_dbHandler->deleteVeranstalter(id.toStdString( ));
|
||||
}
|
||||
|
||||
void EinsatzplanFrameController::deleteVeranstaltung(QString veranstaltungsname) {
|
||||
DBHandler* db = new DBHandler(m_connectionString);
|
||||
db->deleteVeranstaltung(veranstaltungsname.toStdString( ));
|
||||
m_dbHandler->deleteVeranstaltung(veranstaltungsname.toStdString( ));
|
||||
}
|
||||
|
||||
void EinsatzplanFrameController::createMember(QString name, QString email, QString passwort, bool admin) {
|
||||
DBHandler* db = new DBHandler(m_connectionString);
|
||||
db->createVeranstalter(email.toStdString( ), name.toStdString( ), passwort.toStdString( ), admin ? "TRUE" : "FALSE");
|
||||
m_dbHandler->createVeranstalter(name.toStdString( ), email.toStdString( ), passwort.toStdString( ), admin);
|
||||
}
|
||||
|
||||
void EinsatzplanFrameController::createVeranstaltung(QString name, QString raum, QString campus, QString time) {
|
||||
DBHandler* db = new DBHandler(m_connectionString);
|
||||
db->createVeranstaltung(name.toStdString( ), std::to_string((char)time.toStdString( ).at(0) - 48), campus.toStdString( ), raum.toStdString( ));
|
||||
m_dbHandler->createVeranstaltung(name.toStdString( ), campus.toStdString( ), raum.toStdString( ), std::to_string((char)time.toStdString( ).at(0) - 48));
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
#include <QString>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "../../Core/DBHandler/DBHandler/DBHandler.hpp"
|
||||
#include "../../Core/DBHandler/DBHandler.hpp"
|
||||
#include "../../Core/config/config.hpp"
|
||||
|
||||
class EinsatzplanFrameController {
|
||||
private:
|
||||
std::string m_connectionString;
|
||||
std::unique_ptr<DBHandler> m_dbHandler;
|
||||
|
||||
protected:
|
||||
QString m_id;
|
||||
@@ -20,4 +20,5 @@ public:
|
||||
void deleteVeranstaltung(QString veranstaltungsname);
|
||||
void createMember(QString name, QString email, QString passwort, bool admin);
|
||||
void createVeranstaltung(QString name, QString raum, QString campus, QString time);
|
||||
|
||||
};
|
||||
|
||||
@@ -3,18 +3,16 @@
|
||||
LoginFrameController::LoginFrameController( ) {
|
||||
auto config = load_config( );
|
||||
|
||||
m_connectionString = fmt::format(
|
||||
m_dbHandler = std::make_unique<DBHandler>(fmt::format(
|
||||
"host={} port={} dbname={} user={} password={}",
|
||||
config.at("DB_HOST"),
|
||||
config.at("DB_PORT"),
|
||||
config.at("DB_NAME"),
|
||||
config.at("DB_USER"),
|
||||
config.at("DB_PASSWORD")
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
int LoginFrameController::tryLogin(QString id, QString password) {
|
||||
DBLogin* loginHandler = new DBLogin(m_connectionString);
|
||||
|
||||
return loginHandler->checkValidLogin(id.toStdString( ), password.toStdString( ));
|
||||
return m_dbHandler->tryAuthenticate(id.toStdString( ), password.toStdString( ));
|
||||
}
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
#include <QString>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "../../Core/DBHandler/DBLogin/DBLogin.hpp"
|
||||
#include "../../Core/DBHandler/DBHandler.hpp"
|
||||
#include "../../Core/config/config.hpp"
|
||||
|
||||
class LoginFrameController {
|
||||
private:
|
||||
std::string m_connectionString;
|
||||
std::unique_ptr<DBHandler> m_dbHandler;
|
||||
|
||||
public:
|
||||
LoginFrameController( );
|
||||
|
||||
int tryLogin(QString id, QString password);
|
||||
|
||||
};
|
||||
|
||||
@@ -17,20 +17,18 @@ PlanGridController::PlanGridController( ) {
|
||||
|
||||
const std::map<std::string, std::string> config = load_config( );
|
||||
|
||||
m_connectionString = fmt::format(
|
||||
m_dbHandler = std::make_unique<DBHandler>(fmt::format(
|
||||
"host={} port={} dbname={} user={} password={}",
|
||||
config.at("DB_HOST"),
|
||||
config.at("DB_PORT"),
|
||||
config.at("DB_NAME"),
|
||||
config.at("DB_USER"),
|
||||
config.at("DB_PASSWORD")
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
QMap<QPair<QString, QString>, QWidget*>* PlanGridController::getVeranstaltungen( ) {
|
||||
DBHandler* db = new DBHandler(m_connectionString);
|
||||
|
||||
std::vector<std::string> planData = db->getVeranstaltung( );
|
||||
std::vector<std::string> planData = m_dbHandler->getPlan( );
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
@@ -118,17 +116,35 @@ QMap<QPair<QString, QString>, QWidget*>* PlanGridController::getVeranstaltungen(
|
||||
)"));
|
||||
|
||||
container->setFixedSize(240, 100);
|
||||
if (infoVector.at(8) == "4") {
|
||||
planMap->insert(qMakePair(
|
||||
weekdays[std::stoi(infoVector.at(0)) - 1],
|
||||
QString::fromStdString(infoVector.at(1).erase(5, 8))),
|
||||
container);
|
||||
|
||||
std::string originalString = infoVector.at(1);
|
||||
if (originalString.length( ) >= 2) {
|
||||
char secondChar = originalString[1];
|
||||
secondChar += 2;
|
||||
originalString[1] = secondChar;
|
||||
}
|
||||
|
||||
planMap->insert(qMakePair(
|
||||
weekdays[std::stoi(infoVector.at(0)) - 1],
|
||||
QString::fromStdString(originalString)),
|
||||
container);
|
||||
} else {
|
||||
|
||||
planMap->insert(qMakePair(
|
||||
weekdays[std::stoi(infoVector.at(0)) - 1],
|
||||
QString::fromStdString(infoVector.at(1).erase(5, 8))),
|
||||
container);
|
||||
}
|
||||
}
|
||||
|
||||
return planMap;
|
||||
}
|
||||
|
||||
void PlanGridController::Krankmelden(const int id, int tag, int stunde) {
|
||||
DBHandler db(m_connectionString);
|
||||
|
||||
db.meldeKrank(std::to_string(id), std::to_string(tag), std::to_string(stunde));
|
||||
void PlanGridController::Krankmelden(const int id, const int tag, const std::string& uhrzeit) {
|
||||
m_dbHandler->krankmelden(std::to_string(id), uhrzeit, tag);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
#include <QPushButton>
|
||||
|
||||
#include "../../Core/config/config.hpp"
|
||||
#include "../../Core/DBHandler/DBHandler/DBHandler.hpp"
|
||||
#include "../../Core/DBHandler/DBHandler.hpp"
|
||||
|
||||
class PlanGridController : public QObject {
|
||||
Q_OBJECT
|
||||
private:
|
||||
std::string m_connectionString;
|
||||
std::unique_ptr<DBHandler> m_dbHandler;
|
||||
|
||||
protected:
|
||||
QString weekdays[5];
|
||||
QString times[5];
|
||||
@@ -22,5 +23,5 @@ public:
|
||||
PlanGridController( );
|
||||
|
||||
QMap<QPair<QString, QString>, QWidget*>* getVeranstaltungen( );
|
||||
void Krankmelden(const int id, const int tag, const int stunde);
|
||||
void Krankmelden(const int id, const int tag, const std::string& uhrzeit);
|
||||
};
|
||||
|
||||
168
src/Core/DBHandler/DBHandler.cpp
Normal file
168
src/Core/DBHandler/DBHandler.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "DBHandler.hpp"
|
||||
|
||||
DBHandler::DBHandler(const std::string& connStr) :
|
||||
m_dbConnection(std::make_unique<pqxx::connection>(connStr.c_str( ))) {
|
||||
try {
|
||||
m_dbConnection->is_open( ) ?
|
||||
fmt::print("Databased connected") :
|
||||
fmt::print("Failed to connect to Databased");
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
}
|
||||
};
|
||||
|
||||
int DBHandler::tryAuthenticate(std::string id, std::string pw) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
|
||||
std::string query =
|
||||
"SELECT admin FROM veranstalter WHERE id = $1 AND passwort = $2";
|
||||
|
||||
pqxx::result response = W.exec_params(query, id, pw);
|
||||
|
||||
return response.affected_rows( ) > 0 ? response[0][0].as<bool>( ) : -1;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool DBHandler::createVeranstalter(const std::string& name, const std::string& email, const std::string& password, bool admin) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string admin_value = admin ? "TRUE" : "FALSE";
|
||||
std::string query = fmt::format(
|
||||
"INSERT INTO Veranstalter (name, email, passwort, admin) VALUES ({}, {}, {}, {})",
|
||||
W.quote(name), W.quote(email), W.quote(password), admin_value
|
||||
);
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBHandler::deleteVeranstalter(int id) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string query = fmt::format(
|
||||
"DELETE FROM Veranstalter WHERE ID = {}", W.quote(id)
|
||||
);
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBHandler::deleteVeranstalter(const std::string& name) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string query = fmt::format(
|
||||
"DELETE FROM Veranstalter WHERE name = {}", W.quote(name)
|
||||
);
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBHandler::createVeranstaltung(const std::string& name, const std::string& campus, const std::string& raum, const std::string& dauer) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string cmp(1, campus.back( ));
|
||||
std::string query = fmt::format(
|
||||
"INSERT INTO Veranstaltung (name, ort, raum, dauer) VALUES ({}, {}, {}, {})",
|
||||
W.quote(name), W.quote(cmp), W.quote(raum), W.quote(dauer)
|
||||
);
|
||||
fmt::println(query);
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBHandler::deleteVeranstaltung(const std::string& name) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string query = fmt::format(
|
||||
"DELETE FROM Veranstaltung WHERE name = {}", W.quote(name)
|
||||
);
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBHandler::krankmelden(const std::string& veranstalter, const std::string& uhrzeit, int tag) {
|
||||
try {
|
||||
pqxx::work W(*m_dbConnection.get( ));
|
||||
std::string query =
|
||||
"INSERT INTO Krank (stundeImPlan_uhrzeit, stundeImPlan_tag, veranstalter, krank) "
|
||||
"SELECT SIP.uhrzeit, SIP.tag, V.ID, TRUE "
|
||||
"FROM StundeImPlan SIP "
|
||||
"JOIN Veranstalter V ON SIP.veranstalter = V.ID "
|
||||
"JOIN Uhrzeit U ON SIP.uhrzeit = U.ID "
|
||||
"JOIN Veranstaltung VA ON SIP.veranstaltung = VA.name "
|
||||
"WHERE V.id = " + W.quote(veranstalter) +
|
||||
" AND U.anfangszeit = " + W.quote(std::string(uhrzeit + ":00")) +
|
||||
" AND SIP.tag = " + W.quote(tag) + ";";
|
||||
|
||||
W.exec(query);
|
||||
W.commit( );
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> DBHandler::getPlan( ) {
|
||||
std::vector<std::string> plan;
|
||||
try {
|
||||
pqxx::nontransaction N(*m_dbConnection.get( ));
|
||||
std::string query =
|
||||
R"(SELECT SIP.tag, U.anfangszeit, U.endzeit, VA.ort, VA.name AS veranstaltungsname, V.name AS veranstaltername, VA.raum, SIP.veranstalter, VA.dauer
|
||||
FROM StundeImPlan SIP
|
||||
JOIN Uhrzeit U ON SIP.uhrzeit = U.ID
|
||||
JOIN Veranstaltung VA ON SIP.veranstaltung = VA.name
|
||||
JOIN Veranstalter V ON SIP.veranstalter = V.ID
|
||||
ORDER BY U.anfangszeit)";
|
||||
pqxx::result R(N.exec(query));
|
||||
|
||||
for (auto row : R) {
|
||||
std::string entry = fmt::format(
|
||||
"{},{},{},{},{},{},{},{},{}",
|
||||
row["tag"].c_str( ), row["anfangszeit"].c_str( ), row["endzeit"].c_str( ), row["ort"].c_str( ),
|
||||
row["veranstaltungsname"].c_str( ), row["veranstaltername"].c_str( ), row["raum"].c_str( ), row["veranstalter"].c_str( ), row["dauer"].c_str( )
|
||||
);
|
||||
plan.push_back(entry);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
34
src/Core/DBHandler/DBHandler.hpp
Normal file
34
src/Core/DBHandler/DBHandler.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <pqxx/pqxx>
|
||||
#include <string>
|
||||
#include <fmt/core.h>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
|
||||
class DBHandler {
|
||||
private:
|
||||
std::unique_ptr<pqxx::connection> m_dbConnection;
|
||||
|
||||
public:
|
||||
DBHandler(const std::string& connStr);
|
||||
|
||||
/**
|
||||
* @brief Tries to login the user
|
||||
* @param id user id
|
||||
* @param pw user password
|
||||
* @return returns 1 if admin and 0 if not
|
||||
*/
|
||||
int tryAuthenticate(std::string id, std::string pw);
|
||||
|
||||
bool createVeranstalter(const std::string& name, const std::string& email, const std::string& password, bool admin);
|
||||
bool deleteVeranstalter(int id);
|
||||
bool deleteVeranstalter(const std::string& name);
|
||||
|
||||
bool createVeranstaltung(const std::string& name, const std::string& campus, const std::string& time, const std::string& veranstalter);
|
||||
bool deleteVeranstaltung(const std::string& name);
|
||||
|
||||
bool krankmelden(const std::string& veranstalter, const std::string& uhrzeit, int tag);
|
||||
|
||||
std::vector<std::string> getPlan( );
|
||||
};
|
||||
@@ -1,204 +0,0 @@
|
||||
#include "DBHandler.hpp"
|
||||
|
||||
DBHandler::DBHandler(std::string connStr) :
|
||||
connectionObject(connStr.c_str( )) {
|
||||
try {
|
||||
if (connectionObject.is_open( ))
|
||||
fmt::print("Databased connected");
|
||||
else
|
||||
fmt::print("Failed to connect to Databased");
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print(e.what( ));
|
||||
}
|
||||
};
|
||||
|
||||
void DBHandler::deleteVeranstalter(std::string id){
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
std::string query = fmt::format("DELETE FROM Student WHERE id = {0}",id);
|
||||
worker.exec(query);
|
||||
worker.commit();
|
||||
query = fmt::format("DELETE FROM Veranstalter WHERE id = {0}",id);
|
||||
worker.exec_params(query);
|
||||
worker.commit();
|
||||
fmt::print("Veranstalter with ID {} deleted successfully.\n", id);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print("ERROR: {0}", e.what( ));
|
||||
}
|
||||
}
|
||||
|
||||
void DBHandler::deleteVeranstaltung(std::string name) {
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
std::string query = fmt::format("DELETE FROM Veranstaltung WHERE name = '{0}'", name);
|
||||
worker.exec(query);
|
||||
worker.commit();
|
||||
fmt::print("Veranstaltung with name '{}' deleted successfully.\n", name);
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error deleting Veranstaltung: {}\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void DBHandler::createVeranstalter(std::string email, std::string name, std::string passwort, std::string admin) {
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
std::string query = fmt::format(
|
||||
"INSERT INTO Veranstalter (email, name, passwort, admin) VALUES ('{}', '{}', '{}', {})",
|
||||
email, name, passwort, admin
|
||||
);
|
||||
worker.exec(query);
|
||||
worker.commit();
|
||||
fmt::print("Veranstalter {} created successfully.\n", name);
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error creating Veranstalter: {}\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void DBHandler::createVeranstaltung(std::string name, std::string uhrzeit, std::string standort, std::string raum) {
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
std::string query = fmt::format(
|
||||
"INSERT INTO Veranstaltung (name, uhrzeit, standort, raum) VALUES ('{}', '{}', '{}', '{}')",
|
||||
name, uhrzeit, standort, raum
|
||||
);
|
||||
worker.exec(query);
|
||||
worker.commit();
|
||||
fmt::print("Veranstaltung {} created successfully.\n", name);
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error creating Veranstaltung: {}\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void DBHandler::createEinsatzplan() {
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
|
||||
// Fetch all Veranstaltungen
|
||||
pqxx::result veranstaltungen = worker.exec("SELECT ID, dauer, used FROM Veranstaltung");
|
||||
|
||||
// Fetch all available Uhrzeiten
|
||||
std::vector<int> uhrzeiten = {1, 2, 3, 4, 5}; // Representing 1 to 5 time slots
|
||||
|
||||
// Fetch all available Veranstalter
|
||||
pqxx::result veranstalter = worker.exec("SELECT ID FROM Veranstalter");
|
||||
|
||||
std::mt19937 rng(static_cast<unsigned int>(std::time(nullptr))); // Random number generator
|
||||
std::uniform_int_distribution<int> day_dist(1, 5); // Random days between 1 and 5 (Monday to Friday)
|
||||
|
||||
for (auto row : veranstaltungen) {
|
||||
int veranstaltungID = row["id"].as<int>();
|
||||
int dauer = row["dauer"].as<int>();
|
||||
int used = row["used"].as<int>();
|
||||
|
||||
while (used < dauer) {
|
||||
// Randomly select a day
|
||||
int day = day_dist(rng);
|
||||
|
||||
// Randomly select a Uhrzeit
|
||||
std::uniform_int_distribution<int> uhrzeit_dist(0, uhrzeiten.size() - 1);
|
||||
int uhrzeitIndex = uhrzeit_dist(rng);
|
||||
int uhrzeitID = uhrzeiten[uhrzeitIndex];
|
||||
|
||||
// Randomly select a Veranstalter
|
||||
std::uniform_int_distribution<int> veranstalter_dist(0, veranstalter.size() - 1);
|
||||
int veranstalterIndex = veranstalter_dist(rng);
|
||||
int veranstalterID = veranstalter[veranstalterIndex]["id"].as<int>();
|
||||
|
||||
// Check if the selected Veranstalter is valid for the selected time and location
|
||||
std::string checkQuery = fmt::format(
|
||||
"SELECT COUNT(*) FROM StundenImPlan sip "
|
||||
"JOIN Veranstaltung v ON sip.veranstaltung_ID = v.ID "
|
||||
"WHERE sip.tag = {} AND (sip.uhrzeit_ID = {} OR sip.uhrzeit_ID = {} - 1) "
|
||||
"AND v.ort != (SELECT ort FROM Veranstaltung WHERE ID = {}) "
|
||||
"AND sip.veranstalter_ID = {}",
|
||||
day, uhrzeitID, uhrzeitID, veranstaltungID, veranstalterID);
|
||||
pqxx::result checkResult = worker.exec(checkQuery);
|
||||
int count = checkResult[0][0].as<int>();
|
||||
|
||||
if (count == 0) {
|
||||
// Assign to StundenImPlan
|
||||
std::string query = fmt::format(
|
||||
"INSERT INTO StundenImPlan (uhrzeit_ID, tag, veranstalter_ID, veranstaltung_ID) VALUES ({}, {}, {}, {})",
|
||||
uhrzeitID, day, veranstalterID, veranstaltungID
|
||||
);
|
||||
worker.exec(query);
|
||||
|
||||
// Update used count
|
||||
used += 2;
|
||||
std::string updateQuery = fmt::format(
|
||||
"UPDATE Veranstaltung SET used = {} WHERE ID = {}",
|
||||
used, veranstaltungID
|
||||
);
|
||||
worker.exec(updateQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
worker.commit();
|
||||
fmt::print("Random schedule assigned successfully.\n");
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error assigning random schedule: {}\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> DBHandler::getVeranstaltung() {
|
||||
std::vector<std::string> results;
|
||||
|
||||
try {
|
||||
pqxx::work txn(connectionObject);
|
||||
|
||||
// Check if StundenImPlan is empty
|
||||
std::string checkQuery = "SELECT COUNT(*) FROM StundenImPlan";
|
||||
pqxx::result countResult = txn.exec(checkQuery);
|
||||
int count = countResult[0][0].as<int>();
|
||||
|
||||
if (count == 0) {
|
||||
createEinsatzplan();
|
||||
}
|
||||
|
||||
// Fetch data from StundenImPlan
|
||||
pqxx::result stundenImPlanResult = txn.exec(
|
||||
"SELECT sip.tag, u.anfangszeit, u.endzeit, v.ort, v.name AS veranstaltungsname, "
|
||||
"a.name AS veranstaltername, v.raum, sip.veranstalter_ID "
|
||||
"FROM StundenImPlan sip "
|
||||
"JOIN Uhrzeit u ON sip.uhrzeit_ID = u.ID "
|
||||
"JOIN Veranstaltung v ON sip.veranstaltung_ID = v.ID "
|
||||
"JOIN Veranstalter a ON sip.veranstalter_ID = a.ID"
|
||||
);
|
||||
|
||||
// Format the results
|
||||
for (const auto &row : stundenImPlanResult) {
|
||||
std::string result = fmt::format("{},{},{},{},{},{},{},{}",
|
||||
row["tag"].as<int>(),
|
||||
row["anfangszeit"].as<std::string>(),
|
||||
row["endzeit"].as<std::string>(),
|
||||
row["ort"].as<std::string>(),
|
||||
row["veranstaltungsname"].as<std::string>(),
|
||||
row["veranstaltername"].as<std::string>(),
|
||||
row["raum"].as<std::string>(),
|
||||
row["veranstalter_id"].as<int>());
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
fmt::print(stderr, "Error retrieving Veranstaltung data: {}\n", e.what());
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void DBHandler::meldeKrank(std::string id, std::string tag, std::string stunde){
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
std::string query = fmt::format("Update StundeImPlan SET veranstalter_ID = NULL WHERE veranstalter_ID = {0}",id);
|
||||
worker.exec(query);
|
||||
worker.commit();
|
||||
fmt::print("Veranstalter with ID {} marked ill successfully.\n", id);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::print("ERROR: {0}", e.what( ));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pqxx/pqxx>
|
||||
#include <string>
|
||||
#include <fmt/core.h>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
|
||||
class DBHandler {
|
||||
protected:
|
||||
pqxx::connection connectionObject;
|
||||
|
||||
void createEinsatzplan();
|
||||
public:
|
||||
DBHandler(std::string connStr);
|
||||
void deleteVeranstalter(std::string id);
|
||||
void deleteVeranstaltung(std::string name);
|
||||
void createVeranstalter(std::string email, std::string name, std::string passwort, std::string admin);
|
||||
void createVeranstaltung(std::string name, std::string uhrzeit, std::string standort, std::string raum);
|
||||
std::vector<std::string> getVeranstaltung();
|
||||
void meldeKrank(std::string id, std::string tag, std::string stunde);
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "DBLogin.hpp"
|
||||
|
||||
DBLogin::DBLogin(std::string connStr) : DBHandler(connStr) { };
|
||||
|
||||
int DBLogin::checkValidLogin(std::string id, std::string pw) {
|
||||
try {
|
||||
pqxx::work worker(connectionObject);
|
||||
|
||||
std::string query =
|
||||
"SELECT admin FROM studenten_veranstalter WHERE id = $1 AND passwort = $2";
|
||||
|
||||
pqxx::result response = worker.exec_params(query, id, pw);
|
||||
|
||||
return response.affected_rows( ) > 0 ? response[0][0].as<bool>( ) : -1;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
fmt::printf("ERROR: %s", e.what( ));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fmt/printf.h>
|
||||
|
||||
#include "../DBHandler/DBHandler.hpp"
|
||||
|
||||
class DBLogin : public DBHandler {
|
||||
public:
|
||||
DBLogin(std::string connStr);
|
||||
|
||||
/**
|
||||
* @brief Tries to login the user
|
||||
* @param id user id
|
||||
* @param pw user password
|
||||
* @return returns 1 if admin and 0 if not
|
||||
*/
|
||||
int checkValidLogin(std::string id, std::string pw);
|
||||
};
|
||||
@@ -210,6 +210,8 @@ void EinsatzplanFrame::createVeranstaltung( ) {
|
||||
QString campus = dialog.getCampus( );
|
||||
QString time = dialog.getTime( );
|
||||
m_controller->createVeranstaltung(name, raum, campus, time);
|
||||
m_planGrid->setPlanMap(m_planGrid->planGridController->getVeranstaltungen( ));
|
||||
m_planGrid->populateGrid( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ void PlanGrid::populateGrid( ) {
|
||||
planGridController->Krankmelden(
|
||||
id,
|
||||
i + 1,
|
||||
j + 1
|
||||
m_times[j].toStdString( )
|
||||
);
|
||||
}
|
||||
planMap = planGridController->getVeranstaltungen( );
|
||||
|
||||
Reference in New Issue
Block a user