If no authToken is stored in settings but email and password are on startup the log_in route is triggered to receive a new token. This token will be used to access a protected API.

This commit is contained in:
2026-02-20 16:44:58 +01:00
parent 064da850c4
commit 6cd205506f
10 changed files with 113 additions and 15 deletions

View File

@ -27,12 +27,12 @@ void SettingsDialog::createContent() {
serverLayout->addWidget(m_urlEdit, 0, 1); serverLayout->addWidget(m_urlEdit, 0, 1);
QLabel* emailLabel = new QLabel("Email:"); QLabel* emailLabel = new QLabel("Email:");
m_emailEdit = new QLineEdit(); m_emailEdit = new QLineEdit();
m_emailEdit->setEnabled(false); // m_emailEdit->setEnabled(false);
serverLayout->addWidget(emailLabel, 1, 0); serverLayout->addWidget(emailLabel, 1, 0);
serverLayout->addWidget(m_emailEdit, 1, 1); serverLayout->addWidget(m_emailEdit, 1, 1);
QLabel* passwordLabel = new QLabel("Password:"); QLabel* passwordLabel = new QLabel("Password:");
m_passwordEdit = new QLineEdit(); m_passwordEdit = new QLineEdit();
m_passwordEdit->setEnabled(false); // m_passwordEdit->setEnabled(false);
m_passwordEdit->setEchoMode(QLineEdit::Password); m_passwordEdit->setEchoMode(QLineEdit::Password);
serverLayout->addWidget(passwordLabel, 2, 0); serverLayout->addWidget(passwordLabel, 2, 0);
serverLayout->addWidget(m_passwordEdit, 2, 1); serverLayout->addWidget(m_passwordEdit, 2, 1);

View File

@ -572,4 +572,5 @@ void MainWindow::initServerConnection() {
&GenericCore::onCreateOnlineAccountTriggered); &GenericCore::onCreateOnlineAccountTriggered);
connect(m_editItemDialog.get(), &EditItemDialog::sendInviteMailTriggered, m_core.get(), connect(m_editItemDialog.get(), &EditItemDialog::sendInviteMailTriggered, m_core.get(),
&GenericCore::onSendInviteMailTriggered); &GenericCore::onSendInviteMailTriggered);
emit m_core->loginAndStoreAuthToken();
} }

View File

@ -71,7 +71,7 @@ QByteArray JsonParser::itemValuesListToJson(const QList<ModelItemValues>& itemVa
return jsonDoc.toJson(QJsonDocument::Compact); return jsonDoc.toJson(QJsonDocument::Compact);
} }
QByteArray JsonParser::ToJsonObject(const QHash<QString, QVariant>& values, QByteArray JsonParser::toJsonDoc(const QHash<QString, QVariant>& values,
const QString& objectName) { const QString& objectName) {
QJsonDocument jsonDoc; QJsonDocument jsonDoc;
QJsonObject rootObject; QJsonObject rootObject;

View File

@ -19,7 +19,7 @@ class JsonParser {
const QString& rootValueName = ""); const QString& rootValueName = "");
static QByteArray itemValuesListToJson(const QList<ModelItemValues>& itemValuesList, static QByteArray itemValuesListToJson(const QList<ModelItemValues>& itemValuesList,
const QString& objectName = ""); const QString& objectName = "");
static QByteArray ToJsonObject(const QHash<QString, QVariant>& Values, static QByteArray toJsonDoc(const QHash<QString, QVariant>& Values,
const QString& objectName = ""); const QString& objectName = "");
static ModelItemValues serverUserCredentialsToItemValues(const QJsonDocument& jsonDoc); static ModelItemValues serverUserCredentialsToItemValues(const QJsonDocument& jsonDoc);

View File

@ -156,6 +156,12 @@ bool GenericCore::isSyncServerSetup() const {
} }
} }
void GenericCore::onLoginSuccessful() {
qInfo() << "Login successful.";
emit displayStatusMessage("Login successful.");
emit sendGetRequest(GetCurrentBiddingRound);
}
void GenericCore::onBiddingsChanged(const QList<bidding> biddings) { void GenericCore::onBiddingsChanged(const QList<bidding> biddings) {
qInfo() << "onBiddingsChanged: biddings:" << biddings.count(); qInfo() << "onBiddingsChanged: biddings:" << biddings.count();
// NEXT merge biddings into model // NEXT merge biddings into model
@ -166,7 +172,7 @@ void GenericCore::onCreateOnlineAccountTriggered(const QString& mailAddress) {
qInfo() << "Creating online account for:" << mailAddress; qInfo() << "Creating online account for:" << mailAddress;
QHash<QString, QVariant> hash; QHash<QString, QVariant> hash;
hash.insert("email", mailAddress); hash.insert("email", mailAddress);
const QByteArray jsonDoc = JsonParser::ToJsonObject(hash, "user"); const QByteArray jsonDoc = JsonParser::toJsonDoc(hash, "user");
emit sendPostRequest(RegisterUser, jsonDoc); emit sendPostRequest(RegisterUser, jsonDoc);
} }
@ -256,6 +262,7 @@ void GenericCore::applyServerConfiguration() {
if (!urlValue.isEmpty()) { if (!urlValue.isEmpty()) {
const QString emailValue = serverSettings.value("email").toString(); const QString emailValue = serverSettings.value("email").toString();
const QString passwordValue = serverSettings.value("password").toString(); const QString passwordValue = serverSettings.value("password").toString();
m_serverCommunicator->setServerConfiguration(urlValue, emailValue, passwordValue); const QString authToken = serverSettings.value("token").toString();
m_serverCommunicator->setServerConfiguration(urlValue, emailValue, passwordValue, authToken);
} }
} }

View File

@ -47,6 +47,8 @@ class GenericCore : public QObject {
bool isSyncServerSetup() const; bool isSyncServerSetup() const;
public slots: public slots:
void onLoginSuccessful();
void onBiddingsChanged(const QList<bidding> biddings); void onBiddingsChanged(const QList<bidding> biddings);
void onCreateOnlineAccountTriggered(const QString& mailAddress); void onCreateOnlineAccountTriggered(const QString& mailAddress);
@ -59,6 +61,7 @@ class GenericCore : public QObject {
void displayStatusMessage(QString message); void displayStatusMessage(QString message);
/// *** server communication *** /// *** server communication ***
void loginAndStoreAuthToken();
/// request signals /// request signals
void sendGetRequest(GetRequestTypes type, QVariant data = QVariant()); void sendGetRequest(GetRequestTypes type, QVariant data = QVariant());
void sendPostRequest(PostRequestTypes type, QByteArray data); void sendPostRequest(PostRequestTypes type, QByteArray data);

View File

@ -91,7 +91,7 @@ enum GetRequestTypes {
GetBiddingsOfSpecificRound, GetBiddingsOfSpecificRound,
GetBiddingsOfHighestRound GetBiddingsOfHighestRound
}; };
enum PostRequestTypes { RegisterUser, MailInvite }; enum PostRequestTypes { LogInAdmin, RegisterUser, MailInvite };
/// functions /// functions
static UserRoles GET_ROLE_FOR_COLUMN(const int column) { static UserRoles GET_ROLE_FOR_COLUMN(const int column) {

View File

@ -5,12 +5,14 @@
// TODO add namespace // TODO add namespace
static const QString ROUTE_LOG_IN = "/log_in"; static const QString ROUTE_USER_LOG_IN = "/log_in";
static const QString apiPrefix = "/api/"; static const QString apiPrefix = "/api/";
static const QString ROUTE_ITEMS = apiPrefix + "items"; static const QString ROUTE_ITEMS = apiPrefix + "items";
static const QString ROUTE_ADMIN_LOG_IN = apiPrefix + "log_in";
static const QString ROUTE_REGISTER_USER = apiPrefix + "users"; static const QString ROUTE_REGISTER_USER = apiPrefix + "users";
static const QString ROUTE_MAIL_INVITE = apiPrefix + "invite"; static const QString ROUTE_MAIL_INVITE = apiPrefix + "invite";

View File

@ -10,6 +10,8 @@
#include "../structs.h" #include "../structs.h"
#include "apiroutes.h" #include "apiroutes.h"
#include "../data/settingshandler.h"
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
ServerCommunicator::ServerCommunicator(GenericCore* core) ServerCommunicator::ServerCommunicator(GenericCore* core)
@ -19,6 +21,9 @@ ServerCommunicator::ServerCommunicator(GenericCore* core)
m_restManager = std::make_shared<QRestAccessManager>(&m_netManager); m_restManager = std::make_shared<QRestAccessManager>(&m_netManager);
m_serviceApi = std::make_shared<QNetworkRequestFactory>(); m_serviceApi = std::make_shared<QNetworkRequestFactory>();
connect(core, &GenericCore::loginAndStoreAuthToken, this, &ServerCommunicator::onLoginTriggered);
connect(this, &ServerCommunicator::loginSuccessful, core, &GenericCore::onLoginSuccessful);
connect(m_core, &GenericCore::sendGetRequest, this, connect(m_core, &GenericCore::sendGetRequest, this,
&ServerCommunicator::onSendGetRequestTriggered); &ServerCommunicator::onSendGetRequestTriggered);
connect(m_core, &GenericCore::sendPostRequest, this, connect(m_core, &GenericCore::sendPostRequest, this,
@ -51,15 +56,21 @@ void ServerCommunicator::setUrl(const QUrl& url) {
void ServerCommunicator::setServerConfiguration(const QString url, void ServerCommunicator::setServerConfiguration(const QString url,
const QString email, const QString email,
const QString password) { const QString password,
const QString authToken) {
setUrl(url); setUrl(url);
m_email = email; m_email = email;
m_password = password; m_password = password;
m_authToken = authToken;
if (!m_authToken.isEmpty()) {
m_serviceApi->setBearerToken(authToken.toLatin1());
}
} }
QString ServerCommunicator::getUserLoginUrl() const { QString ServerCommunicator::getUserLoginUrl() const {
const QString logInUrl = m_serviceApi->baseUrl().toString() + ROUTE_LOG_IN; const QString logInUrl = m_serviceApi->baseUrl().toString() + ROUTE_USER_LOG_IN;
return logInUrl; return logInUrl;
} }
@ -96,6 +107,7 @@ void ServerCommunicator::onSendGetRequestTriggered(const GetRequestTypes type,
return; return;
} }
m_serviceApi->setBearerToken(m_authToken.toLatin1());
const QNetworkRequest request = m_serviceApi->createRequest(path); const QNetworkRequest request = m_serviceApi->createRequest(path);
m_restManager->get(request, this, [this, type](QRestReply& reply) { m_restManager->get(request, this, [this, type](QRestReply& reply) {
@ -145,6 +157,9 @@ void ServerCommunicator::onSendPostRequestTriggered(const PostRequestTypes type,
const QByteArray data) { const QByteArray data) {
QString path; QString path;
switch (type) { switch (type) {
case LogInAdmin:
path = ROUTE_ADMIN_LOG_IN;
break;
case RegisterUser: case RegisterUser:
path = ROUTE_REGISTER_USER; path = ROUTE_REGISTER_USER;
break; break;
@ -162,6 +177,7 @@ void ServerCommunicator::onSendPostRequestTriggered(const PostRequestTypes type,
return; return;
} }
m_serviceApi->setBearerToken(m_authToken.toLatin1());
const QNetworkRequest request = m_serviceApi->createRequest(path); const QNetworkRequest request = m_serviceApi->createRequest(path);
m_restManager->post(request, data, this, [this, type](QRestReply& reply) { m_restManager->post(request, data, this, [this, type](QRestReply& reply) {
@ -188,6 +204,10 @@ void ServerCommunicator::onSendPostRequestTriggered(const PostRequestTypes type,
void ServerCommunicator::onPostReplySuccessful(const PostRequestTypes type, void ServerCommunicator::onPostReplySuccessful(const PostRequestTypes type,
const QJsonDocument doc) { const QJsonDocument doc) {
switch (type) { switch (type) {
case LogInAdmin:
qInfo() << "Admin successfully logged in:" << type;
handleLogInReply(doc);
break;
case RegisterUser: case RegisterUser:
qInfo() << "Register user successful:" << type; qInfo() << "Register user successful:" << type;
onlineUserAccountReply(doc); onlineUserAccountReply(doc);
@ -207,7 +227,34 @@ void ServerCommunicator::onPostReplyFailure(const PostRequestTypes type,
const QString message = const QString message =
QString("Request of type %1 returned: %2").arg(QString::number(type), errorString); QString("Request of type %1 returned: %2").arg(QString::number(type), errorString);
// NEXT improve error message to the UI; // NEXT improve error message to the UI;
m_core->displayStatusMessage(message); emit m_core->displayStatusMessage(message);
}
QByteArray ServerCommunicator::createLoginBody() {
QHash<QString, QVariant> values;
values.insert("email", m_email);
values.insert("password", m_password);
return JsonParser::toJsonDoc(values, "admin");
}
void ServerCommunicator::handleLogInReply(const QJsonDocument jsonDoc) {
QJsonObject rootObject = jsonDoc.object();
bool hasErrors = rootObject.contains(QString("errors"));
if (hasErrors) {
qCritical() << "Reply has error(s)!";
QString errorString = rootObject["errors"].toString();
emit m_core->displayStatusMessage(errorString);
} else {
qInfo() << "Reply has no error(s)!";
const QJsonObject dataObject = rootObject["data"].toObject();
const QString authToken = dataObject["token"].toString();
m_authToken = authToken;
SettingsHandler::saveSettings({{"token", authToken}}, "Server");
emit loginSuccessful();
emit m_core->displayStatusMessage("Successfully logged in.");
}
} }
void ServerCommunicator::currentBiddingRoundChangedReply(const QJsonDocument jsonDoc) { void ServerCommunicator::currentBiddingRoundChangedReply(const QJsonDocument jsonDoc) {
@ -245,3 +292,30 @@ void ServerCommunicator::mailInviteSentReply(const QJsonDocument jsonDoc) {
qInfo() << "Invitation mail successfully sent."; qInfo() << "Invitation mail successfully sent.";
emit m_core->displayStatusMessage("Invitation mail successfully sent."); emit m_core->displayStatusMessage("Invitation mail successfully sent.");
} }
void ServerCommunicator::onLoginTriggered() {
qInfo() << "Login triggered...";
if (m_email.isEmpty() || m_password.isEmpty()) {
emit m_core->displayStatusMessage(
"Missing email or password in settings! Not trying to log in.");
return;
}
if (m_authToken.isEmpty()) {
/// get new authToken
qWarning() << "Creating a new authToken!";
const QByteArray loginBody = createLoginBody();
onSendPostRequestTriggered(LogInAdmin, loginBody);
} else {
/// try authToken
qWarning() << "Validity check of token not implemented yet!!!";
qInfo() << "Assuming validity of token...";
emit loginSuccessful();
// TODO try validity of token and trigger log_in if not valid
// try default route to test access;
// if (access denied) {
// m_apiClient->sendAPIRequestPost(ROUTE_LOG_IN_ADMIN, );
// }
}
}

View File

@ -22,10 +22,15 @@ class ServerCommunicator : public QObject {
QUrl url() const; QUrl url() const;
void setUrl(const QUrl& url); void setUrl(const QUrl& url);
void setServerConfiguration(const QString url, const QString email, const QString password); void setServerConfiguration(const QString url,
const QString email,
const QString password,
const QString authToken);
QString getUserLoginUrl() const; QString getUserLoginUrl() const;
public slots: public slots:
void onLoginTriggered();
void onSendGetRequestTriggered(const GetRequestTypes type, QVariant data); void onSendGetRequestTriggered(const GetRequestTypes type, QVariant data);
void onGetReplySuccessful(const GetRequestTypes type, const QJsonDocument doc); void onGetReplySuccessful(const GetRequestTypes type, const QJsonDocument doc);
void onGetReplyFailure(const GetRequestTypes type, const QString errorString); void onGetReplyFailure(const GetRequestTypes type, const QString errorString);
@ -44,6 +49,8 @@ class ServerCommunicator : public QObject {
void deleteRequestSuccessful(const QByteArray responseData); void deleteRequestSuccessful(const QByteArray responseData);
void deleteRequestFailure(const QString errorString); void deleteRequestFailure(const QString errorString);
void loginSuccessful();
void currentBiddingRoundChanged(int round, bool isRunning); void currentBiddingRoundChanged(int round, bool isRunning);
void biddingsChanged(QList<bidding> biddings); void biddingsChanged(QList<bidding> biddings);
void onlineUserAccountReceived(const QString mailAddress, void onlineUserAccountReceived(const QString mailAddress,
@ -59,9 +66,13 @@ class ServerCommunicator : public QObject {
QString m_email; QString m_email;
QString m_password; QString m_password;
// QString m_authToken; QString m_authToken;
QByteArray createLoginBody();
/// reply parser /// reply parser
void handleLogInReply(const QJsonDocument jsonDoc);
void currentBiddingRoundChangedReply(const QJsonDocument jsonDoc); void currentBiddingRoundChangedReply(const QJsonDocument jsonDoc);
void currentBiddingsReply(const QJsonDocument jsonDoc); void currentBiddingsReply(const QJsonDocument jsonDoc);
void onlineUserAccountReply(const QJsonDocument jsonDoc); void onlineUserAccountReply(const QJsonDocument jsonDoc);