2026-08-26 00:28:35 +02:00
|
|
|
#include "settings.h"
|
|
|
|
|
|
|
|
|
|
#include <QEventLoop>
|
|
|
|
|
#include <QUrl>
|
|
|
|
|
|
2026-09-26 10:17:13 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2026-08-26 00:28:35 +02:00
|
|
|
#include <qt6keychain/keychain.h>
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
const QLatin1String kService("photogallery-uploader");
|
|
|
|
|
const QLatin1String kPasswordKey("password");
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
Settings::Settings()
|
|
|
|
|
: m_settings(QStringLiteral("inflo.ws"), QStringLiteral("photogallery-uploader"))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::baseUrl() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value(QStringLiteral("baseUrl")).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setBaseUrl(const QString &value)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue(QStringLiteral("baseUrl"), normalizeBaseUrl(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::username() const
|
|
|
|
|
{
|
|
|
|
|
return m_settings.value(QStringLiteral("username")).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setUsername(const QString &value)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue(QStringLiteral("username"), value.trimmed());
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-26 10:17:13 +02:00
|
|
|
int Settings::concurrency() const
|
|
|
|
|
{
|
|
|
|
|
const int v = m_settings.value(QStringLiteral("concurrency"), kDefaultConcurrency).toInt();
|
|
|
|
|
return std::clamp(v, 1, kMaxConcurrency);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setConcurrency(int value)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue(QStringLiteral("concurrency"), std::clamp(value, 1, kMaxConcurrency));
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-26 00:28:35 +02:00
|
|
|
QString Settings::readPassword() const
|
|
|
|
|
{
|
|
|
|
|
QKeychain::ReadPasswordJob job(kService);
|
|
|
|
|
job.setAutoDelete(false);
|
|
|
|
|
job.setKey(kPasswordKey);
|
|
|
|
|
|
|
|
|
|
QEventLoop loop;
|
|
|
|
|
QObject::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
|
|
|
|
job.start();
|
|
|
|
|
loop.exec();
|
|
|
|
|
|
|
|
|
|
if (job.error() != QKeychain::NoError)
|
|
|
|
|
return QString();
|
|
|
|
|
return job.textData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::writePassword(const QString &value) const
|
|
|
|
|
{
|
|
|
|
|
QKeychain::WritePasswordJob job(kService);
|
|
|
|
|
job.setAutoDelete(false);
|
|
|
|
|
job.setKey(kPasswordKey);
|
|
|
|
|
job.setTextData(value);
|
|
|
|
|
|
|
|
|
|
QEventLoop loop;
|
|
|
|
|
QObject::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
|
|
|
|
job.start();
|
|
|
|
|
loop.exec();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Settings::isConfigured() const
|
|
|
|
|
{
|
|
|
|
|
return !baseUrl().isEmpty() && !username().isEmpty() && !readPassword().isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Settings::LastPost Settings::lastPost() const
|
|
|
|
|
{
|
|
|
|
|
LastPost p;
|
|
|
|
|
p.slug = m_settings.value(QStringLiteral("last/slug")).toString();
|
|
|
|
|
p.url = m_settings.value(QStringLiteral("last/url")).toString();
|
|
|
|
|
p.caption = m_settings.value(QStringLiteral("last/caption")).toString();
|
|
|
|
|
p.postedAt = m_settings.value(QStringLiteral("last/postedAt")).toDateTime();
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Settings::setLastPost(const LastPost &value)
|
|
|
|
|
{
|
|
|
|
|
m_settings.setValue(QStringLiteral("last/slug"), value.slug);
|
|
|
|
|
m_settings.setValue(QStringLiteral("last/url"), value.url);
|
|
|
|
|
m_settings.setValue(QStringLiteral("last/caption"), value.caption);
|
|
|
|
|
m_settings.setValue(QStringLiteral("last/postedAt"), value.postedAt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::validateBaseUrl(const QString &raw)
|
|
|
|
|
{
|
|
|
|
|
const QString trimmed = raw.trimmed();
|
|
|
|
|
if (trimmed.isEmpty())
|
|
|
|
|
return QStringLiteral("Base URL is required");
|
|
|
|
|
const QUrl url(trimmed);
|
|
|
|
|
if (!url.isValid() || url.host().isEmpty())
|
|
|
|
|
return QStringLiteral("Not a valid URL");
|
|
|
|
|
if (url.scheme() != QStringLiteral("https"))
|
|
|
|
|
return QStringLiteral("Must be https — plain http sends your password in the clear");
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Settings::normalizeBaseUrl(const QString &raw)
|
|
|
|
|
{
|
|
|
|
|
QString v = raw.trimmed();
|
|
|
|
|
while (v.endsWith(QLatin1Char('/')))
|
|
|
|
|
v.chop(1);
|
|
|
|
|
if (v.endsWith(QStringLiteral("/upload"), Qt::CaseInsensitive))
|
|
|
|
|
v.chop(QStringLiteral("/upload").size());
|
|
|
|
|
while (v.endsWith(QLatin1Char('/')))
|
|
|
|
|
v.chop(1);
|
|
|
|
|
return v;
|
|
|
|
|
}
|