2026-01-25 10:47:19 +01:00
|
|
|
#include "servercommunicator.h"
|
|
|
|
|
#include "apiroutes.h"
|
|
|
|
|
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
#include <QJsonDocument>
|
|
|
|
|
#include <QJsonObject>
|
|
|
|
|
#include <QRestReply>
|
|
|
|
|
|
2026-05-08 14:44:40 +02:00
|
|
|
#include "../formats/jsonparser.h"
|
|
|
|
|
|
2026-01-25 10:47:19 +01:00
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
|
|
|
|
|
|
ServerCommunicator::ServerCommunicator(QObject* parent)
|
|
|
|
|
: QObject{parent} {
|
|
|
|
|
m_netManager.setAutoDeleteReplies(true);
|
|
|
|
|
m_restManager = std::make_shared<QRestAccessManager>(&m_netManager);
|
|
|
|
|
m_serviceApi = std::make_shared<QNetworkRequestFactory>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ServerCommunicator::sslSupported() {
|
|
|
|
|
#if QT_CONFIG(ssl)
|
|
|
|
|
return QSslSocket::supportsSsl();
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QUrl ServerCommunicator::url() const { return m_serviceApi->baseUrl(); }
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::setUrl(const QUrl& url) {
|
|
|
|
|
if (m_serviceApi->baseUrl() == url) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
m_serviceApi->setBaseUrl(url);
|
|
|
|
|
QHttpHeaders authenticationHeaders;
|
2026-01-29 08:54:47 +01:00
|
|
|
authenticationHeaders.append(QHttpHeaders::WellKnownHeader::ContentType, "application/json");
|
2026-01-25 10:47:19 +01:00
|
|
|
m_serviceApi->setCommonHeaders(authenticationHeaders);
|
|
|
|
|
emit urlChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 08:02:17 +02:00
|
|
|
void ServerCommunicator::setServerConfiguration(const QString url,
|
|
|
|
|
const QString email,
|
|
|
|
|
const QString password,
|
|
|
|
|
const QString authToken) {
|
|
|
|
|
setUrl(url);
|
|
|
|
|
|
|
|
|
|
m_email = email;
|
|
|
|
|
m_password = password;
|
|
|
|
|
m_authToken = authToken;
|
|
|
|
|
|
2026-05-08 14:44:40 +02:00
|
|
|
if (authToken.isEmpty()) {
|
|
|
|
|
if (validLoginCredentials()) {
|
|
|
|
|
const QByteArray userCredentials =
|
|
|
|
|
JsonParser::userCredentialsToJsonDocument(m_email, m_password);
|
|
|
|
|
sendPostRequest(ROUTE_LOG_IN, userCredentials);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
/// authToken not empty:
|
2026-04-27 08:02:17 +02:00
|
|
|
m_serviceApi->setBearerToken(authToken.toLatin1());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 09:44:32 +02:00
|
|
|
void ServerCommunicator::fetchItems() { sendGetRequest(ROUTE_ITEMS); }
|
2026-01-29 08:54:47 +01:00
|
|
|
|
2026-05-04 08:16:48 +02:00
|
|
|
void ServerCommunicator::sendItem(const QByteArray& jsonData) {
|
|
|
|
|
sendPostRequest(ROUTE_ITEMS, jsonData);
|
2026-01-29 08:54:47 +01:00
|
|
|
}
|
2026-02-02 16:15:20 +01:00
|
|
|
|
|
|
|
|
void ServerCommunicator::deleteItem(const QString& id) {
|
2026-05-04 08:16:48 +02:00
|
|
|
const QString path = QString("%1/%2").arg(ROUTE_ITEMS, id);
|
|
|
|
|
sendDeleteRequest(path);
|
2026-05-03 09:44:32 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-08 14:44:40 +02:00
|
|
|
bool ServerCommunicator::validLoginCredentials() {
|
|
|
|
|
if (url().isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (m_email.isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (m_password.isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-03 09:44:32 +02:00
|
|
|
void ServerCommunicator::sendGetRequest(const QString& path) {
|
|
|
|
|
// TODO check for valid path, instead of emptiness
|
|
|
|
|
if (path.isEmpty()) {
|
|
|
|
|
qDebug() << "Empty path -> Not sending a request.";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QNetworkRequest request = m_serviceApi->createRequest(path);
|
|
|
|
|
m_restManager->get(request, this, [this, path](QRestReply& reply) {
|
|
|
|
|
if (reply.isSuccess()) {
|
|
|
|
|
qInfo() << "Request successful.";
|
|
|
|
|
const QJsonDocument doc = reply.readJson().value();
|
|
|
|
|
onGetReplySuccessful(path, doc);
|
|
|
|
|
} else {
|
|
|
|
|
if (reply.hasError()) {
|
|
|
|
|
const QString errorString = reply.errorString();
|
|
|
|
|
qWarning() << "Network error:" << errorString;
|
|
|
|
|
onGetReplyFailure(path, errorString);
|
|
|
|
|
} else {
|
|
|
|
|
int statusCode = reply.httpStatus();
|
|
|
|
|
qWarning() << "Request not successful:" << statusCode;
|
2026-05-08 14:44:40 +02:00
|
|
|
if (statusCode == 401) {
|
|
|
|
|
notAuthorized(path);
|
|
|
|
|
} else {
|
|
|
|
|
onGetReplyFailure(path, QString("HTTP status code: %1").arg(statusCode));
|
|
|
|
|
}
|
2026-05-03 09:44:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::onGetReplySuccessful(const QString& path, const QJsonDocument doc) {
|
|
|
|
|
if (path == ROUTE_ITEMS) {
|
|
|
|
|
emit itemsFetched(doc.toJson());
|
|
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::onGetReplyFailure(const QString& path, const QString errorString) {
|
|
|
|
|
if (path == ROUTE_ITEMS) {
|
|
|
|
|
emit itemsFetchFailure(errorString);
|
|
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-04 08:16:48 +02:00
|
|
|
void ServerCommunicator::sendPostRequest(const QString& path, const QByteArray data) {
|
|
|
|
|
const QNetworkRequest request = m_serviceApi->createRequest(path);
|
2026-05-03 09:44:32 +02:00
|
|
|
|
2026-05-04 08:16:48 +02:00
|
|
|
m_restManager->post(request, data, this, [this, path](QRestReply& reply) {
|
|
|
|
|
if (reply.isSuccess()) {
|
|
|
|
|
int statusCode = reply.httpStatus();
|
|
|
|
|
qInfo() << "Request successful. Status code:" << statusCode;
|
|
|
|
|
const QJsonDocument doc = reply.readJson().value();
|
|
|
|
|
onPostReplySuccessful(path, doc);
|
|
|
|
|
} else {
|
|
|
|
|
if (reply.hasError()) {
|
|
|
|
|
const QString errorString = reply.errorString();
|
|
|
|
|
qWarning() << "Network error:" << errorString;
|
|
|
|
|
onPostReplyFailure(path, errorString);
|
|
|
|
|
} else {
|
|
|
|
|
int statusCode = reply.httpStatus();
|
|
|
|
|
qWarning() << "Request not successful:" << statusCode;
|
|
|
|
|
qInfo() << "Content:" << reply.readJson();
|
2026-05-08 14:44:40 +02:00
|
|
|
if (statusCode == 401) {
|
|
|
|
|
notAuthorized(path);
|
|
|
|
|
} else {
|
|
|
|
|
onPostReplyFailure(path, QString("HTTP status code: %1").arg(statusCode));
|
|
|
|
|
}
|
2026-05-04 08:16:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonDocument doc) {
|
|
|
|
|
if (path == ROUTE_ITEMS) {
|
|
|
|
|
emit sendItemSuccessful(doc.toJson());
|
2026-05-08 14:44:40 +02:00
|
|
|
} else if (path == ROUTE_LOG_IN) {
|
|
|
|
|
qCritical() << "Login success:" << doc.toJson(QJsonDocument::Compact);
|
|
|
|
|
emit loginSuccessful(doc.toJson(QJsonDocument::Compact));
|
2026-05-04 08:16:48 +02:00
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-05-03 09:44:32 +02:00
|
|
|
|
2026-05-04 08:16:48 +02:00
|
|
|
void ServerCommunicator::onPostReplyFailure(const QString& path, const QString errorString) {
|
|
|
|
|
if (path == ROUTE_ITEMS) {
|
|
|
|
|
emit sendItemFailure(errorString);
|
2026-05-08 14:44:40 +02:00
|
|
|
} else if (path == ROUTE_LOG_IN) {
|
|
|
|
|
qCritical() << "Login failure:" << errorString;
|
|
|
|
|
emit loginFailure(errorString);
|
2026-05-04 08:16:48 +02:00
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::sendDeleteRequest(const QString& path) {
|
|
|
|
|
const QNetworkRequest request = m_serviceApi->createRequest(path);
|
|
|
|
|
m_restManager->deleteResource(request, this, [this, path](QRestReply& reply) {
|
|
|
|
|
if (reply.isSuccess()) {
|
|
|
|
|
qInfo() << "Request successful.";
|
|
|
|
|
const QJsonDocument doc = reply.readJson().value();
|
|
|
|
|
onDeleteReplySuccessful(path, doc);
|
|
|
|
|
} else {
|
|
|
|
|
if (reply.hasError()) {
|
|
|
|
|
const QString errorString = reply.errorString();
|
|
|
|
|
qWarning() << "Network error:" << errorString;
|
|
|
|
|
onDeleteReplyFailure(path, errorString);
|
|
|
|
|
} else {
|
|
|
|
|
int statusCode = reply.httpStatus();
|
|
|
|
|
qWarning() << "Request not successful:" << statusCode;
|
2026-05-08 14:44:40 +02:00
|
|
|
if (statusCode == 401) {
|
|
|
|
|
notAuthorized(path);
|
|
|
|
|
} else {
|
|
|
|
|
onDeleteReplyFailure(path, QString("HTTP status code: %1").arg(statusCode));
|
|
|
|
|
}
|
2026-05-04 08:16:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::onDeleteReplySuccessful(const QString& path, const QJsonDocument doc) {
|
|
|
|
|
if (path.startsWith(ROUTE_ITEMS)) {
|
|
|
|
|
emit deleteItemSuccessful(doc.toJson());
|
|
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ServerCommunicator::onDeleteReplyFailure(const QString& path, const QString errorString) {
|
|
|
|
|
if (path.startsWith(ROUTE_ITEMS)) {
|
|
|
|
|
emit deleteItemFailure(errorString);
|
|
|
|
|
} else {
|
|
|
|
|
qWarning() << "Can't match request path:" << path;
|
|
|
|
|
}
|
|
|
|
|
}
|