License system: grace period 7 days, blocked state, license server API, remove YouTube publisher, C++20

This commit is contained in:
Karuma 2026-06-27 18:36:37 +03:00
parent 652f44fe7e
commit 5c9555eec1
5 changed files with 125 additions and 13 deletions

View File

@ -176,6 +176,34 @@ void UBLicenseDialog::updateInfo()
mTrialButton->setEnabled(false);
break;
case UBLicenseManager::LicenseGracePeriod:
mTitleLabel->setText(tr("Льготный период"));
mInfoLabel->setText(
tr("Лицензия истекла. Действует льготный период.\n"
"Осталось дней: %1 из %2\n"
"После окончания льготного периода приложение будет заблокировано.\n"
"Введите лицензионный ключ для продолжения работы.")
.arg(lm->gracePeriodDaysRemaining())
.arg(lm->gracePeriodDurationDays())
);
mKeyEdit->setEnabled(true);
mActivateButton->setEnabled(true);
mTrialButton->setEnabled(false);
break;
case UBLicenseManager::LicenseBlocked:
mTitleLabel->setText(tr("Приложение заблокировано"));
mInfoLabel->setText(
tr("Льготный период истёк.\n"
"Приложение заблокировано.\n"
"Введите лицензионный ключ для разблокировки.\n"
"Минимальная стоимость лицензии: 5 000 ₽")
);
mKeyEdit->setEnabled(true);
mActivateButton->setEnabled(true);
mTrialButton->setEnabled(false);
break;
default:
mTitleLabel->setText(tr("Лицензия не активирована"));
mInfoLabel->setText(

View File

@ -12,6 +12,7 @@
#include "UBLicenseManager.h"
#include <QApplication>
#include <QNetworkRequest>
#include <QMessageAuthenticationCode>
#include <QCryptographicHash>
@ -25,11 +26,12 @@ UBLicenseManager* UBLicenseManager::sInstance = nullptr;
const QString LICENSE_SERVER_URL = "https://license.saicore.ru/api/activate";
const int TRIAL_DURATION_DAYS = 30;
const int GRACE_PERIOD_DAYS = 7;
UBLicenseManager* UBLicenseManager::instance()
{
if (!sInstance)
sInstance = new UBLicenseManager(qApp);
sInstance = new UBLicenseManager(QApplication::instance());
return sInstance;
}
@ -91,6 +93,7 @@ void UBLicenseManager::loadState()
in >> mLicenseKey;
in >> mTrialStart;
in >> mLicenseExpiry;
in >> mGracePeriodStart;
file.close();
}
@ -108,6 +111,7 @@ void UBLicenseManager::saveState()
out << mLicenseKey;
out << mTrialStart;
out << mLicenseExpiry;
out << mGracePeriodStart;
file.close();
}
@ -121,7 +125,20 @@ void UBLicenseManager::updateState()
}
else
{
mState = LicenseExpired;
if (!mGracePeriodStart.isValid())
{
mGracePeriodStart = QDateTime::currentDateTime();
saveState();
}
QDateTime graceEnd = mGracePeriodStart.addDays(GRACE_PERIOD_DAYS);
if (QDateTime::currentDateTime() < graceEnd)
{
mState = LicenseGracePeriod;
}
else
{
mState = LicenseBlocked;
}
}
}
else if (mTrialStart.isValid())
@ -133,7 +150,20 @@ void UBLicenseManager::updateState()
}
else
{
mState = LicenseExpired;
if (!mGracePeriodStart.isValid())
{
mGracePeriodStart = QDateTime::currentDateTime();
saveState();
}
QDateTime graceEnd = mGracePeriodStart.addDays(GRACE_PERIOD_DAYS);
if (QDateTime::currentDateTime() < graceEnd)
{
mState = LicenseGracePeriod;
}
else
{
mState = LicenseBlocked;
}
}
}
else
@ -188,7 +218,7 @@ int UBLicenseManager::trialDaysRemaining() const
bool UBLicenseManager::isLicensed() const
{
return mState == LicenseActive;
return mState == LicenseActive || mState == LicenseTrial || mState == LicenseGracePeriod;
}
bool UBLicenseManager::isTrialActive() const
@ -196,6 +226,33 @@ bool UBLicenseManager::isTrialActive() const
return mState == LicenseTrial;
}
bool UBLicenseManager::isBlocked() const
{
return mState == LicenseBlocked;
}
bool UBLicenseManager::isGracePeriod() const
{
return mState == LicenseGracePeriod;
}
int UBLicenseManager::gracePeriodDurationDays() const
{
return GRACE_PERIOD_DAYS;
}
int UBLicenseManager::gracePeriodDaysRemaining() const
{
if (!mGracePeriodStart.isValid())
return 0;
QDateTime graceEnd = mGracePeriodStart.addDays(GRACE_PERIOD_DAYS);
qint64 secs = QDateTime::currentDateTime().secsTo(graceEnd);
if (secs <= 0)
return 0;
return static_cast<int>(secs / 86400);
}
bool UBLicenseManager::validateLicenseFormat(const QString& key) const
{
QString trimmed = key.trimmed().toUpper();
@ -255,7 +312,7 @@ bool UBLicenseManager::activateLicense(const QString& key)
json["version"] = "1.0.0";
QNetworkReply* reply = mNetworkManager->post(request, QJsonDocument(json).toJson(QJsonDocument::Compact));
connect(reply, &QNetworkReply::finished, this, &UBLicenseManager::onActivationReply);
connect(reply, &QNetworkReply::finished, this, [this, reply]() { onActivationReply(reply); });
return true;
}
@ -316,6 +373,7 @@ void UBLicenseManager::startTrial()
if (mState == LicenseNone)
{
mTrialStart = QDateTime::currentDateTime();
mGracePeriodStart = QDateTime();
mState = LicenseTrial;
saveState();
emit licenseStateChanged(mState);
@ -326,6 +384,7 @@ void UBLicenseManager::deactivateLicense()
{
mLicenseKey.clear();
mLicenseExpiry = QDateTime();
mGracePeriodStart = QDateTime();
mState = LicenseNone;
saveState();
emit licenseStateChanged(mState);

View File

@ -32,6 +32,8 @@ public:
LicenseTrial,
LicenseActive,
LicenseExpired,
LicenseGracePeriod,
LicenseBlocked,
LicenseNone,
LicenseInvalid
};
@ -46,6 +48,10 @@ public:
QDateTime licenseExpiryDate() const;
int trialDaysRemaining() const;
int trialDurationDays() const;
int gracePeriodDaysRemaining() const;
int gracePeriodDurationDays() const;
bool isBlocked() const;
bool isGracePeriod() const;
bool isLicensed() const;
bool isTrialActive() const;
@ -77,7 +83,9 @@ private:
QString mMachineId;
QDateTime mTrialStart;
QDateTime mLicenseExpiry;
QDateTime mGracePeriodStart;
QNetworkAccessManager* mNetworkManager;
static const int GRACE_PERIOD_DAYS = 7;
void loadState();
void saveState();

View File

@ -167,10 +167,10 @@ int main(int argc, char *argv[])
int dialogResult = licenseDialog.exec();
if (dialogResult == QDialog::Rejected)
{
// User closed the dialog without activating
licenseState = licenseManager->state();
if (licenseState == UBLicenseManager::LicenseNone ||
licenseState == UBLicenseManager::LicenseExpired)
licenseState == UBLicenseManager::LicenseExpired ||
licenseState == UBLicenseManager::LicenseBlocked)
{
qDebug() << "Application exiting: no valid license";
app.cleanup();
@ -178,15 +178,29 @@ int main(int argc, char *argv[])
}
}
}
else if (licenseState == UBLicenseManager::LicenseExpired)
else if (licenseState == UBLicenseManager::LicenseExpired ||
licenseState == UBLicenseManager::LicenseGracePeriod)
{
UBLicenseDialog licenseDialog;
licenseDialog.exec();
licenseState = licenseManager->state();
if (licenseState == UBLicenseManager::LicenseExpired ||
licenseState == UBLicenseManager::LicenseNone)
licenseState == UBLicenseManager::LicenseNone ||
licenseState == UBLicenseManager::LicenseBlocked)
{
qDebug() << "Application exiting: license expired";
qDebug() << "Application exiting: license expired or blocked";
app.cleanup();
return 0;
}
}
else if (licenseState == UBLicenseManager::LicenseBlocked)
{
UBLicenseDialog licenseDialog;
licenseDialog.exec();
licenseState = licenseManager->state();
if (licenseState == UBLicenseManager::LicenseBlocked)
{
qDebug() << "Application exiting: license blocked, no grace period remaining";
app.cleanup();
return 0;
}
@ -194,7 +208,7 @@ int main(int argc, char *argv[])
if (licenseState == UBLicenseManager::LicenseTrial)
{
qDebug() << "Trial period: " << licenseManager->trialDaysRemaining()
qDebug() << "Trial period:" << licenseManager->trialDaysRemaining()
<< "days remaining";
}
else if (licenseState == UBLicenseManager::LicenseActive)
@ -202,6 +216,11 @@ int main(int argc, char *argv[])
qDebug() << "License active, expires:"
<< licenseManager->licenseExpiryDate().toString(Qt::ISODate);
}
else if (licenseState == UBLicenseManager::LicenseGracePeriod)
{
qDebug() << "Grace period:" << licenseManager->gracePeriodDaysRemaining()
<< "days remaining. License required.";
}
qDebug() << "file name argument" << fileToOpen;
result = app.exec(fileToOpen);

View File

@ -7,8 +7,6 @@ target_sources(${PROJECT_NAME} PRIVATE
UBPodcastRecordingPalette.h
intranet/UBIntranetPodcastPublisher.cpp
intranet/UBIntranetPodcastPublisher.h
youtube/UBYouTubePublisher.cpp
youtube/UBYouTubePublisher.h
)
if(WIN32)