This commit is contained in:
Crylia
2024-07-08 23:52:36 +02:00
parent 5bce421326
commit 701a8c3a98
15 changed files with 463 additions and 433 deletions

View File

@@ -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 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() CREATE OR REPLACE FUNCTION random_between_two()
RETURNS VARCHAR AS $$ RETURNS VARCHAR AS $$
BEGIN BEGIN
@@ -33,127 +11,226 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION random_between_days()
CREATE TABLE Uhrzeit ( RETURNS INTEGER AS $$
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;
BEGIN BEGIN
-- Wenn die Veranstalter_ID auf NULL gesetzt wird oder ein Veranstalter gelöscht wird RETURN floor(random() * 5 + 1)::INTEGER;
IF TG_OP = 'UPDATE' AND NEW.veranstalter_ID IS NULL THEN END;
-- Eintrag in die Krankmeldung $$ LANGUAGE plpgsql;
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;
-- Finde den Veranstalter mit den wenigsten Arbeitsstunden, CREATE TABLE IF NOT EXISTS Uhrzeit (
-- der am selben Tag keine Veranstaltung in einer anderen Uhrzeit an einem anderen Ort hat ID SERIAL PRIMARY KEY,
SELECT ID INTO neuer_veranstalter 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 FROM Veranstalter
WHERE ID NOT IN ( WHERE arbeitszeit < 18
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
)
)
)
ORDER BY arbeitszeit ASC ORDER BY arbeitszeit ASC
LIMIT 1; LIMIT 1;
-- Wenn ein neuer Veranstalter gefunden wurde IF new_veranstalter_id IS NOT NULL THEN
IF neuer_veranstalter IS NOT NULL THEN UPDATE StundeImPlan
IF TG_OP = 'UPDATE' THEN SET veranstalter = new_veranstalter_id
NEW.veranstalter_ID := neuer_veranstalter; WHERE veranstalter = OLD.ID;
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;
END IF; 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; RETURN NEW;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
CREATE TRIGGER trg_handle_veranstalter_update CREATE TRIGGER trg_handle_krank_insert
BEFORE UPDATE ON StundenImPlan AFTER INSERT ON Krank
FOR EACH ROW FOR EACH ROW
EXECUTE FUNCTION handle_veranstalter_update(); EXECUTE FUNCTION handle_krank_insert();
CREATE TRIGGER trg_handle_veranstalter_delete
BEFORE DELETE ON Veranstalter
FOR EACH ROW
EXECUTE FUNCTION handle_veranstalter_update();
INSERT INTO Uhrzeit (anfangszeit, endzeit) VALUES INSERT INTO Uhrzeit (anfangszeit, endzeit) VALUES
('08:00:00', '10:00:00'), ('08:00:00', '10:00:00'),
@@ -187,4 +264,4 @@ INSERT INTO Veranstaltung (ort, raum, name, dauer) VALUES
('A', '107', 'DBS', 2), ('A', '107', 'DBS', 2),
('B', '208', 'WEB', 2), ('B', '208', 'WEB', 2),
('A', '109', 'BVA', 2), ('A', '109', 'BVA', 2),
('B', '210', 'MA1', 2); ('B', '210', 'MA1', 2);

View File

@@ -5,32 +5,28 @@ EinsatzplanFrameController::EinsatzplanFrameController(QString id, bool admin)
m_admin(admin) { m_admin(admin) {
const std::map<std::string, std::string> config = load_config( ); 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={}", "host={} port={} dbname={} user={} password={}",
config.at("DB_HOST"), config.at("DB_HOST"),
config.at("DB_PORT"), config.at("DB_PORT"),
config.at("DB_NAME"), config.at("DB_NAME"),
config.at("DB_USER"), config.at("DB_USER"),
config.at("DB_PASSWORD") config.at("DB_PASSWORD")
); ));
} }
void EinsatzplanFrameController::deleteMember(QString id) { void EinsatzplanFrameController::deleteMember(QString id) {
DBHandler* db = new DBHandler(m_connectionString); m_dbHandler->deleteVeranstalter(id.toStdString( ));
db->deleteVeranstalter(id.toStdString( ));
} }
void EinsatzplanFrameController::deleteVeranstaltung(QString veranstaltungsname) { void EinsatzplanFrameController::deleteVeranstaltung(QString veranstaltungsname) {
DBHandler* db = new DBHandler(m_connectionString); m_dbHandler->deleteVeranstaltung(veranstaltungsname.toStdString( ));
db->deleteVeranstaltung(veranstaltungsname.toStdString( ));
} }
void EinsatzplanFrameController::createMember(QString name, QString email, QString passwort, bool admin) { void EinsatzplanFrameController::createMember(QString name, QString email, QString passwort, bool admin) {
DBHandler* db = new DBHandler(m_connectionString); m_dbHandler->createVeranstalter(name.toStdString( ), email.toStdString( ), passwort.toStdString( ), admin);
db->createVeranstalter(email.toStdString( ), name.toStdString( ), passwort.toStdString( ), admin ? "TRUE" : "FALSE");
} }
void EinsatzplanFrameController::createVeranstaltung(QString name, QString raum, QString campus, QString time) { void EinsatzplanFrameController::createVeranstaltung(QString name, QString raum, QString campus, QString time) {
DBHandler* db = new DBHandler(m_connectionString); m_dbHandler->createVeranstaltung(name.toStdString( ), campus.toStdString( ), raum.toStdString( ), std::to_string((char)time.toStdString( ).at(0) - 48));
db->createVeranstaltung(name.toStdString( ), std::to_string((char)time.toStdString( ).at(0) - 48), campus.toStdString( ), raum.toStdString( ));
} }

View File

@@ -3,12 +3,12 @@
#include <QString> #include <QString>
#include <fmt/format.h> #include <fmt/format.h>
#include "../../Core/DBHandler/DBHandler/DBHandler.hpp" #include "../../Core/DBHandler/DBHandler.hpp"
#include "../../Core/config/config.hpp" #include "../../Core/config/config.hpp"
class EinsatzplanFrameController { class EinsatzplanFrameController {
private: private:
std::string m_connectionString; std::unique_ptr<DBHandler> m_dbHandler;
protected: protected:
QString m_id; QString m_id;
@@ -20,4 +20,5 @@ public:
void deleteVeranstaltung(QString veranstaltungsname); void deleteVeranstaltung(QString veranstaltungsname);
void createMember(QString name, QString email, QString passwort, bool admin); void createMember(QString name, QString email, QString passwort, bool admin);
void createVeranstaltung(QString name, QString raum, QString campus, QString time); void createVeranstaltung(QString name, QString raum, QString campus, QString time);
}; };

View File

@@ -3,18 +3,16 @@
LoginFrameController::LoginFrameController( ) { LoginFrameController::LoginFrameController( ) {
auto config = load_config( ); auto config = load_config( );
m_connectionString = fmt::format( m_dbHandler = std::make_unique<DBHandler>(fmt::format(
"host={} port={} dbname={} user={} password={}", "host={} port={} dbname={} user={} password={}",
config.at("DB_HOST"), config.at("DB_HOST"),
config.at("DB_PORT"), config.at("DB_PORT"),
config.at("DB_NAME"), config.at("DB_NAME"),
config.at("DB_USER"), config.at("DB_USER"),
config.at("DB_PASSWORD") config.at("DB_PASSWORD")
); ));
} }
int LoginFrameController::tryLogin(QString id, QString password) { int LoginFrameController::tryLogin(QString id, QString password) {
DBLogin* loginHandler = new DBLogin(m_connectionString); return m_dbHandler->tryAuthenticate(id.toStdString( ), password.toStdString( ));
return loginHandler->checkValidLogin(id.toStdString( ), password.toStdString( ));
} }

View File

@@ -4,13 +4,16 @@
#include <QString> #include <QString>
#include <fmt/core.h> #include <fmt/core.h>
#include "../../Core/DBHandler/DBLogin/DBLogin.hpp" #include "../../Core/DBHandler/DBHandler.hpp"
#include "../../Core/config/config.hpp" #include "../../Core/config/config.hpp"
class LoginFrameController { class LoginFrameController {
private: private:
std::string m_connectionString; std::unique_ptr<DBHandler> m_dbHandler;
public: public:
LoginFrameController( ); LoginFrameController( );
int tryLogin(QString id, QString password); int tryLogin(QString id, QString password);
}; };

View File

@@ -17,20 +17,18 @@ PlanGridController::PlanGridController( ) {
const std::map<std::string, std::string> config = load_config( ); 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={}", "host={} port={} dbname={} user={} password={}",
config.at("DB_HOST"), config.at("DB_HOST"),
config.at("DB_PORT"), config.at("DB_PORT"),
config.at("DB_NAME"), config.at("DB_NAME"),
config.at("DB_USER"), config.at("DB_USER"),
config.at("DB_PASSWORD") config.at("DB_PASSWORD")
); ));
} }
QMap<QPair<QString, QString>, QWidget*>* PlanGridController::getVeranstaltungen( ) { QMap<QPair<QString, QString>, QWidget*>* PlanGridController::getVeranstaltungen( ) {
DBHandler* db = new DBHandler(m_connectionString); std::vector<std::string> planData = m_dbHandler->getPlan( );
std::vector<std::string> planData = db->getVeranstaltung( );
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j) { for (int j = 0; j < 5; ++j) {
@@ -118,17 +116,35 @@ QMap<QPair<QString, QString>, QWidget*>* PlanGridController::getVeranstaltungen(
)")); )"));
container->setFixedSize(240, 100); container->setFixedSize(240, 100);
planMap->insert(qMakePair( if (infoVector.at(8) == "4") {
weekdays[std::stoi(infoVector.at(0)) - 1], planMap->insert(qMakePair(
QString::fromStdString(infoVector.at(1).erase(5, 8))), weekdays[std::stoi(infoVector.at(0)) - 1],
container); 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; return planMap;
} }
void PlanGridController::Krankmelden(const int id, int tag, int stunde) { void PlanGridController::Krankmelden(const int id, const int tag, const std::string& uhrzeit) {
DBHandler db(m_connectionString); m_dbHandler->krankmelden(std::to_string(id), uhrzeit, tag);
db.meldeKrank(std::to_string(id), std::to_string(tag), std::to_string(stunde));
} }

View File

@@ -7,12 +7,13 @@
#include <QPushButton> #include <QPushButton>
#include "../../Core/config/config.hpp" #include "../../Core/config/config.hpp"
#include "../../Core/DBHandler/DBHandler/DBHandler.hpp" #include "../../Core/DBHandler/DBHandler.hpp"
class PlanGridController : public QObject { class PlanGridController : public QObject {
Q_OBJECT Q_OBJECT
private: private:
std::string m_connectionString; std::unique_ptr<DBHandler> m_dbHandler;
protected: protected:
QString weekdays[5]; QString weekdays[5];
QString times[5]; QString times[5];
@@ -22,5 +23,5 @@ public:
PlanGridController( ); PlanGridController( );
QMap<QPair<QString, QString>, QWidget*>* getVeranstaltungen( ); 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);
}; };

View 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;
}

View 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( );
};

View File

@@ -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( ));
}
}

View File

@@ -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);
};

View File

@@ -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;
}

View File

@@ -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);
};

View File

@@ -210,6 +210,8 @@ void EinsatzplanFrame::createVeranstaltung( ) {
QString campus = dialog.getCampus( ); QString campus = dialog.getCampus( );
QString time = dialog.getTime( ); QString time = dialog.getTime( );
m_controller->createVeranstaltung(name, raum, campus, time); m_controller->createVeranstaltung(name, raum, campus, time);
m_planGrid->setPlanMap(m_planGrid->planGridController->getVeranstaltungen( ));
m_planGrid->populateGrid( );
} }
} }

View File

@@ -115,7 +115,7 @@ void PlanGrid::populateGrid( ) {
planGridController->Krankmelden( planGridController->Krankmelden(
id, id,
i + 1, i + 1,
j + 1 m_times[j].toStdString( )
); );
} }
planMap = planGridController->getVeranstaltungen( ); planMap = planGridController->getVeranstaltungen( );