Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+46
@@ -0,0 +1,46 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(restapi LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core HttpServer Sql Network)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core HttpServer Sql Network)
|
||||
|
||||
add_executable(restapi
|
||||
src/main.cpp
|
||||
|
||||
src/include/objectMethods.h
|
||||
src/include/apiroutes.h
|
||||
src/include/types.h
|
||||
|
||||
src/include/isValidGeoJsonObject.h
|
||||
src/include/dbConnection.h
|
||||
|
||||
config/db_config.json
|
||||
config/private.key
|
||||
config/server.crt
|
||||
|
||||
src/include/dbQuery.h
|
||||
|
||||
src/include/isValidReplayObject.h
|
||||
|
||||
|
||||
src/include/replayMethods.h
|
||||
|
||||
src/include/authMethods.h
|
||||
src/include/setupSslCertificate.h
|
||||
|
||||
)
|
||||
target_link_libraries(restapi Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::HttpServer Qt${QT_VERSION_MAJOR}::Sql Qt${QT_VERSION_MAJOR}::Network)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS restapi
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"host": "localhost",
|
||||
"port" : 5432,
|
||||
"dbname" : "rme_playback",
|
||||
"user" : "postgres",
|
||||
"password" : "postgres"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIC9zCCAd8CAQAwgZkxCzAJBgNVBAYTAkRFMRYwFAYDVQQIDA1OaWVkZXJzYWNo
|
||||
c2VuMQ8wDQYDVQQHDAZCcmVtZW4xDDAKBgNVBAoMA1JNRTEMMAoGA1UECwwDUk1F
|
||||
MRIwEAYDVQQDDAlsb2NhbGhvc3QxMTAvBgkqhkiG9w0BCQEWIk5pbm8tcGFzY2Fs
|
||||
LnBpbnplckByaGVpbm1ldGFsbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
|
||||
ggEKAoIBAQDkOG9Ci/XVwsXWAiCJYzdGQpvGqZluht1SdegTTTaJB0ok+utYOB1+
|
||||
3AiFjUQQm+lvoOcKW/NqFjDkK6CDkpTJLu6pyLAn+dCkPzQqLKXFMvono/JtEB9G
|
||||
+MT3HlQb2Ds5UuYnQ3KfMTUOKNrlM+8scj49EqikC7VlRE6YsE4/qtOs1bxhTyig
|
||||
C90gCNUmYsMNCeTG7zcsyVApI6mnnO1X7JdcyhsmyPnZ9YMzxRJNlDArI5FYJojM
|
||||
eFMYXuucS634vPhcAYQRFQtrG8e98/HjAWI9k3gzF4zeULctuT1bEjLA+sc4bZy9
|
||||
MQqGxHIvOLkxyhVYD1gyM0F2Tkbg85ZhAgMBAAGgGDAWBgkqhkiG9w0BCQcxCQwH
|
||||
Uk1FMjAyNDANBgkqhkiG9w0BAQsFAAOCAQEAXMyiKr5Mdt1Y1SriIQvDrEczU+xF
|
||||
7PpU8RqE5/Ir/ZMJ8o16RhEFhGAygvP4208pdXWy2/zC6LofdFvi/mx1kEqZLk9E
|
||||
vjfECB7NGDHHI/dC1dydMLu6SwBGqufj5zEGR+kBA06KwrzTwflxLN87DtKLYPzj
|
||||
STs4/LK6RgsfdtlkAhsfOk2XkYRdWi5DLim8KjnC51HD3rheWCgRgiIW1+rBGjRC
|
||||
0Jz/v1nPy9P+v0tPBN5uuLrmTCDNsTQTPh5L3c3DcA2uI9H1Uyu2mZcN+CYkDLAw
|
||||
X9yFlYnF3VNQCaemPnzE4vReQ/RU9mn6TZdgblFRsstgWQvvO9poAvde5g==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkOG9Ci/XVwsXW
|
||||
AiCJYzdGQpvGqZluht1SdegTTTaJB0ok+utYOB1+3AiFjUQQm+lvoOcKW/NqFjDk
|
||||
K6CDkpTJLu6pyLAn+dCkPzQqLKXFMvono/JtEB9G+MT3HlQb2Ds5UuYnQ3KfMTUO
|
||||
KNrlM+8scj49EqikC7VlRE6YsE4/qtOs1bxhTyigC90gCNUmYsMNCeTG7zcsyVAp
|
||||
I6mnnO1X7JdcyhsmyPnZ9YMzxRJNlDArI5FYJojMeFMYXuucS634vPhcAYQRFQtr
|
||||
G8e98/HjAWI9k3gzF4zeULctuT1bEjLA+sc4bZy9MQqGxHIvOLkxyhVYD1gyM0F2
|
||||
Tkbg85ZhAgMBAAECggEADuTT9f7WU1X7vUS0ROMRt2cfbW6iEcGBbiE9vQy782Nj
|
||||
ZlhtxXscCaxobfbTK1ZRfLR+f4GSuCislid2uT92sE58yt3LCUDXafCqAdqaEu2J
|
||||
v86GQrHbqLERgaMcEBkjfFE5rfRL5bG7aaom5vBlunvWLfwqv1H4S5ySmIphAOyQ
|
||||
iNURCtIEElGZbuG8rvByxF7ZAplWStXuNUPcRN0Vs3Lm3CuaTO5UP9hYZ40+rikl
|
||||
oOOQUB/6r8i+LRKUcU7MfEDkF9g3iklWDt8NuuBuL9Pc00ARamQa7pTRFWe+q+0V
|
||||
qjsDmkU25SGyGwAIRknoxnDzc96cajltnwW7J0K6JQKBgQD0bVhiILRICaADCvL5
|
||||
OXMp1+JlYN++Mul0AXIY8vP77rSEFTsNYaNGhHDs7GXjasD8Uxo0dplux6Gs59uS
|
||||
Ob19n8dfzof0P+KTvtZLaIyRCFxbs4U5SEKWTtE37agoiCgwFMSOxKy68N4JXHqL
|
||||
nFTFHnoLRo4D4k2IehVeIeOfuwKBgQDvBqa4Spjolo+KU5+r4Z2OBozeipxwDB3t
|
||||
Ul28eevEbY1o/NT/A4nTw9riD7pExMnCDqw3Xt7BU/DtjDnBqMA9c98hKFxy/yxX
|
||||
dWCvCPWXETq+aD5y9rY8+AUdEyA4Vm4ijnupj6gm6PWd0vOxZz6/67R7gSGLVCgN
|
||||
HU0R3gO6kwKBgQDRw6FNHUn6ZKA43EWm0sHdkBMP87IwdVraHn9/n8j5VWL/04SJ
|
||||
OFi6JOEQwtOx9qTGJr9fdMS6SIKcc6KA/CJ91AhzVThhyg21w9n+fyvbL7SrUgYs
|
||||
IbJbciqk98UPe8IZeUkySOD/0cSLfh0BAVnSjRQp5xPri2QEktkRnr3NDwKBgFoX
|
||||
ybNg+q2AQm5DAsYIbhhgQ6yF1l0tVAJlr0shMUqCeHCAC9BrBwI4qkHW58CP4/Qv
|
||||
D553NcLs3rzKw+JIttzy1cFrsxztLUtxxJV07QyZw+iM5izy7NGiMls5IEXb3ftM
|
||||
dTP+H8U6vYlVP+E4JyCzuP1sOLaJa+c1ih0X75PdAoGBANQQg7XkwflQvduccbpO
|
||||
KfsDOIL0NWsHaqGIhm25ufYqCjdZ7LM4LH+T6BF+6vYteAM6zQOJ4d0j9yYVLHbd
|
||||
tb1ct2RPnrebHsN0HLx5iibJDafOe3+Xb9d7J8MVKi5dXnw8bPZdit5znbqSdc5W
|
||||
FWqhdokOEYyvVxOLEhpnNfY0
|
||||
-----END PRIVATE KEY-----
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDuzCCAqMCFACAK0wopGGeRcujdgfkW0zX6sF6MA0GCSqGSIb3DQEBCwUAMIGZ
|
||||
MQswCQYDVQQGEwJERTEWMBQGA1UECAwNTmllZGVyc2FjaHNlbjEPMA0GA1UEBwwG
|
||||
QnJlbWVuMQwwCgYDVQQKDANSTUUxDDAKBgNVBAsMA1JNRTESMBAGA1UEAwwJbG9j
|
||||
YWxob3N0MTEwLwYJKoZIhvcNAQkBFiJOaW5vLXBhc2NhbC5waW56ZXJAcmhlaW5t
|
||||
ZXRhbGwuY29tMB4XDTI0MTEyMjA3MTg0N1oXDTI1MTEyMjA3MTg0N1owgZkxCzAJ
|
||||
BgNVBAYTAkRFMRYwFAYDVQQIDA1OaWVkZXJzYWNoc2VuMQ8wDQYDVQQHDAZCcmVt
|
||||
ZW4xDDAKBgNVBAoMA1JNRTEMMAoGA1UECwwDUk1FMRIwEAYDVQQDDAlsb2NhbGhv
|
||||
c3QxMTAvBgkqhkiG9w0BCQEWIk5pbm8tcGFzY2FsLnBpbnplckByaGVpbm1ldGFs
|
||||
bC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkOG9Ci/XVwsXW
|
||||
AiCJYzdGQpvGqZluht1SdegTTTaJB0ok+utYOB1+3AiFjUQQm+lvoOcKW/NqFjDk
|
||||
K6CDkpTJLu6pyLAn+dCkPzQqLKXFMvono/JtEB9G+MT3HlQb2Ds5UuYnQ3KfMTUO
|
||||
KNrlM+8scj49EqikC7VlRE6YsE4/qtOs1bxhTyigC90gCNUmYsMNCeTG7zcsyVAp
|
||||
I6mnnO1X7JdcyhsmyPnZ9YMzxRJNlDArI5FYJojMeFMYXuucS634vPhcAYQRFQtr
|
||||
G8e98/HjAWI9k3gzF4zeULctuT1bEjLA+sc4bZy9MQqGxHIvOLkxyhVYD1gyM0F2
|
||||
Tkbg85ZhAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJVr7rwP6gnl47S90JnjIfUS
|
||||
swIN3FAgr2z348FZKaU7fqlZz2uVcU6yrDseqEkf3lDdRAsYs9iV0psXWObD353V
|
||||
Afj0tSH85JikRLbGFnIOlDJ4Dhf577pSnS25wamQZWJ1Z9rME1SmwbdGBYFWwCu5
|
||||
bl7ffi64j+iEIt0/B634WeugkPW8GpN2v9M0JJTNWxrF0CTf4ulXRdYJJ7M8xEt8
|
||||
4ajNV5MmxRJfiMgtsrTJQM+ayghT6URkkm17bzUcTjxIoQZAE2zSiEqdlEXAK+v/
|
||||
GEjICExe642J/6OPcS3BZKDOn5DqQZl8TMGum7SZpg3ycqqqcvD8oKG7cp0LWCo=
|
||||
-----END CERTIFICATE-----
|
||||
Whitespace-only changes.
+129
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Executable
+33
@@ -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();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user