From 760c778c3be824231564ef7b9009bbeb9aeb1bd8 Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Sun, 3 May 2026 09:44:32 +0200 Subject: [PATCH 1/3] fetchItems() uses the more generic sendGetRequest function. --- network/servercommunicator.cpp | 74 +++++++++++++++++++++++----------- network/servercommunicator.h | 4 ++ 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/network/servercommunicator.cpp b/network/servercommunicator.cpp index 8b683a2..bd5b011 100644 --- a/network/servercommunicator.cpp +++ b/network/servercommunicator.cpp @@ -51,28 +51,7 @@ void ServerCommunicator::setServerConfiguration(const QString url, } } -void ServerCommunicator::fetchItems() { - /// Set up a GET request - m_restManager->get(m_serviceApi->createRequest(ROUTE_ITEMS), this, [this](QRestReply& reply) { - if (reply.isSuccess()) { - qInfo() << "Fetching items successful."; - const QJsonDocument doc = reply.readJson().value(); - emit itemsFetched(doc.toJson()); - - } else { - if (reply.hasError()) { - const QString errorString = reply.errorString(); - qCritical() << "ERROR:" << errorString; - emit itemsFetchFailure(errorString); - } else { - int statusCode = reply.httpStatus(); - qCritical() << "ERROR:" << statusCode; - emit itemsFetchFailure(QString::number(statusCode)); - emit itemsFetchFailure(QString("HTTP status code: %1").arg(statusCode)); - } - } - }); -} +void ServerCommunicator::fetchItems() { sendGetRequest(ROUTE_ITEMS); } void ServerCommunicator::postItems(const QByteArray& jsonData) { QNetworkReply* reply = m_restManager->post(m_serviceApi->createRequest(ROUTE_ITEMS), jsonData); @@ -109,4 +88,53 @@ void ServerCommunicator::deleteItem(const QString& id) { } reply->deleteLater(); }); -} \ No newline at end of file +} + +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; + onGetReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } + } + }); +} + +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; + } +} + +void ServerCommunicator::onSendPostRequestTriggered(const QString& path, const QByteArray data) {} + +void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonDocument doc) {} + +void ServerCommunicator::onPostReplyFailure(const QString& path, const QString errorString) {} diff --git a/network/servercommunicator.h b/network/servercommunicator.h index 83f8be7..15bd111 100644 --- a/network/servercommunicator.h +++ b/network/servercommunicator.h @@ -44,6 +44,10 @@ class ServerCommunicator : public QObject { QString m_email; QString m_password; QString m_authToken; + + void sendGetRequest(const QString& path); + void onGetReplySuccessful(const QString& path, const QJsonDocument doc); + void onGetReplyFailure(const QString& path, const QString errorString); }; #endif // SERVERCOMMUNICATOR_H From ceaf6b5fbd4160148309cd6cf21a842d4a6743f5 Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Mon, 4 May 2026 08:16:48 +0200 Subject: [PATCH 2/3] sendItem(...) & deleteItem(...) use the more generic send...Request(...) functions. (No merging of UUID of sent item into model and no deletion of local item yet.) --- genericcore.cpp | 29 +++++---- genericcore.h | 10 +-- network/servercommunicator.cpp | 113 +++++++++++++++++++++++---------- network/servercommunicator.h | 21 ++++-- 4 files changed, 114 insertions(+), 59 deletions(-) diff --git a/genericcore.cpp b/genericcore.cpp index c21c655..a3a3ea1 100644 --- a/genericcore.cpp +++ b/genericcore.cpp @@ -159,7 +159,7 @@ void GenericCore::saveItems() { } void GenericCore::onSendItemTriggered(const QByteArray& jsonData) { - m_serverCommunicator->postItems(jsonData); + m_serverCommunicator->sendItem(jsonData); } void GenericCore::onItemsFetched(const QByteArray jsonData) { @@ -173,20 +173,20 @@ void GenericCore::onItemsFetchFailure(const QString errorString) { emit displayStatusMessage(QString("Error: %1").arg(errorString)); } -void GenericCore::onPostRequestSuccessful(const QByteArray responseData) { +void GenericCore::onSendItemSuccessful(const QByteArray responseData) { const QString message = m_mainModel->updateItemsFromJson(responseData); emit displayStatusMessage(message); } -void GenericCore::onPostRequestFailure(const QString errorString) { +void GenericCore::onSendItemFailure(const QString errorString) { emit displayStatusMessage(QString("Error: %1").arg(errorString)); } -void GenericCore::onDeleteRequestSuccessful(const QByteArray responseData) { +void GenericCore::onDeleteItemSuccessful(const QByteArray responseData) { qWarning() << "TODO: Process success response!!!"; } -void GenericCore::onDeleteRequestFailure(const QString errorString) { +void GenericCore::onDeleteItemFailure(const QString errorString) { qWarning() << "TODO: Process error response!!!"; } @@ -252,7 +252,8 @@ void GenericCore::setupServerCommunication() { /// request connections connect(this, &GenericCore::fetchItemsFromServer, m_serverCommunicator.get(), &ServerCommunicator::fetchItems); - connect(this, &GenericCore::postItemToServer, this, &GenericCore::onSendItemTriggered); + connect(this, &GenericCore::sendItemToServer, m_serverCommunicator.get(), + &ServerCommunicator::sendItem); connect(this, &GenericCore::deleteItemFromServer, m_serverCommunicator.get(), &ServerCommunicator::deleteItem); @@ -261,14 +262,14 @@ void GenericCore::setupServerCommunication() { &GenericCore::onItemsFetched); connect(m_serverCommunicator.get(), &ServerCommunicator::itemsFetchFailure, this, &GenericCore::onItemsFetchFailure); - connect(m_serverCommunicator.get(), &ServerCommunicator::postRequestSuccessful, this, - &GenericCore::onPostRequestSuccessful); - connect(m_serverCommunicator.get(), &ServerCommunicator::postRequestFailure, this, - &GenericCore::onPostRequestFailure); - connect(m_serverCommunicator.get(), &ServerCommunicator::deleteRequestSuccessful, this, - &GenericCore::onDeleteRequestSuccessful); - connect(m_serverCommunicator.get(), &ServerCommunicator::deleteRequestFailure, this, - &GenericCore::onDeleteRequestFailure); + connect(m_serverCommunicator.get(), &ServerCommunicator::sendItemSuccessful, this, + &GenericCore::onSendItemSuccessful); + connect(m_serverCommunicator.get(), &ServerCommunicator::sendItemFailure, this, + &GenericCore::onSendItemFailure); + connect(m_serverCommunicator.get(), &ServerCommunicator::deleteItemSuccessful, this, + &GenericCore::onDeleteItemSuccessful); + connect(m_serverCommunicator.get(), &ServerCommunicator::deleteItemFailure, this, + &GenericCore::onDeleteItemFailure); applyServerConfiguration(); } diff --git a/genericcore.h b/genericcore.h index 722b5cd..6711b7c 100644 --- a/genericcore.h +++ b/genericcore.h @@ -42,15 +42,15 @@ class GenericCore : public QObject { void onSendItemTriggered(const QByteArray& jsonData); void onItemsFetched(const QByteArray jsonData); void onItemsFetchFailure(const QString errorString); - void onPostRequestSuccessful(const QByteArray responseData); - void onPostRequestFailure(const QString errorString); - void onDeleteRequestSuccessful(const QByteArray responseData); - void onDeleteRequestFailure(const QString errorString); + void onSendItemSuccessful(const QByteArray responseData); + void onSendItemFailure(const QString errorString); + void onDeleteItemSuccessful(const QByteArray responseData); + void onDeleteItemFailure(const QString errorString); signals: void displayStatusMessage(QString message); void fetchItemsFromServer(); - void postItemToServer(const QByteArray& jsonData); + void sendItemToServer(const QByteArray& jsonData); void deleteItemFromServer(const QString& id); private: diff --git a/network/servercommunicator.cpp b/network/servercommunicator.cpp index bd5b011..b3c10b2 100644 --- a/network/servercommunicator.cpp +++ b/network/servercommunicator.cpp @@ -53,41 +53,13 @@ void ServerCommunicator::setServerConfiguration(const QString url, void ServerCommunicator::fetchItems() { sendGetRequest(ROUTE_ITEMS); } -void ServerCommunicator::postItems(const QByteArray& jsonData) { - QNetworkReply* reply = m_restManager->post(m_serviceApi->createRequest(ROUTE_ITEMS), jsonData); - - QObject::connect(reply, &QNetworkReply::finished, [=]() { - if (reply->error() == QNetworkReply::NoError) { - QByteArray responseData = reply->readAll(); - const QString message = QString("POST successful! Response: %1").arg(responseData); - qInfo() << message; - emit postRequestSuccessful(responseData); - } else { - const QString message = QString("Error: %1").arg(reply->errorString()); - qDebug() << message; - emit postRequestFailure(message); - } - reply->deleteLater(); - }); +void ServerCommunicator::sendItem(const QByteArray& jsonData) { + sendPostRequest(ROUTE_ITEMS, jsonData); } void ServerCommunicator::deleteItem(const QString& id) { - const QString deleteRoute = QString("%1/%2").arg(ROUTE_ITEMS, id); - QNetworkReply* reply = m_restManager->deleteResource(m_serviceApi->createRequest(deleteRoute)); - - QObject::connect(reply, &QNetworkReply::finished, [=]() { - if (reply->error() == QNetworkReply::NoError) { - QByteArray responseData = reply->readAll(); - const QString message = QString("DELETE successful! Response: %1").arg(responseData); - qInfo() << message; - emit deleteRequestSuccessful(responseData); - } else { - const QString message = QString("Error: %1").arg(reply->errorString()); - qDebug() << message; - emit deleteRequestFailure(message); - } - reply->deleteLater(); - }); + const QString path = QString("%1/%2").arg(ROUTE_ITEMS, id); + sendDeleteRequest(path); } void ServerCommunicator::sendGetRequest(const QString& path) { @@ -133,8 +105,79 @@ void ServerCommunicator::onGetReplyFailure(const QString& path, const QString er } } -void ServerCommunicator::onSendPostRequestTriggered(const QString& path, const QByteArray data) {} +void ServerCommunicator::sendPostRequest(const QString& path, const QByteArray data) { + const QNetworkRequest request = m_serviceApi->createRequest(path); -void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonDocument doc) {} + 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(); + onPostReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } + } + }); +} -void ServerCommunicator::onPostReplyFailure(const QString& path, const QString errorString) {} +void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonDocument doc) { + if (path == ROUTE_ITEMS) { + emit sendItemSuccessful(doc.toJson()); + } else { + qWarning() << "Can't match request path:" << path; + } +} + +void ServerCommunicator::onPostReplyFailure(const QString& path, const QString errorString) { + if (path == ROUTE_ITEMS) { + emit sendItemFailure(errorString); + } 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; + onDeleteReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } + } + }); +} + +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; + } +} diff --git a/network/servercommunicator.h b/network/servercommunicator.h index 15bd111..fcffe66 100644 --- a/network/servercommunicator.h +++ b/network/servercommunicator.h @@ -23,18 +23,21 @@ class ServerCommunicator : public QObject { public slots: void fetchItems(); - void postItems(const QByteArray& jsonData); + void sendItem(const QByteArray& jsonData); void deleteItem(const QString& id); + // NEXT editItem(const QByteArray& jsonData) signals: void urlChanged(); void itemsFetched(const QByteArray jsonDoc); void itemsFetchFailure(const QString errorString); - void postRequestSuccessful(const QByteArray responseData); - void postRequestFailure(const QString errorString); - void deleteRequestSuccessful(const QByteArray responseData); - void deleteRequestFailure(const QString errorString); + + void sendItemSuccessful(const QByteArray responseData); + void sendItemFailure(const QString errorString); + + void deleteItemSuccessful(const QByteArray responseData); + void deleteItemFailure(const QString errorString); private: QNetworkAccessManager m_netManager; @@ -48,6 +51,14 @@ class ServerCommunicator : public QObject { void sendGetRequest(const QString& path); void onGetReplySuccessful(const QString& path, const QJsonDocument doc); void onGetReplyFailure(const QString& path, const QString errorString); + + void sendPostRequest(const QString& path, const QByteArray data); + void onPostReplySuccessful(const QString& path, const QJsonDocument doc); + void onPostReplyFailure(const QString& path, const QString errorString); + + void sendDeleteRequest(const QString& path); + void onDeleteReplySuccessful(const QString& path, const QJsonDocument doc); + void onDeleteReplyFailure(const QString& path, const QString errorString); }; #endif // SERVERCOMMUNICATOR_H From 0feaf09d83b47bf15361891de5aebccf6d407d06 Mon Sep 17 00:00:00 2001 From: Bent Witthold Date: Fri, 8 May 2026 14:44:40 +0200 Subject: [PATCH 3/3] Auth token is stored in settings and deleted if a request is not authorized (with automatic re-login). Failed request need to be resend. --- data/settingshandler.cpp | 44 ++++++++++++++++++++++++++ data/settingshandler.h | 3 ++ formats/jsonparser.cpp | 24 ++++++++++++++ formats/jsonparser.h | 5 +++ genericcore.cpp | 57 ++++++++++++++++++++++++++++++++-- genericcore.h | 5 +++ network/apiroutes.h | 2 ++ network/servercommunicator.cpp | 48 +++++++++++++++++++++++++--- network/servercommunicator.h | 7 +++++ 9 files changed, 189 insertions(+), 6 deletions(-) diff --git a/data/settingshandler.cpp b/data/settingshandler.cpp index eb11006..691854b 100644 --- a/data/settingshandler.cpp +++ b/data/settingshandler.cpp @@ -40,4 +40,48 @@ void SettingsHandler::saveSettings(QVariantMap settingMap, QString group) { settings.sync(); } +void SettingsHandler::deleteSettings(QStringList keys, QString group) { + qInfo() << "deleting settings..."; + + QSettings settings; + if (!group.isEmpty()) { + qDebug() << "starting group:" << group; + settings.beginGroup(group); + } + + foreach (QString key, keys) { + qDebug() << "removing:" << key; + settings.remove(key); + } + if (!group.isEmpty()) { + settings.endGroup(); + } + + settings.sync(); +} + +QVariantMap SettingsHandler::getChangeset(QVariantMap newSettings, QString group) { + const QVariantMap oldSettings = getSettings(group); + + QVariantMap result; + + for (QVariantMap::const_iterator iter = newSettings.begin(); iter != newSettings.end(); ++iter) { + qDebug() << iter.key() << iter.value(); + QString key = iter.key(); + QVariant newValue = iter.value(); + QVariant oldValue = oldSettings.value(key); + + if (oldValue == newValue) { + qInfo() << "oldValue == newValue -> ignoring..."; + } else { + const QString debugString = + QString("oldValue != newValue -> adding '%1' to changeset...").arg(key); + qInfo() << debugString; + result.insert(key, newValue); + } + } + + return result; +} + SettingsHandler::SettingsHandler() {} diff --git a/data/settingshandler.h b/data/settingshandler.h index a636cf6..3488939 100644 --- a/data/settingshandler.h +++ b/data/settingshandler.h @@ -7,6 +7,9 @@ class SettingsHandler { public: static QVariantMap getSettings(QString group = ""); static void saveSettings(QVariantMap settingMap, QString group = ""); + static void deleteSettings(QStringList keys, QString group = ""); + + static QVariantMap getChangeset(QVariantMap newSettings, QString group = ""); private: SettingsHandler(); diff --git a/formats/jsonparser.cpp b/formats/jsonparser.cpp index 559ea20..b41c1e2 100644 --- a/formats/jsonparser.cpp +++ b/formats/jsonparser.cpp @@ -74,6 +74,30 @@ QJsonObject JsonParser::itemValuesToJsonObject(const ModelItemValues& itemValues return result; } +QByteArray JsonParser::userCredentialsToJsonDocument(const QString email, const QString password) { + QJsonDocument jsonDoc; + QJsonObject rootObject; + + QJsonObject userObject; + userObject.insert("email", email); + userObject.insert("password", password); + + rootObject.insert("user", userObject); + jsonDoc.setObject(rootObject); + + return jsonDoc.toJson(QJsonDocument::Compact); +} + +QVariant JsonParser::getValueFromJson(const QByteArray& jsonData, + const QString key, + const QString objectName) { + QJsonDocument doc = QJsonDocument::fromJson(jsonData); + QJsonObject rootObject = doc.object(); + QJsonObject userObject = rootObject.value(objectName).toObject(); + + return userObject.value(key); +} + JsonParser::JsonParser() {} QJsonArray JsonParser::extractItemArray(const QJsonDocument& doc, const QString& objectName) { diff --git a/formats/jsonparser.h b/formats/jsonparser.h index ba2a95f..fa805af 100644 --- a/formats/jsonparser.h +++ b/formats/jsonparser.h @@ -20,6 +20,11 @@ class JsonParser { const QString& objectName = ""); static QJsonObject itemValuesToJsonObject(const ModelItemValues& itemValues); + static QByteArray userCredentialsToJsonDocument(const QString email, const QString password); + static QVariant getValueFromJson(const QByteArray& jsonData, + const QString key, + const QString objectName = ""); + private: explicit JsonParser(); diff --git a/genericcore.cpp b/genericcore.cpp index a3a3ea1..c5d7f76 100644 --- a/genericcore.cpp +++ b/genericcore.cpp @@ -14,6 +14,7 @@ #include "constants.h" #include "data/filehandler.h" #include "data/settingshandler.h" +#include "formats/jsonparser.h" #include "model/generalsortfiltermodel.h" #include "model/metadata.h" #include "model/tablemodel.h" @@ -126,6 +127,24 @@ QVariantMap GenericCore::getSettings(QString group) const { } void GenericCore::applySettings(QVariantMap settingMap, QString group) { + const QVariantMap changeset = SettingsHandler::getChangeset(settingMap, group); + + if (changeset.isEmpty()) { + return; + } + + if (group == "Server") { + const bool urlChanged = changeset.contains("url"); + const bool emailChanged = changeset.contains("email"); + const bool passwordChanged = changeset.contains("password"); + if (urlChanged || emailChanged || passwordChanged) { + if (!changeset.contains("authToken")) { + qInfo() << "Account settings changed, but no new token present. Deleting old token..."; + SettingsHandler::deleteSettings({"authToken"}, "Server"); + } + } + } + SettingsHandler::saveSettings(settingMap, group); if (group == "Server") { @@ -158,6 +177,30 @@ void GenericCore::saveItems() { } } +void GenericCore::onLoginSuccessful(const QByteArray jsonData) { + emit displayStatusMessage("Login successful."); + qInfo() << "Storing auth token..."; + QString token = JsonParser::getValueFromJson(jsonData, "token", "user").toString(); + SettingsHandler::saveSettings({{"authToken", token}}, "Server"); + applyServerConfiguration(); +} + +void GenericCore::onLoginFailure(const QString errorString) { + emit displayStatusMessage(QString("Error: %1").arg(errorString)); +} + +void GenericCore::onNotAuthorized(const QString /*path*/) { + const QVariantMap serverSettings = SettingsHandler::getSettings("Server"); + const QString tokenValue = serverSettings.value("authToken").toString(); + if (!tokenValue.isEmpty()) { + SettingsHandler::deleteSettings({"authToken"}, "Server"); + displayStatusMessage("Not authorized! Deleted token. Please retry."); + } else { + displayStatusMessage("Not authorized! But no token was present. Please check your settings."); + } + applyServerConfiguration(); +} + void GenericCore::onSendItemTriggered(const QByteArray& jsonData) { m_serverCommunicator->sendItem(jsonData); } @@ -258,6 +301,14 @@ void GenericCore::setupServerCommunication() { &ServerCommunicator::deleteItem); /// response connections + connect(m_serverCommunicator.get(), &ServerCommunicator::loginSuccessful, this, + &GenericCore::onLoginSuccessful); + connect(m_serverCommunicator.get(), &ServerCommunicator::loginFailure, this, + &GenericCore::onLoginFailure); + + connect(m_serverCommunicator.get(), &ServerCommunicator::notAuthorized, this, + &GenericCore::onNotAuthorized); + connect(m_serverCommunicator.get(), &ServerCommunicator::itemsFetched, this, &GenericCore::onItemsFetched); connect(m_serverCommunicator.get(), &ServerCommunicator::itemsFetchFailure, this, @@ -277,8 +328,10 @@ void GenericCore::setupServerCommunication() { void GenericCore::applyServerConfiguration() { const QVariantMap serverSettings = SettingsHandler::getSettings("Server"); const QString urlValue = serverSettings.value("url").toString(); - // NEXT if urlValue is empty -> remove authToken from settings? - if (!urlValue.isEmpty()) { + if (urlValue.isEmpty()) { + SettingsHandler::deleteSettings({"authToken"}, "Server"); + } else { + /// urlValue in NOT empty const QString emailValue = serverSettings.value("email").toString(); const QString passwordValue = serverSettings.value("password").toString(); const QString authTokenValue = serverSettings.value("authToken").toString(); diff --git a/genericcore.h b/genericcore.h index 6711b7c..22df81a 100644 --- a/genericcore.h +++ b/genericcore.h @@ -39,6 +39,11 @@ class GenericCore : public QObject { public slots: void saveItems(); + void onLoginSuccessful(const QByteArray jsonData); + void onLoginFailure(const QString errorString); + + void onNotAuthorized(const QString /*path*/); + void onSendItemTriggered(const QByteArray& jsonData); void onItemsFetched(const QByteArray jsonData); void onItemsFetchFailure(const QString errorString); diff --git a/network/apiroutes.h b/network/apiroutes.h index e89da3a..12b25d6 100644 --- a/network/apiroutes.h +++ b/network/apiroutes.h @@ -7,6 +7,8 @@ static const QString apiPrefix = "/api/"; +static const QString ROUTE_LOG_IN = apiPrefix + "log_in"; + static const QString ROUTE_ITEMS = apiPrefix + "items"; #endif // APIROUTES_H diff --git a/network/servercommunicator.cpp b/network/servercommunicator.cpp index b3c10b2..1684bf1 100644 --- a/network/servercommunicator.cpp +++ b/network/servercommunicator.cpp @@ -6,6 +6,8 @@ #include #include +#include "../formats/jsonparser.h" + using namespace Qt::StringLiterals; ServerCommunicator::ServerCommunicator(QObject* parent) @@ -46,7 +48,14 @@ void ServerCommunicator::setServerConfiguration(const QString url, m_password = password; m_authToken = authToken; - if (!authToken.isEmpty()) { + if (authToken.isEmpty()) { + if (validLoginCredentials()) { + const QByteArray userCredentials = + JsonParser::userCredentialsToJsonDocument(m_email, m_password); + sendPostRequest(ROUTE_LOG_IN, userCredentials); + } + } else { + /// authToken not empty: m_serviceApi->setBearerToken(authToken.toLatin1()); } } @@ -62,6 +71,19 @@ void ServerCommunicator::deleteItem(const QString& id) { sendDeleteRequest(path); } +bool ServerCommunicator::validLoginCredentials() { + if (url().isEmpty()) { + return false; + } + if (m_email.isEmpty()) { + return false; + } + if (m_password.isEmpty()) { + return false; + } + return true; +} + void ServerCommunicator::sendGetRequest(const QString& path) { // TODO check for valid path, instead of emptiness if (path.isEmpty()) { @@ -83,7 +105,11 @@ void ServerCommunicator::sendGetRequest(const QString& path) { } else { int statusCode = reply.httpStatus(); qWarning() << "Request not successful:" << statusCode; - onGetReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + if (statusCode == 401) { + notAuthorized(path); + } else { + onGetReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } } } }); @@ -123,7 +149,11 @@ void ServerCommunicator::sendPostRequest(const QString& path, const QByteArray d int statusCode = reply.httpStatus(); qWarning() << "Request not successful:" << statusCode; qInfo() << "Content:" << reply.readJson(); - onPostReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + if (statusCode == 401) { + notAuthorized(path); + } else { + onPostReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } } } }); @@ -132,6 +162,9 @@ void ServerCommunicator::sendPostRequest(const QString& path, const QByteArray d void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonDocument doc) { if (path == ROUTE_ITEMS) { emit sendItemSuccessful(doc.toJson()); + } else if (path == ROUTE_LOG_IN) { + qCritical() << "Login success:" << doc.toJson(QJsonDocument::Compact); + emit loginSuccessful(doc.toJson(QJsonDocument::Compact)); } else { qWarning() << "Can't match request path:" << path; } @@ -140,6 +173,9 @@ void ServerCommunicator::onPostReplySuccessful(const QString& path, const QJsonD void ServerCommunicator::onPostReplyFailure(const QString& path, const QString errorString) { if (path == ROUTE_ITEMS) { emit sendItemFailure(errorString); + } else if (path == ROUTE_LOG_IN) { + qCritical() << "Login failure:" << errorString; + emit loginFailure(errorString); } else { qWarning() << "Can't match request path:" << path; } @@ -160,7 +196,11 @@ void ServerCommunicator::sendDeleteRequest(const QString& path) { } else { int statusCode = reply.httpStatus(); qWarning() << "Request not successful:" << statusCode; - onDeleteReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + if (statusCode == 401) { + notAuthorized(path); + } else { + onDeleteReplyFailure(path, QString("HTTP status code: %1").arg(statusCode)); + } } } }); diff --git a/network/servercommunicator.h b/network/servercommunicator.h index fcffe66..77b4d00 100644 --- a/network/servercommunicator.h +++ b/network/servercommunicator.h @@ -30,6 +30,11 @@ class ServerCommunicator : public QObject { signals: void urlChanged(); + void loginSuccessful(const QByteArray responseData); + void loginFailure(const QString errorString); + + void notAuthorized(const QString path); + void itemsFetched(const QByteArray jsonDoc); void itemsFetchFailure(const QString errorString); @@ -48,6 +53,8 @@ class ServerCommunicator : public QObject { QString m_password; QString m_authToken; + bool validLoginCredentials(); + void sendGetRequest(const QString& path); void onGetReplySuccessful(const QString& path, const QJsonDocument doc); void onGetReplyFailure(const QString& path, const QString errorString);