feat(profile): selezione del profilo di cui vedere le sessioni (v0.5.0)

- Impostazioni > Sessions: selettore "Profile" (elenco da /api/profiles;
  "(server active)" come prima voce = nessun cookie di profilo)
- ApiClient: fetchProfiles() + switchProfile(); lo switch usa
  /api/profile/switch (process_wide=False lato server: il cookie firmato
  hermes_profile scopa le richieste dell'app per-client; il profilo attivo
  globale del server non viene toccato); refresh automatico delle sessioni
- CookieJar::removeCookiesByName per l'opzione "(server active)"
- Il profilo scelto viene riapplicato automaticamente dopo il login
- i18n: nuove stringhe tradotte it/fr/de
This commit is contained in:
2026-09-12 22:46:27 +02:00
parent 22ccb49424
commit 7b8e5e1102
15 changed files with 421 additions and 104 deletions
+78 -1
View File
@@ -1,6 +1,7 @@
#include "apiclient.h"
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
@@ -29,6 +30,9 @@ ApiClient::ApiClient(Settings *settings, QObject *parent)
m_jar->setFilePath(cfg + QStringLiteral("/cookies.dat"));
m_jar->load();
m_nam.setCookieJar(m_jar);
// Il profilo selezionato (impostazione app) e' esposto anche da ApiClient.
connect(m_settings, &Settings::profileChanged, this, &ApiClient::profileChanged);
}
// ---------------------------------------------------------------- helpers --
@@ -170,7 +174,12 @@ void ApiClient::login(const QString &password)
return;
}
setLoggedIn(true);
refreshSessions();
// Riapplica il profilo scelto dall'utente: il nuovo cookie di sessione
// va rilegato al profilo (switchProfile aggiorna anche le sessioni).
if (!m_settings->profile().isEmpty())
switchProfile(m_settings->profile());
else
refreshSessions();
});
}
@@ -221,6 +230,74 @@ int ApiClient::sessionsCount() const
return m_sessionsModel->rowCount();
}
QString ApiClient::profile() const
{
return m_settings->profile();
}
void ApiClient::fetchProfiles()
{
QNetworkReply *reply = m_nam.get(jsonRequest(QStringLiteral("/api/profiles")));
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
reply->deleteLater();
const QByteArray data = reply->readAll();
const int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status < 200 || status >= 300) {
qDebug() << "[api] fetchProfiles HTTP" << status;
return;
}
const QJsonArray arr = QJsonDocument::fromJson(data).object()
.value(QStringLiteral("profiles")).toArray();
QStringList names;
for (int i = 0; i < arr.size(); ++i) {
const QString n = arr.at(i).toObject().value(QStringLiteral("name")).toString();
if (!n.isEmpty())
names << n;
}
qDebug() << "[api] profili disponibili:" << names;
if (names != m_profiles) {
m_profiles = names;
emit profilesChanged();
}
});
}
void ApiClient::switchProfile(const QString &name)
{
const QString target = name.trimmed();
if (target.isEmpty()) {
// "(attivo sul server)": rimuove il cookie di profilo e torna a
// seguire il profilo attivo del server.
m_jar->removeCookiesByName(QStringLiteral("hermes_profile"));
m_settings->setProfile(QString());
emit profileSwitched(QString());
refreshSessions();
return;
}
QJsonObject body;
body.insert(QStringLiteral("name"), target);
QNetworkReply *reply = m_nam.post(jsonRequest(QStringLiteral("/api/profile/switch")),
QJsonDocument(body).toJson(QJsonDocument::Compact));
connect(reply, &QNetworkReply::finished, this, [this, reply, target]() {
reply->deleteLater();
const QByteArray data = reply->readAll();
const int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (status >= 200 && status < 300) {
// Il Set-Cookie firmato (hermes_profile) viene salvato dal jar:
// da qui in poi le richieste dell'app sono profilate lato server.
m_settings->setProfile(target);
qDebug() << "[api] profilo selezionato:" << target;
emit profileSwitched(target);
refreshSessions();
} else {
const QString err = errorFromReply(reply, data);
qDebug() << "[api] switch profilo fallito:" << err;
emit profileSwitchFailed(err);
}
});
}
void ApiClient::openSession(const QString &id)
{
setLastError(QString());