|
|
|
@@ -1,5 +1,7 @@
|
|
|
|
|
#include <pqxx/pqxx>
|
|
|
|
|
#include "database.hpp"
|
|
|
|
|
#include <format>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
User PostgresDB::GetUser(const int uid) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
@@ -84,4 +86,220 @@ User PostgresDB::GetUser(const std::string& username, const std::string& passwor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PostgresDB::GetUser(row["uid"].as<int>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
User PostgresDB::CreateUser(const std::string& username, const std::string& password, bool is_system) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R = W.exec("SELECT * FROM users WHERE username = $1", pqxx::params{username});
|
|
|
|
|
|
|
|
|
|
if (R.size() != 0) {
|
|
|
|
|
W.commit();
|
|
|
|
|
throw std::runtime_error("User already exists");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"INSERT INTO users (username, password_hash, is_system) VALUES ($1, $2, $3)",
|
|
|
|
|
pqxx::params{username, hashing::HashPassword(password, hashing::GenerateSetting()), is_system}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
int uid = W.query_value<int>("SELECT uid FROM users WHERE username = $1", pqxx::params{username});
|
|
|
|
|
|
|
|
|
|
if (is_system) {
|
|
|
|
|
W.exec("INSERT INTO systems (uid) VALUES ($1)", pqxx::params{uid});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
W.commit();
|
|
|
|
|
return GetUser(uid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::DeleteUser(const User& user) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec("DELETE FROM users WHERE uid = $1", pqxx::params{user.uid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::UpdateUserPassowrd(User& user, const std::string& password) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"UPDATE users SET password_hash = $1 WHERE uid = $2",
|
|
|
|
|
pqxx::params{hashing::HashPassword(password, hashing::GenerateSetting()), user.uid}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
W.commit();
|
|
|
|
|
GetUser(user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::CreateMember(User& user, const std::string& name, const std::string& pronouns, const std::string& description) {
|
|
|
|
|
if (!user.is_system) throw std::runtime_error("User does not have a system");
|
|
|
|
|
|
|
|
|
|
for (const auto& member : user.system->members) {
|
|
|
|
|
if (member.name == name) throw std::runtime_error("Member already exists");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"INSERT INTO members (sid, name, pronouns, description) VALUES ($1, $2, $3, $4)",
|
|
|
|
|
pqxx::params{user.system->sid, name, pronouns, description}
|
|
|
|
|
);
|
|
|
|
|
W.commit();
|
|
|
|
|
GetUser(user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::UpdateMemberDescription(Member& member, const std::string& description) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec("UPDATE members SET description = $1 WHERE mid = $2", pqxx::params{description, member.mid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::UpdateMemberPronouns(Member& member, const std::string& pronouns) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec("UPDATE members SET pronouns = $1 WHERE mid = $2", pqxx::params{pronouns, member.mid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::UpdateMemberName(Member& member, const std::string& name) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R = W.exec("SELECT * FROM members WHERE sid = $1", pqxx::params{member.sid});
|
|
|
|
|
|
|
|
|
|
for (auto row : R) {
|
|
|
|
|
if (row["name"].as<std::string>() == name) throw std::runtime_error("Member already exists");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
W.exec("UPDATE members SET name = $1 WHERE mid = $2", pqxx::params{name, member.mid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::DeleteMember(const Member& member) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec("DELETE FROM members WHERE mid = $1", pqxx::params{member.mid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::CreateAccessToken(User& user) {
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R = W.exec("SELECT * FROM access_tokens WHERE uid = $1", pqxx::params{user.uid});
|
|
|
|
|
|
|
|
|
|
if (R.size() != 0) throw std::runtime_error("User already has an access token");
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"INSERT INTO access_tokens (uid, token) VALUES ($1, $2)",
|
|
|
|
|
pqxx::params{user.uid, hashing::generate_token()}
|
|
|
|
|
);
|
|
|
|
|
W.commit();
|
|
|
|
|
GetUser(user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::DeleteAccessToken(const User& user) {
|
|
|
|
|
if (user.accesstoken == nullptr) throw std::runtime_error("User has no access token");
|
|
|
|
|
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
W.exec("DELETE FROM access_tokens WHERE uid = $1", pqxx::params{user.uid});
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::StartFront(const User& user, const Member& member, const std::string& note, Timestamp start_time) {
|
|
|
|
|
std::string time_string = std::format("{:%Y-%m-%d %H:%M:%S+00:00}", start_time);
|
|
|
|
|
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R = W.exec("SELECT * FROM front_history WHERE mid = $1 AND end_time IS NULL", pqxx::params{member.mid});
|
|
|
|
|
|
|
|
|
|
if (R.size() != 0) throw std::runtime_error("Front already started");
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"INSERT INTO front_history (uid, mid, start_time, note) VALUES ($1, $2, $3, $4)",
|
|
|
|
|
pqxx::params{user.uid, member.mid, time_string, note}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PostgresDB::EndFront(const User& user, const Member& member, Timestamp end_time) {
|
|
|
|
|
std::string time_string = std::format("{:%Y-%m-%d %H:%M:%S+00:00}", end_time);
|
|
|
|
|
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R = W.exec("SELECT * FROM front_history WHERE mid = $1 AND end_time IS NULL", pqxx::params{member.mid});
|
|
|
|
|
|
|
|
|
|
if (R.size() == 0) throw std::runtime_error("Front not started");
|
|
|
|
|
|
|
|
|
|
int64_t fid = R[0]["fid"].as<int64_t>();
|
|
|
|
|
|
|
|
|
|
W.exec(
|
|
|
|
|
"UPDATE front_history SET end_time = $1 WHERE fid = $2",
|
|
|
|
|
pqxx::params{time_string, fid}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
W.commit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Front> PostgresDB::GetFronts(const User& user, Timestamp start_time, std::optional<Timestamp> end_time) {
|
|
|
|
|
std::string start_time_string = std::format("{:%Y-%m-%d %H:%M:%S+00:00}", start_time);
|
|
|
|
|
std::vector<Front> front_history;
|
|
|
|
|
|
|
|
|
|
pqxx::connection C(conn_str);
|
|
|
|
|
pqxx::work W(C);
|
|
|
|
|
|
|
|
|
|
pqxx::result R;
|
|
|
|
|
|
|
|
|
|
if (end_time.has_value()) {
|
|
|
|
|
std::string end_time_string = std::format("{:%Y-%m-%d %H:%M:%S+00}", end_time.value());
|
|
|
|
|
R = W.exec(
|
|
|
|
|
"SELECT * FROM front_history WHERE uid = $1 AND start_time >= $2 AND end_time <= $3 ORDER BY start_time DESC",
|
|
|
|
|
pqxx::params{user.uid, start_time_string, end_time_string}
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
R = W.exec(
|
|
|
|
|
"SELECT * FROM front_history WHERE uid = $1 AND start_time >= $2 ORDER BY start_time DESC",
|
|
|
|
|
pqxx::params{user.uid, start_time_string}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto row : R) {
|
|
|
|
|
Front front;
|
|
|
|
|
front.fid = row["fid"].as<int64_t>();
|
|
|
|
|
front.uid = row["uid"].as<int>();
|
|
|
|
|
|
|
|
|
|
pqxx::result R2 = W.exec("SELECT * FROM members WHERE mid = $1", pqxx::params{row["mid"].as<int>()});
|
|
|
|
|
front.member = new Member;
|
|
|
|
|
front.member->mid = R2[0]["mid"].as<int>();
|
|
|
|
|
front.member->sid = R2[0]["sid"].as<int>();
|
|
|
|
|
front.member->name = R2[0]["name"].as<std::string>();
|
|
|
|
|
front.member->pronouns = R2[0]["pronouns"].as<std::string>();
|
|
|
|
|
front.member->description = R2[0]["description"].as<std::string>();
|
|
|
|
|
|
|
|
|
|
front.is_active = true;
|
|
|
|
|
front.start_time = ParseTimestamp(row["start_time"].as<std::string>());
|
|
|
|
|
if (!row["end_time"].is_null()) {
|
|
|
|
|
front.is_active = false;
|
|
|
|
|
front.end_time = ParseTimestamp(row["end_time"].as<std::string>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
front.note = row["note"].as<std::string>();
|
|
|
|
|
front_history.push_back(front);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return front_history;
|
|
|
|
|
}
|