From 701a8c3a98040dc1df71117649217af48e533a35 Mon Sep 17 00:00:00 2001 From: Crylia Date: Mon, 8 Jul 2024 23:52:36 +0200 Subject: [PATCH] pain --- script.sql | 339 +++++++++++------- .../EinsatzplanFrameController.cpp | 16 +- .../EinsatzplanFrameController.hpp | 5 +- .../LoginFrameController.cpp | 8 +- .../LoginFrameController.hpp | 7 +- .../PlanGridController/PlanGridController.cpp | 42 ++- .../PlanGridController/PlanGridController.hpp | 7 +- src/Core/DBHandler/DBHandler.cpp | 168 +++++++++ src/Core/DBHandler/DBHandler.hpp | 34 ++ src/Core/DBHandler/DBHandler/DBHandler.cpp | 204 ----------- src/Core/DBHandler/DBHandler/DBHandler.hpp | 22 -- src/Core/DBHandler/DBLogin/DBLogin.cpp | 22 -- src/Core/DBHandler/DBLogin/DBLogin.hpp | 18 - .../EinsatzplanFrame/EinsatzplanFrame.cpp | 2 + src/View/PlanGrid/PlanGrid.cpp | 2 +- 15 files changed, 463 insertions(+), 433 deletions(-) create mode 100644 src/Core/DBHandler/DBHandler.cpp create mode 100644 src/Core/DBHandler/DBHandler.hpp delete mode 100644 src/Core/DBHandler/DBHandler/DBHandler.cpp delete mode 100644 src/Core/DBHandler/DBHandler/DBHandler.hpp delete mode 100644 src/Core/DBHandler/DBLogin/DBLogin.cpp delete mode 100644 src/Core/DBHandler/DBLogin/DBLogin.hpp diff --git a/script.sql b/script.sql index 1d8a082..3b430b6 100644 --- a/script.sql +++ b/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,127 +11,226 @@ BEGIN END; $$ LANGUAGE plpgsql; - -CREATE TABLE Uhrzeit ( - ID SERIAL PRIMARY KEY, - anfangszeit TIME NOT NULL, - endzeit TIME NOT NULL -); - -CREATE TABLE Veranstalter ( - ID INTEGER PRIMARY KEY DEFAULT nextval('global_id_seq'), - name VARCHAR(30), - email VARCHAR(30), - passwort VARCHAR(30), - arbeitszeit INTEGER DEFAULT 0, - 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), - 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) -); - -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 OR REPLACE FUNCTION handle_veranstalter_update() RETURNS TRIGGER AS $$ -DECLARE - neuer_veranstalter INTEGER; +CREATE OR REPLACE FUNCTION random_between_days() +RETURNS INTEGER 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; + RETURN floor(random() * 5 + 1)::INTEGER; +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 +CREATE TABLE IF NOT EXISTS Uhrzeit ( + ID SERIAL PRIMARY KEY, + anfangszeit TIME NOT NULL, + endzeit TIME NOT NULL +); + +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), + passwort VARCHAR(30), + arbeitszeit INTEGER DEFAULT 0, + admin BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE TABLE IF NOT EXISTS StundeImPlan ( + uhrzeit INTEGER REFERENCES Uhrzeit(ID), + tag INTEGER NOT NULL, + veranstaltung VARCHAR(3) REFERENCES Veranstaltung(name), + veranstalter INTEGER REFERENCES Veranstalter(ID), + PRIMARY KEY(uhrzeit, tag) +); + +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) +); + +-- Function to delete StundeImPlan when Veranstaltung is deleted +CREATE OR REPLACE FUNCTION delete_stundeimplan_for_veranstaltung() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM StundeImPlan WHERE veranstaltung = OLD.name; + RETURN OLD; +END; +$$ LANGUAGE plpgsql; + +-- 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; - END IF; - -- Update der Arbeitszeit des neuen Veranstalters - 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; - END IF; + IF new_veranstalter_id IS NOT NULL THEN + UPDATE StundeImPlan + SET veranstalter = new_veranstalter_id + WHERE veranstalter = OLD.ID; END IF; + 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 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'), @@ -187,4 +264,4 @@ INSERT INTO Veranstaltung (ort, raum, name, dauer) VALUES ('A', '107', 'DBS', 2), ('B', '208', 'WEB', 2), ('A', '109', 'BVA', 2), -('B', '210', 'MA1', 2); \ No newline at end of file +('B', '210', 'MA1', 2); diff --git a/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.cpp b/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.cpp index 8d07d32..ea369e4 100644 --- a/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.cpp +++ b/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.cpp @@ -5,32 +5,28 @@ EinsatzplanFrameController::EinsatzplanFrameController(QString id, bool admin) m_admin(admin) { const std::map config = load_config( ); - m_connectionString = fmt::format( + m_dbHandler = std::make_unique(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)); } diff --git a/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.hpp b/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.hpp index f209478..c5379ae 100644 --- a/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.hpp +++ b/src/Controller/EinsatzplanFrameController/EinsatzplanFrameController.hpp @@ -3,12 +3,12 @@ #include #include -#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 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); + }; diff --git a/src/Controller/LoginFrameController/LoginFrameController.cpp b/src/Controller/LoginFrameController/LoginFrameController.cpp index ae14765..53a9857 100644 --- a/src/Controller/LoginFrameController/LoginFrameController.cpp +++ b/src/Controller/LoginFrameController/LoginFrameController.cpp @@ -3,18 +3,16 @@ LoginFrameController::LoginFrameController( ) { auto config = load_config( ); - m_connectionString = fmt::format( + m_dbHandler = std::make_unique(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( )); } diff --git a/src/Controller/LoginFrameController/LoginFrameController.hpp b/src/Controller/LoginFrameController/LoginFrameController.hpp index f38501b..64f34e7 100644 --- a/src/Controller/LoginFrameController/LoginFrameController.hpp +++ b/src/Controller/LoginFrameController/LoginFrameController.hpp @@ -4,13 +4,16 @@ #include #include -#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 m_dbHandler; + public: LoginFrameController( ); + int tryLogin(QString id, QString password); + }; diff --git a/src/Controller/PlanGridController/PlanGridController.cpp b/src/Controller/PlanGridController/PlanGridController.cpp index e4e02c3..01957d5 100644 --- a/src/Controller/PlanGridController/PlanGridController.cpp +++ b/src/Controller/PlanGridController/PlanGridController.cpp @@ -17,20 +17,18 @@ PlanGridController::PlanGridController( ) { const std::map config = load_config( ); - m_connectionString = fmt::format( + m_dbHandler = std::make_unique(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, QWidget*>* PlanGridController::getVeranstaltungen( ) { - DBHandler* db = new DBHandler(m_connectionString); - - std::vector planData = db->getVeranstaltung( ); + std::vector planData = m_dbHandler->getPlan( ); for (int i = 0; i < 5; ++i) for (int j = 0; j < 5; ++j) { @@ -118,17 +116,35 @@ QMap, QWidget*>* PlanGridController::getVeranstaltungen( )")); container->setFixedSize(240, 100); - planMap->insert(qMakePair( - weekdays[std::stoi(infoVector.at(0)) - 1], - QString::fromStdString(infoVector.at(1).erase(5, 8))), - container); + 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); } diff --git a/src/Controller/PlanGridController/PlanGridController.hpp b/src/Controller/PlanGridController/PlanGridController.hpp index a0c5bbc..83fc34e 100644 --- a/src/Controller/PlanGridController/PlanGridController.hpp +++ b/src/Controller/PlanGridController/PlanGridController.hpp @@ -7,12 +7,13 @@ #include #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 m_dbHandler; + protected: QString weekdays[5]; QString times[5]; @@ -22,5 +23,5 @@ public: PlanGridController( ); QMap, 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); }; diff --git a/src/Core/DBHandler/DBHandler.cpp b/src/Core/DBHandler/DBHandler.cpp new file mode 100644 index 0000000..f652f93 --- /dev/null +++ b/src/Core/DBHandler/DBHandler.cpp @@ -0,0 +1,168 @@ +#include "DBHandler.hpp" + +DBHandler::DBHandler(const std::string& connStr) : + m_dbConnection(std::make_unique(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( ) : -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 DBHandler::getPlan( ) { + std::vector 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; +} diff --git a/src/Core/DBHandler/DBHandler.hpp b/src/Core/DBHandler/DBHandler.hpp new file mode 100644 index 0000000..30111c7 --- /dev/null +++ b/src/Core/DBHandler/DBHandler.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include +#include + +class DBHandler { +private: + std::unique_ptr 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 getPlan( ); +}; diff --git a/src/Core/DBHandler/DBHandler/DBHandler.cpp b/src/Core/DBHandler/DBHandler/DBHandler.cpp deleted file mode 100644 index d86e9cd..0000000 --- a/src/Core/DBHandler/DBHandler/DBHandler.cpp +++ /dev/null @@ -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 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(std::time(nullptr))); // Random number generator - std::uniform_int_distribution day_dist(1, 5); // Random days between 1 and 5 (Monday to Friday) - - for (auto row : veranstaltungen) { - int veranstaltungID = row["id"].as(); - int dauer = row["dauer"].as(); - int used = row["used"].as(); - - while (used < dauer) { - // Randomly select a day - int day = day_dist(rng); - - // Randomly select a Uhrzeit - std::uniform_int_distribution uhrzeit_dist(0, uhrzeiten.size() - 1); - int uhrzeitIndex = uhrzeit_dist(rng); - int uhrzeitID = uhrzeiten[uhrzeitIndex]; - - // Randomly select a Veranstalter - std::uniform_int_distribution veranstalter_dist(0, veranstalter.size() - 1); - int veranstalterIndex = veranstalter_dist(rng); - int veranstalterID = veranstalter[veranstalterIndex]["id"].as(); - - // 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(); - - 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 DBHandler::getVeranstaltung() { - std::vector 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(); - - 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(), - row["anfangszeit"].as(), - row["endzeit"].as(), - row["ort"].as(), - row["veranstaltungsname"].as(), - row["veranstaltername"].as(), - row["raum"].as(), - row["veranstalter_id"].as()); - 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( )); - } -} \ No newline at end of file diff --git a/src/Core/DBHandler/DBHandler/DBHandler.hpp b/src/Core/DBHandler/DBHandler/DBHandler.hpp deleted file mode 100644 index 4129c7e..0000000 --- a/src/Core/DBHandler/DBHandler/DBHandler.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -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 getVeranstaltung(); - void meldeKrank(std::string id, std::string tag, std::string stunde); -}; diff --git a/src/Core/DBHandler/DBLogin/DBLogin.cpp b/src/Core/DBHandler/DBLogin/DBLogin.cpp deleted file mode 100644 index 5790608..0000000 --- a/src/Core/DBHandler/DBLogin/DBLogin.cpp +++ /dev/null @@ -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( ) : -1; - } - catch (const std::exception& e) { - fmt::printf("ERROR: %s", e.what( )); - } - - return -1; -} - diff --git a/src/Core/DBHandler/DBLogin/DBLogin.hpp b/src/Core/DBHandler/DBLogin/DBLogin.hpp deleted file mode 100644 index cf1bd7c..0000000 --- a/src/Core/DBHandler/DBLogin/DBLogin.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#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); -}; diff --git a/src/View/EinsatzplanFrame/EinsatzplanFrame.cpp b/src/View/EinsatzplanFrame/EinsatzplanFrame.cpp index 2e2edef..fbc1a26 100644 --- a/src/View/EinsatzplanFrame/EinsatzplanFrame.cpp +++ b/src/View/EinsatzplanFrame/EinsatzplanFrame.cpp @@ -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( ); } } diff --git a/src/View/PlanGrid/PlanGrid.cpp b/src/View/PlanGrid/PlanGrid.cpp index 6019ea4..b3c85a1 100644 --- a/src/View/PlanGrid/PlanGrid.cpp +++ b/src/View/PlanGrid/PlanGrid.cpp @@ -115,7 +115,7 @@ void PlanGrid::populateGrid( ) { planGridController->Krankmelden( id, i + 1, - j + 1 + m_times[j].toStdString( ) ); } planMap = planGridController->getVeranstaltungen( );