Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

View File
Whitespace-only changes.
+129
View File
@@ -0,0 +1,129 @@
#ifndef APIROUTES_H
#define APIROUTES_H
#include "authMethods.h"
#include "dbConnection.h"
#include "objectMethods.h"
#include "replayMethods.h"
#include <QDebug>
#include <QString>
#include <QJsonDocument>
#include <QHttpServerResponse>
#include <qhttpserver.h>
#include <qjsonobject.h>
// Loggt die HTTP-Anfragen
void logRequest(const QHttpServerRequest &request) {
const auto method = request.method();
const QString url = request.url().toString();
qDebug() << "Request received:"
<< "Method:" << method
<< "URL:" << url;
}
// Fügt CORS-Routen hinzu
void addCorsRoutes(QHttpServer &server) {
const QStringList corsRoutes = {
"/objects", "/objects/replayinit", "/objects/replay",
"/replays", "/replays/delete", "/replays/user",
"/login", "/auth", "/replays/replay/avg",
"/bookmark", "/replays/replay/bookmark"
};
auto handleOptionsRequest = [](const QHttpServerRequest &request) {
logRequest(request);
QHttpServerResponse response("");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
};
for (const auto &route : corsRoutes) {
server.route(route, QHttpServerRequest::Method::Options, handleOptionsRequest);
}
}
// Fügt API-Routen hinzu
void addApiRoutes(QHttpServer &server) {
// Stellt sicher, dass die Datenbank verbunden und initialisiert ist
QSqlDatabase db = connectToDb();
initializeDatabase(db);
// Routenregistrierungen
server.route("/objects", QHttpServerRequest::Method::Post, [](const QHttpServerRequest &request) {
logRequest(request);
return ObjectMethods::postObjects(request);
});
server.route("/objects/replayinit", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return ObjectMethods::getReplayInitInformation(request);
});
server.route("/objects/replay", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return ObjectMethods::getGeoObjectsInterval(request);
});
server.route("/replays", QHttpServerRequest::Method::Post, [](const QHttpServerRequest &request) {
logRequest(request);
return postReplays(request);
});
server.route("/replays", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return getAllReplays(request);
});
server.route("/replays/delete", QHttpServerRequest::Method::Delete, [](const QHttpServerRequest &request) {
logRequest(request);
return deleteReplay(request);
});
server.route("/replays/replay", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return getSingleReplay(request);
});
server.route("/replays/replay/bookmark", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return ObjectMethods::getBookmarks(request);
});
server.route("/replays/user", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return getUserReplays(request);
});
server.route("/bookmark", QHttpServerRequest::Method::Post, [](const QHttpServerRequest &request) {
logRequest(request);
return ObjectMethods::postBookmark(request);
});
server.route("/login", QHttpServerRequest::Method::Post, [](const QHttpServerRequest &request) {
logRequest(request);
return loginUser(request);
});
server.route("/auth", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return authUser(request);
});
server.route("/replays/replay/avg", QHttpServerRequest::Method::Get, [](const QHttpServerRequest &request) {
logRequest(request);
return getAvg(request);
});
}
// Hauptfunktion zum Einrichten der API-Routen und CORS-Policy
void setupApiRoutes(QHttpServer &server) {
addApiRoutes(server);
addCorsRoutes(server);
}
#endif // APIROUTES_H
+161
View File
@@ -0,0 +1,161 @@
#ifndef AUTHMETHODS_H
#define AUTHMETHODS_H
#include <qhttpserverrequest.h>
#include <qhttpserverresponse.h>
#include <qcryptographichash.h>
#include <qjsondocument.h>
#include <QJsonObject>
#include <qsqldatabase.h>
#include <qsqlerror.h>
#include <qsqlquery.h>
#include <QUuid>
#include <QDateTime>
#include <QDebug>
QString hashPassword(const QString &password) {
return QString(QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha256).toHex());
}
QString generateToken() {
return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
QHttpServerResponse login(const QJsonObject &json) {
QString username = json["username"].toString();
QString password = json["password"].toString();
QSqlDatabase db = QSqlDatabase::database();
QSqlQuery query(db);
query.prepare(QString("SELECT id, password FROM public.users WHERE username = '%1'").arg(username));
if (!query.exec() || !query.next()) {
QHttpServerResponse response("Invalid username or password", QHttpServerResponse::StatusCode::Unauthorized);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QString hashedPassword = query.value("password").toString();
if (hashedPassword != hashPassword(password)) {
QHttpServerResponse response("Invalid username or password", QHttpServerResponse::StatusCode::Unauthorized);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QString token = generateToken();
int userId = query.value("id").toInt();
QDateTime expiryDate = QDateTime::currentDateTimeUtc().addSecs(24 * 3600);
query.prepare("INSERT INTO public.tokens (user_id, token, expiry_date) VALUES (:user_id, :token, :expiry_date)");
query.bindValue(":user_id", userId);
query.bindValue(":token", token);
query.bindValue(":expiry_date", expiryDate);
if (!query.exec()) {
qDebug() << "Error inserting token";
QHttpServerResponse response("Token generation failed", QHttpServerResponse::StatusCode::InternalServerError);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QJsonObject jsonResponse;
jsonResponse["token"] = token;
QByteArray responseBody = QJsonDocument(jsonResponse).toJson();
QHttpServerResponse response(responseBody, QHttpServerResponse::StatusCode::Ok);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QHttpServerResponse loginUser(const QHttpServerRequest &request) {
auto body = request.body();
QJsonDocument jsonRequest = QJsonDocument::fromJson(body);
qDebug() << jsonRequest;
if (!jsonRequest.isObject()) {
QHttpServerResponse response("Invalid Request!", QHttpServerResponse::StatusCode::BadRequest);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
return login(jsonRequest.object());
}
QHttpServerResponse checkAuth(const QString &token) {
QSqlDatabase db = QSqlDatabase::database();
QSqlQuery query(db);
query.prepare(QString("SELECT user_id, expiry_date FROM tokens WHERE token = :token"));
query.bindValue(":token", token);
if (!query.exec() || !query.next()) {
QHttpServerResponse response("Invalid token", QHttpServerResponse::StatusCode::Unauthorized);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QDateTime expiryDate = query.value("expiry_date").toDateTime();
if (QDateTime::currentDateTimeUtc() > expiryDate) {
QHttpServerResponse response("Token expired", QHttpServerResponse::StatusCode::Unauthorized);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QJsonObject jsonResponse;
jsonResponse["status"] = "Authenticated";
QHttpServerResponse response(QJsonDocument(jsonResponse).toJson(), QHttpServerResponse::StatusCode::Ok);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
QHttpServerResponse authUser(const QHttpServerRequest &request) {
QList<QPair<QByteArray, QByteArray>> headers = request.headers();
QString token;
for (const auto &header : headers) {
if (header.first.toLower() == "authorization") {
QString authHeader = QString::fromUtf8(header.second);
if (authHeader.startsWith("Bearer ")) {
token = authHeader.mid(7);
}
break;
}
}
if (token.isEmpty()) {
QHttpServerResponse response("No token provided", QHttpServerResponse::StatusCode::Unauthorized);
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
return response;
}
return checkAuth(token);
}
#endif // AUTHMETHODS_H
+202
View File
@@ -0,0 +1,202 @@
#ifndef DBCONNECTION_H
#define DBCONNECTION_H
#include <QDebug>
#include <QSqlDatabase>
#include <QFile>
#include <QSqlError>
#include <QSqlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDir>
#include <QCoreApplication>
QSqlDatabase connectToDb() {
QString path = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "../../config" + QDir::separator() + "db_config.json");
QFile inFile(path);
if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Kann die Datei nicht öffnen:" << inFile.errorString();
}
QByteArray data = inFile.readAll();
inFile.close();
QJsonParseError errorPtr;
QJsonDocument doc = QJsonDocument::fromJson(data, &errorPtr);
if (doc.isNull()) {
qDebug() << "Parse failed";
}
QJsonObject rootObj = doc.object();
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName(rootObj.value("host").toString());
db.setPort(rootObj.value("port").toInt());
db.setDatabaseName(rootObj.value("dbname").toString());
db.setUserName(rootObj.value("user").toString());
db.setPassword(rootObj.value("password").toString());
if (!db.open()) {
qDebug() << "Datenbankverbindung konnte nicht hergestellt werden";
return db;
}
qDebug() << "Datenbankverbindung wurde hergestellt";
return db;
}
QMap<QString, QString> getTableCreationQueries() {
QMap<QString, QString> tableQueries;
tableQueries["extensions"] = R"(
CREATE EXTENSION IF NOT EXISTS postgis;
)";
tableQueries["geojson-seq"] =R"(
CREATE SEQUENCE geojson_objects_id_seq;
)";
// Tabelle für Benutzer
tableQueries["users"] = R"(
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
)
)";
// Tabelle für Tokens
tableQueries["tokens"] = R"(
CREATE TABLE IF NOT EXISTS tokens (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
token TEXT NOT NULL,
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
expiry_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)
)";
// Tabelle für Replays
tableQueries["replays"] = R"(
CREATE TABLE IF NOT EXISTS replays (
uuid TEXT PRIMARY KEY,
name TEXT NOT NULL,
created_by INT NOT NULL,
time_created BIGINT,
FOREIGN KEY (created_by) REFERENCES groups(id) ON DELETE CASCADE
)
)";
// Tabelle für Gruppen
tableQueries["groups"] = R"(
CREATE TABLE IF NOT EXISTS groups (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE
)
)";
// Tabelle für die Zuordnung von Benutzern zu Gruppen
tableQueries["user_groups"] = R"(
CREATE TABLE IF NOT EXISTS user_groups (
user_id INT NOT NULL,
group_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, group_id)
)
)";
// Tabelle für die Zuordnung von Replays zu Gruppen
tableQueries["group_replays"] = R"(
CREATE TABLE IF NOT EXISTS group_replays (
group_id INT NOT NULL,
replay_uuid TEXT NOT NULL,
FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE,
FOREIGN KEY (replay_uuid) REFERENCES replays(uuid) ON DELETE CASCADE,
PRIMARY KEY (group_id, replay_uuid)
)
)";
// Root-User erstellen (falls nicht bereits vorhanden)
tableQueries["root_user"] = R"(
INSERT INTO users (username, password)
VALUES ('root', '4813494d137e1631bba301d5acab6e7bb7aa74ce1185d456565ef51d737677b2')
ON CONFLICT (username) DO NOTHING
)";
// Root-Gruppe erstellen (falls nicht bereits vorhanden)
tableQueries["root_group"] = R"(
INSERT INTO groups (name)
VALUES ('Root')
ON CONFLICT (name) DO NOTHING
)";
// Root-User der Root-Gruppe zuordnen
tableQueries["root_user_group"] = R"(
INSERT INTO user_groups (user_id, group_id)
SELECT u.id, g.id
FROM users u, groups g
WHERE u.username = 'root' AND g.name = 'Root'
ON CONFLICT (user_id, group_id) DO NOTHING
)";
return tableQueries;
}
bool initializeDatabase(QSqlDatabase db) {
if (!db.isOpen()) {
qDebug() << "Die Datenbank ist nicht geöffnet.";
return false;
}
QSqlQuery setupQuery(db);
if (!setupQuery.exec(R"(
CREATE TABLE IF NOT EXISTS executed_queries (
query_name TEXT PRIMARY KEY
);
)")) {
qDebug() << "Fehler beim Erstellen der Tabelle executed_queries:" << setupQuery.lastError().text();
return false;
}
QStringList executionOrder = {
"extensions", "geojson_seq", "users", "tokens", "replays",
"groups", "user_groups", "group_replays", "root_group",
"root_user", "root_user_group"
};
QMap<QString, QString> tableQueries = getTableCreationQueries();
for (const QString& key : executionOrder) {
QSqlQuery checkQuery(db);
checkQuery.prepare("SELECT 1 FROM executed_queries WHERE query_name = :queryName");
checkQuery.bindValue(":queryName", key);
if (!checkQuery.exec() || !checkQuery.next()) {
QSqlQuery execQuery(db);
if (!execQuery.exec(tableQueries[key])) {
qDebug() << "Fehler beim Ausführen der Query für" << key << ":" << execQuery.lastError().text();
return false;
}
QSqlQuery insertQuery(db);
insertQuery.prepare("INSERT INTO executed_queries (query_name) VALUES (:queryName)");
insertQuery.bindValue(":queryName", key);
if (!insertQuery.exec()) {
qDebug() << "Fehler beim Einfügen in executed_queries:" << insertQuery.lastError().text();
}
qDebug() << "Query für" << key << "erfolgreich ausgeführt.";
}
}
qDebug() << "Datenbank wurde erfolgreich initialisiert.";
return true;
}
#endif
+444
View File
@@ -0,0 +1,444 @@
#ifndef DBQUERY_H
#define DBQUERY_H
#include <qjsonobject.h>
#include <qdebug.h>
#include <qsqldatabase.h>
#include <qsqlquery.h>
#include "types.h"
#include <qjsondocument.h>
#include <QSqlError>
#include <QUuid>
#include <QDateTime>
bool insertGeoObjectToDb(const QJsonObject &obj) {
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return false;
}
QSqlQuery query(db);
QJsonObject propertiesObj = obj["properties"].toObject();
QJsonObject geoJsonObj = obj["geometry"].toObject();
QString replayId = propertiesObj["replay_id"].toString();
qint64 timestamp = propertiesObj["timestamp"].toInteger();
QString properties = QString::fromUtf8(QJsonDocument(propertiesObj).toJson());
QString geoJson = QString::fromUtf8(QJsonDocument(geoJsonObj).toJson());
query.prepare(QString("INSERT INTO %1.geojson_objects (properties, geom, timestamp) VALUES (:properties, ST_GeomFromGeoJson(:geoJson), :timestamp)").arg(replayId));
query.bindValue(":properties", properties);
query.bindValue(":geoJson", geoJson);
query.bindValue(":timestamp", timestamp);
if(!query.exec()) {
qDebug() << query.lastError().text();
return false;
}
return true;
}
QJsonArray getGeoObjectsIntervallFromDb(const QString &replayId, const QString &start_timestamp, const QString &end_timestamp) {
QJsonArray array;
QSqlDatabase db = QSqlDatabase::database();
if (!db.isOpen()) {
return array;
}
QSqlQuery query(db);
query.prepare(QString(
"SELECT properties, ST_AsGeoJSON(geom) as geojson "
"FROM %1.geojson_objects "
"WHERE timestamp BETWEEN :start_timestamp AND :end_timestamp "
"ORDER BY timestamp ASC"
).arg(replayId));
// Werte binden
query.bindValue(":start_timestamp", start_timestamp);
query.bindValue(":end_timestamp", end_timestamp);
// Query ausführen
if (!query.exec()) {
return array;
}
// Ergebnisse verarbeiten
while (query.next()) {
GeoJSONFeature feature;
QJsonObject geometry = QJsonDocument::fromJson(query.value("geojson").toByteArray()).object();
QJsonObject properties = QJsonDocument::fromJson(query.value("properties").toByteArray()).object();
feature.properties = properties;
feature.geometry = geometry;
array.append(feature.toJson());
}
return array;
}
QJsonObject getReplayInitInformationsFromDb(const QString &replayId) {
QJsonObject result;
QJsonObject timestamps;
QJsonArray geojsons;
QSqlDatabase db = QSqlDatabase::database();
if (!db.isOpen()) {
return result;
}
QSqlQuery query(db);
// Abrufen von min_timestamp und max_timestamp
if (query.exec(QString("SELECT MIN(timestamp) as min_timestamp, MAX(timestamp) as max_timestamp FROM %1.geojson_objects").arg(replayId))) {
if (query.next()) {
timestamps["min_timestamp"] = query.value("min_timestamp").toString();
timestamps["max_timestamp"] = query.value("max_timestamp").toString();
}
}
// Abrufen der GeoJSON-Objekte
if (query.exec(QString("SELECT properties, ST_AsGeoJSON(geom) as geojson FROM %1.geojson_objects WHERE timestamp BETWEEN (SELECT MIN(timestamp) FROM %1.geojson_objects) AND (SELECT MIN(timestamp) FROM %1.geojson_objects) + 300000;").arg(replayId))) {
while (query.next()) {
GeoJSONFeature feature;
QJsonObject geometry = QJsonDocument::fromJson(query.value("geojson").toByteArray()).object();
QJsonObject properties = QJsonDocument::fromJson(query.value("properties").toByteArray()).object();
feature.properties = properties;
feature.geometry = geometry;
geojsons.append(feature.toJson());
}
}
// Ergebnis zusammensetzen
result["timestamps"] = timestamps;
result["geojsons"] = geojsons;
return result;
}
bool insertReplayToDb(const QJsonObject &obj) {
QString uuid = "r" + QUuid::createUuid().toString(QUuid::WithoutBraces);
uuid = uuid.replace("-", "_");
QSqlDatabase db = QSqlDatabase::database();
QString replayName = obj["name"].toString();
int createdBy = obj["created_by"].toInt();
uint now = std::chrono::duration_cast<std::chrono::seconds> (std::chrono::system_clock::now().time_since_epoch()).count();
if(!db.isOpen()) {
return false;
}
QSqlQuery query(db);
if(!query.exec(QString("CREATE SCHEMA IF NOT EXISTS %1;").arg(uuid))) {
qDebug() << query.lastError().text();
return false;
}
if(!query.exec(QString("CREATE TABLE IF NOT EXISTS %1.geojson_objects(id integer NOT NULL DEFAULT nextval('geojson_objects_id_seq'::regclass),properties jsonb, geom geometry(Geometry,4326),timestamp BIGINT, CONSTRAINT geojson_objects_pkey PRIMARY KEY (id))").arg(uuid))) {
qDebug() << query.lastError().text();
return false;
}
if(!query.exec(QString("CREATE TABLE IF NOT EXISTS %1.marker(id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, timestamp BIGINT NOT NULL)").arg(uuid))) {
qDebug() << query.lastError().text();
return false;
}
query.prepare(QString("INSERT INTO public.replays VALUES (:uuid, :name, :created_by, :time_created);"));
query.bindValue(":name", replayName);
query.bindValue(":uuid", uuid);
query.bindValue(":created_by", createdBy);
query.bindValue(":time_created", now);
if(!query.exec()) {
qDebug() << query.lastError().text();
return false;
}
query.prepare(QString("INSERT INTO group_replays (group_id, replay_uuid) VALUES (:group_id, :replay_uuid)"));
query.bindValue(":group_id", createdBy);
query.bindValue(":replay_uuid", uuid);
if(!query.exec()) {
qDebug() << query.lastError().text();
return false;
}
return true;
}
QJsonArray getReplaysfromDb() {
QJsonArray array;
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return array;
}
QSqlQuery query(db);
if(!query.exec(QString("SELECT * FROM public.replays ORDER BY uuid ASC"))) {
return array;
}
while(query.next()) {
QJsonObject obj;
obj["name"] = query.value("name").toString();
obj["uuid"] = query.value("uuid").toString();
obj["created_by"] = query.value("created_by").toString();
obj["time_created"] = query.value("time_created").toString();
array.append(obj);
}
return array;
}
QJsonArray getReplayfromDb(const QString &replayId) {
QJsonArray array;
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return array;
}
QSqlQuery query(db);
if(!query.exec(QString("SELECT * FROM public.replays WHERE uuid = '%1' " ).arg(replayId))) {
qDebug() << query.lastError().text();
return array;
}
while(query.next()) {
QJsonObject obj;
obj["name"] = query.value("name").toString();
obj["uuid"] = query.value("uuid").toString();
obj["created_by"] = query.value("created_by").toString();
obj["time_created"] = query.value("time_created").toString();
array.append(obj);
}
return array;
}
QJsonArray getUserReplaysfromDb(const QString &token) {
QJsonArray array;
QString userId;
QString groupId;
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return array;
}
QSqlQuery query(db);
// 1. Hole den user_id für das gegebene Token
query.prepare("SELECT user_id FROM public.tokens WHERE token = :token");
query.bindValue(":token", token);
if (!query.exec()) {
qDebug() << "Query execution failed:" << query.lastError().text();
return array;
}
if (query.next()) {
userId = query.value("user_id").toString();
} else {
qDebug() << "No user found for token:" << token;
return array;
}
// 2. Finde die Gruppe, der der Benutzer angehört
query.prepare("SELECT group_id FROM public.user_groups WHERE user_id = :user_id");
query.bindValue(":user_id", userId);
if (!query.exec()) {
qDebug() << "Query execution failed to find group for user:" << query.lastError().text();
return array;
}
if (query.next()) {
groupId = query.value("group_id").toString();
} else {
qDebug() << "No group found for user:" << userId;
return array;
}
// 3. Hole alle replays, die der Gruppe zugeordnet sind
query.prepare("SELECT replay_uuid FROM public.group_replays WHERE group_id = :group_id");
query.bindValue(":group_id", groupId);
if (!query.exec()) {
qDebug() << "Query execution failed to get replays for group:" << query.lastError().text();
return array;
}
// 4. Hole die vollständigen Informationen für jedes Replay
while (query.next()) {
QString replayUuid = query.value("replay_uuid").toString();
// Finde die Replay-Daten anhand der UUID
QSqlQuery replayQuery(db);
replayQuery.prepare("SELECT * FROM public.replays WHERE uuid = :uuid");
replayQuery.bindValue(":uuid", replayUuid);
if (!replayQuery.exec()) {
qDebug() << "Query execution failed to get replay details:" << replayQuery.lastError().text();
continue; // Falls das Replay nicht gefunden wird, überspringe es
}
if (replayQuery.next()) {
QJsonObject obj;
obj["name"] = replayQuery.value("name").toString();
obj["uuid"] = replayQuery.value("uuid").toString();
obj["created_by"] = replayQuery.value("created_by").toInt();
obj["time_created"] = replayQuery.value("time_created").toString();
array.append(obj);
}
}
return array;
}
bool deleteReplayFromDb(const QString &replayId, QString &error) {
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
error = "Database connection went wrong";
return false;
}
QSqlQuery query(db);
if(!query.exec(QString("DELETE FROM public.replays WHERE uuid = '%1' ").arg(replayId))) {
qDebug() << query.lastError().text();
error = "Deleting replay from public.replay went wrong";
return false;
}
if(!query.exec(QString("DROP SCHEMA if exists %1 cascade;").arg(replayId))) {
qDebug() << query.lastError().text();
error = "Droping replay Schema went wrong";
return false;
}
error = "Successful replay delete";
return true;
}
QJsonArray getAvgLatLng(const QString &replayId, QString &error) {
QJsonArray array;
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return array;
}
QSqlQuery query(db);
if(!query.exec(QString("SELECT AVG(ST_X(geom::geometry)) AS avg_longitude, AVG(ST_Y(geom::geometry)) AS avg_latitude FROM %1.geojson_objects").arg(replayId))) {
qDebug() << query.lastError().text();
return array;
}
while(query.next()) {
QJsonObject obj;
obj["lat"] = query.value("avg_longitude").toDouble();
obj["lng"] = query.value("avg_latitude").toDouble();
array.append(obj);
}
return array;
}
bool insertBookmark(const QJsonObject &obj) {
qDebug() << obj["name"].toString();
qDebug() << obj["description"].toString();
qDebug() << obj["timestamp"].toInteger();
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return false;
}
QSqlQuery query(db);
QString replayId = obj["uuid"].toString();
qint64 timestamp = obj["timestamp"].toInteger();
QString name = obj["name"].toString();
QString description = obj["description"].toString();
query.prepare(QString("INSERT INTO %1.marker (name, description, timestamp) VALUES (:name, :description, :timestamp)").arg(replayId));
query.bindValue(":name", name);
query.bindValue(":description", description);
query.bindValue(":timestamp", timestamp);
if(!query.exec()) {
qDebug() << query.lastError().text();
return false;
}
return true;
}
QJsonArray getBookmarkFromDB(const QString &replayId) {
QJsonArray array;
QSqlDatabase db = QSqlDatabase::database();
if(!db.isOpen()) {
return array;
}
QSqlQuery query(db);
if(!query.exec(QString("SELECT * FROM %1.marker ORDER BY timestamp DESC").arg(replayId))) {
return array;
}
while(query.next()) {
QJsonObject obj;
obj["name"] = query.value("name").toString();
obj["description"] = query.value("description").toString();
obj["timestamp"] = query.value("timestamp").toLongLong();
array.append(obj);
}
return array;
}
#endif // DBQUERY_H
@@ -0,0 +1,38 @@
#ifndef ISVALIDGEOJSONOBJECT_H
#define ISVALIDGEOJSONOBJECT_H
#include <qjsonobject.h>
#include <qjsonarray.h>
bool isValidGeoJSONFeature(const QJsonObject &json, QString &error) {
if(!json.contains("type") || json["type"].toString() != "Feature") {
error = "Invalid GeoJson: 'type', must be 'Feature'";
return false;
}
if(!json.contains("geometry") || !json["geometry"].isObject()) {
error = "Invalid GeoJSON: 'geometry' field is missing or not an object";
return false;
}
QJsonObject geometry = json["geometry"].toObject();
if(!geometry.contains("coordinates") || !geometry["coordinates"].isArray()) {
error = "Invalid GeoJSON: 'geometry.coordinates' must be an an array or is missing";
return false;
}
QJsonArray coordinates = geometry["coordinates"].toArray();
if(json.contains("properties") && !json["properties"].isObject()) {
error = "InvalidGeoJSON: 'properties must be an object";
return false;
}
error = "GeoJSON is valid and successfully added to database ";
return true;
}
#endif // ISVALIDGEOJSONOBJECT_H
@@ -0,0 +1,17 @@
#ifndef ISVALIDREPLAYOBJECT_H
#define ISVALIDREPLAYOBJECT_H
#include <qjsonobject.h>
bool isValidReplayObject(const QJsonObject &json, QString &error) {
if(!json.contains("name") || !json.contains("created_by")) {
error = "Replay is missing something -> name || location || created_by";
return false;
}
error = "Replay is valid and successfully created";
return true;
}
#endif // ISVALIDREPLAYOBJECT_H
+127
View File
@@ -0,0 +1,127 @@
#ifndef OBJECTMETHODS_H
#define OBJECTMETHODS_H
#include <qhttpserverresponse.h>
#include <qsqldatabase.h>
#include "dbQuery.h"
#include "isValidGeoJsonObject.h"
#include "types.h"
#include <qhttpserverrequest.h>
#include <qjsondocument.h>
#include <qjsonobject.h>
#include <QDebug>
#include <qjsonarray.h>
namespace ObjectMethods {
// Set common response headers for CORS and content-type
void setCommonHeaders(QHttpServerResponse &response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Content-Type", "application/json");
}
// Handle errors and return a response with a specific status code
QHttpServerResponse createErrorResponse(const QString &errorMessage, QHttpServerResponse::StatusCode statusCode) {
QHttpServerResponse response(errorMessage, statusCode);
setCommonHeaders(response);
return response;
}
// Validate and insert GeoJSON feature into the database
QHttpServerResponse handleGeoJSONFeature(const QJsonObject &jsonObj) {
QString error;
GeoJSONFeature geoJsonObj = geoJsonObj.fromJson(jsonObj);
if (!isValidGeoJSONFeature(geoJsonObj.toJson(), error)) {
return createErrorResponse(error, QHttpServerResponse::StatusCode::BadRequest);
}
insertGeoObjectToDb(geoJsonObj.toJson());
return QHttpServerResponse(QString(), QHttpServerResponse::StatusCode::Ok);
}
QHttpServerResponse postObjects(const QHttpServerRequest &request) {
auto body = request.body();
QJsonDocument jsonRequest = QJsonDocument::fromJson(body);
if (!jsonRequest.isObject() && !jsonRequest.isArray()) {
return createErrorResponse("Invalid JSON", QHttpServerResponse::StatusCode::BadRequest);
}
// Handle single object or an array of objects
if (jsonRequest.isObject()) {
return handleGeoJSONFeature(jsonRequest.object());
} else if (jsonRequest.isArray()) {
for (const QJsonValue &obj : jsonRequest.array()) {
if (obj.isObject()) {
QHttpServerResponse response = handleGeoJSONFeature(obj.toObject());
if (response.statusCode() == QHttpServerResponse::StatusCode::BadRequest) {
return response; // Return error response immediately if one is found
}
}
}
}
return QHttpServerResponse(QString(), QHttpServerResponse::StatusCode::Ok);
}
QHttpServerResponse getGeoObjectsInterval(const QHttpServerRequest &request) {
if (!request.query().hasQueryItem("replayId") || !request.query().hasQueryItem("start") || !request.query().hasQueryItem("end")) {
return createErrorResponse("Query param is missing", QHttpServerResponse::StatusCode::BadRequest);
}
QString replayId = request.query().queryItemValue("replayId");
QString start_timestamp = request.query().queryItemValue("start");
QString end_timestamp = request.query().queryItemValue("end");
QJsonArray array = getGeoObjectsIntervallFromDb(replayId, start_timestamp, end_timestamp);
QHttpServerResponse response(array, QHttpServerResponse::StatusCode::Ok);
setCommonHeaders(response);
return response;
}
QHttpServerResponse getReplayInitInformation(const QHttpServerRequest &request) {
if (!request.query().hasQueryItem("replayId")) {
return createErrorResponse("replayId is missing", QHttpServerResponse::StatusCode::BadRequest);
}
QJsonObject obj = getReplayInitInformationsFromDb(request.query().queryItemValue("replayId"));
QHttpServerResponse response(obj, QHttpServerResponse::StatusCode::Ok);
setCommonHeaders(response);
return response;
}
QHttpServerResponse postBookmark(const QHttpServerRequest &request) {
auto body = request.body();
QJsonDocument jsonRequest = QJsonDocument::fromJson(body);
QString error;
if (jsonRequest["name"].isNull() || jsonRequest["timestamp"].isNull()) {
error = "values are missing";
return createErrorResponse(error, QHttpServerResponse::StatusCode::BadRequest);
}
insertBookmark(jsonRequest.object());
QHttpServerResponse response(error, QHttpServerResponse::StatusCode::Ok);
setCommonHeaders(response);
return response;
}
QHttpServerResponse getBookmarks(const QHttpServerRequest &request) {
if (!request.query().hasQueryItem("replayId")) {
return createErrorResponse("replayId is missing", QHttpServerResponse::StatusCode::BadRequest);
}
QJsonArray array = getBookmarkFromDB(request.query().queryItemValue("replayId"));
QHttpServerResponse response(array, QHttpServerResponse::StatusCode::Ok);
setCommonHeaders(response);
return response;
}
} // namespace ObjectMethods
#endif // OBJECTMETHODS_H
+129
View File
@@ -0,0 +1,129 @@
#ifndef REPLAYMETHODS_H
#define REPLAYMETHODS_H
#include <qhttpserverrequest.h>
#include <qhttpserverresponse.h>
#include <qjsonarray.h>
#include <qjsondocument.h>
#include "dbQuery.h"
#include "isValidReplayObject.h"
namespace {
const QByteArray ACCESS_CONTROL_ALLOW_ORIGIN = "*";
const QByteArray CONTENT_TYPE_JSON = "application/json";
QHttpServerResponse createBadRequestResponse(const QString& message) {
QHttpServerResponse response(message, QHttpServerResponder::StatusCode::BadRequest);
response.setHeader(QByteArray("Access-Control-Allow-Origin"), ACCESS_CONTROL_ALLOW_ORIGIN);
response.setHeader(QByteArray("Content-Type"), CONTENT_TYPE_JSON);
return response;
}
QHttpServerResponse createOkResponse(const QJsonArray& array) {
QHttpServerResponse response(array, QHttpServerResponder::StatusCode::Ok);
response.setHeader(QByteArray("Access-Control-Allow-Origin"), ACCESS_CONTROL_ALLOW_ORIGIN);
response.setHeader(QByteArray("Content-Type"), CONTENT_TYPE_JSON);
return response;
}
QHttpServerResponse createOkResponse(const QString& message) {
QHttpServerResponse response(message, QHttpServerResponder::StatusCode::Ok);
response.setHeader(QByteArray("Access-Control-Allow-Origin"), ACCESS_CONTROL_ALLOW_ORIGIN);
response.setHeader(QByteArray("Content-Type"), CONTENT_TYPE_JSON);
return response;
}
QHttpServerResponse createInternalErrorResponse(const QString& error) {
QHttpServerResponse response(error, QHttpServerResponder::StatusCode::InternalServerError);
response.setHeader(QByteArray("Access-Control-Allow-Origin"), ACCESS_CONTROL_ALLOW_ORIGIN);
response.setHeader(QByteArray("Access-Control-Allow-Methods"), QByteArray("GET, POST, DELETE, OPTIONS"));
response.setHeader(QByteArray("Access-Control-Allow-Headers"), QByteArray("Content-Type, Authorization"));
return response;
}
bool hasReplayId(const QHttpServerRequest &request) {
return request.query().hasQueryItem("replayId");
}
bool hasToken(const QHttpServerRequest &request) {
return request.query().hasQueryItem("token");
}
}
QHttpServerResponse getSingleReplay(const QHttpServerRequest &request) {
if (!hasReplayId(request)) {
return createBadRequestResponse("replayId is missing");
}
return createOkResponse(getReplayfromDb(request.query().queryItemValue("replayId")));
}
QHttpServerResponse getAllReplays(const QHttpServerRequest &request) {
return createOkResponse(getReplaysfromDb());
}
QHttpServerResponse getUserReplays(const QHttpServerRequest &request) {
if (!hasToken(request)) {
return createBadRequestResponse("token is missing");
}
return createOkResponse(getUserReplaysfromDb(request.query().queryItemValue("token")));
}
QHttpServerResponse postReplays(const QHttpServerRequest &request) {
auto body = request.body();
QJsonDocument jsonRequest = QJsonDocument::fromJson(body);
if (!jsonRequest.isObject() && !jsonRequest.isArray()) {
return createBadRequestResponse("Invalid JSON");
}
QString error;
if (jsonRequest.isObject()) {
QJsonObject jsonObj = jsonRequest.object();
if (!isValidReplayObject(jsonObj, error)) {
return createBadRequestResponse(error);
}
insertReplayToDb(jsonObj);
} else if (jsonRequest.isArray()) {
for (const QJsonValue &obj : jsonRequest.array()) {
if (obj.isObject()) {
QJsonObject jsonObj = obj.toObject();
if (!isValidReplayObject(jsonObj, error)) {
return createBadRequestResponse(error);
}
insertReplayToDb(jsonObj);
}
}
}
return createOkResponse("Replays added successfully");
}
QHttpServerResponse deleteReplay(const QHttpServerRequest &request) {
if (!hasReplayId(request)) {
return createBadRequestResponse("replayId is missing");
}
QString replayId = request.query().queryItemValue("replayId");
QString error;
if (!deleteReplayFromDb(replayId, error)) {
return createInternalErrorResponse(error);
}
return createOkResponse("Replay deleted successfully");
}
QHttpServerResponse getAvg(const QHttpServerRequest &request) {
if (!hasReplayId(request)) {
return createBadRequestResponse("replayId is missing");
}
QString error;
QJsonArray array = getAvgLatLng(request.query().queryItemValue("replayId"), error);
return createOkResponse(array);
}
#endif // REPLAYMETHODS_H
@@ -0,0 +1,32 @@
#ifndef SETUPSSLCERTIFICATE_H
#define SETUPSSLCERTIFICATE_H
#include <QCoreApplication>
#include <qdir.h>
#include <qsslconfiguration.h>
#include <qsslkey.h>
QSslConfiguration setupSslCertificate() {
QSslConfiguration sslConfiguration;
QString cert = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "../../config" + QDir::separator() + "server.crt");
QString key = QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "../../config" + QDir::separator() + "private.key");
QFile certFile(cert);
QFile keyFile(key);
if (!certFile.open(QIODevice::ReadOnly) || !keyFile.open(QIODevice::ReadOnly)) {
qCritical() << "Failed to open certificate or key file";
return sslConfiguration;
}
QSslCertificate certificate(&certFile, QSsl::Pem);
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "RME2024");
sslConfiguration.setLocalCertificate(certificate);
sslConfiguration.setPrivateKey(privateKey);
sslConfiguration.setProtocol(QSsl::TlsV1_2);
return sslConfiguration;
}
#endif // SETUPSSLCERTIFICATE_H
+35
View File
@@ -0,0 +1,35 @@
#ifndef TYPES_H
#define TYPES_H
#include <QJsonArray>
#include <QJsonObject>
struct GeoJSONFeature {
QJsonObject geometry;
QJsonObject properties;
QJsonObject toJson() const {
QJsonObject feature;
feature["type"] = "Feature";
feature["geometry"] = geometry;
feature["properties"] = properties;
return feature;
}
static GeoJSONFeature fromJson(const QJsonObject &json) {
GeoJSONFeature feature;
if(json["type"] == "Feature") {
feature.geometry = json["geometry"].toObject();
feature.properties = json["properties"].toObject();
}
return feature;
}
};
#endif // TYPES_H
+33
View File
@@ -0,0 +1,33 @@
#include "include/apiroutes.h"
// #include "include/setupSslCertificate.h"
#include <QCoreApplication>
#include <qhttpserver.h>
#include <QTcpServer>
#include <QtSql/QSqlDatabase>
#include <QSslConfiguration>
#include <QSslCertificate>
#include <QSslKey>
#include <QFile>
#include <QDir>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QHttpServer server;
qDebug() << hashPassword("root");
// server.sslSetup(setupSslCertificate()); -> Ssl Certificate einfügen
setupApiRoutes(server);
const auto port = server.listen(QHostAddress::Any, 8080);
if (!port) {
qDebug() << "Server failed to listen on port" << port;
return 0;
}
qDebug() << "Server started on Port " << port;
return a.exec();
}