mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-18 08:55:41 +03:00
* refactor: move business logic from servers model * refactor: move containersModel initialization * refactor: added protocol ui controller and removed settings class from protocols model * refactor: moved cli management to separate controller * refactor: moved app split to separate controller * refactor: moved site split to separate controller * refactor: moved allowed dns to separate controller * refactor: moved language logic to separate ui controller * refactor: removed Settings from devices model * refactor: moved configs and services api logit to separate core controller * refactor: added a layer with a repository between the storage and controllers * refactor: use child parent system instead of smart pointers for controllers and models initialization * refactor: moved install functions from server controller to install controller * refactor: install controller refactoring * chore: renamed exportController to exportUiController * refactor: separate export controller * refactor: removed VpnConfigurationsController * chore: renamed ServerController to SshSession * refactor: replaced ServerController to SshSession * chore: moved qml controllers to separate folder * chore: include fixes * chore: moved utils from core root to core/utils * chore: include fixes * chore: rename core/utils files to camelCase foramt * chore: include fixes * chore: moved some utils to api and selfhosted folders * chore: include fixes * chore: remove unused file * chore: moved serialization folder to core/utils * chore: include fixes * chore: moved some files from client root to core/utils * chore: include fixes * chore: moved ui utils to ui/utils folder * chore: include fixes * chore: move utils from root to ui/utils * chore: include fixes * chore: moved configurators to core/configurators * chore: include fixes * refactor: moved iap logic from ui controller to core * refactor: moved remaining core logic from ApiConfigsController to SubscriptionController * chore: rename apiNewsController to apiNewsUiController * refactor: moved core logic from news ui controller to core * chore: renamed apiConfigsController to subscriptionUiController * chore: include fixes * refactor: merge ApiSettingsController with SubscriptionUiController * chore: moved ui selfhosted controllers to separate folder * chore: include fixes * chore: rename connectionController to connectiomUiController * refactor: moved core logic from connectionUiController * chore: rename settingsController to settingsUiController * refactor: move core logic from settingsUiController * refactor: moved core controller signal/slot connections to separate class * fix: newsController fixes after refactoring * chore: rename model to camelCase * chore: include fixes * chore: remove unused code * chore: move selfhosted core to separate folder * chore: include fixes * chore: rename importController to importUiController * refactor: move core logic from importUiController * chore: minor fixes * chore: remove prem v1 migration * refactor: remove openvpn over cloak and openvpn over shadowsocks * refactor: removed protocolsForContainer function * refactor: add core models * refactor: replace json with c++ structs for server config * refactor: move getDnsPair to ServerConfigUtils * feat: add admin selfhosted config export test * feat: add multi import test * refactor: use coreController for tests * feat: add few simple tests * chore: qrepos in all core controllers * feat: add test for settings * refactor: remove repo dependency from configurators * chore: moved protocols to core folder * chore: include fixes * refactor: moved containersDefs, defs, apiDefs, protocolsDefs to different places * chore: include fixes * chore: build fixes * chore: build fixes * refactor: remove q repo and interface repo * feat: add test for ui servers model and controller * chore: renamed to camelCase * chore: include fixes * refactor: moved core logic from sites ui controller * fix: fixed api config processing * fix: fixed processed server index processing * refactor: protocol models now use c++ structs instead of json configs * refactor: servers model now use c++ struct instead of json config * fix: fixed default server index processing * fix: fix logs init * fix: fix secure settings load keys * chore: build fixes * fix: fixed clear settings * fix: fixed restore backup * fix: sshSession usage * fix: fixed export functions signatures * fix: return missing part from buildContainerWorker * fix: fixed server description on page home * refactor: add container config helpers functions * refactor: c++ structs instead of json * chore: add dns protocol config struct * refactor: move config utils functions to config structs * feat: add test for selfhosted server setup * refactor: separate resources.qrc * fix: fixed server rename * chore: return nameOverriddenByUser * fix: build fixes * fix: fixed models init * refactor: cleanup models usage * fix: fixed models init * chore: cleanup connections and functions signatures * chore: cleanup updateModel calls * feat: added cache to servers repo * chore: cleanup unused functions * chore: ssxray processing * chore: remove transportProtoWithDefault and portWithDefault functions * chore: removed proto types any and l2tp * refactor: moved some constants * fix: fixed native configs export * refactor: remove json from processConfigWith functions * fix: fixed processed server index usage * fix: qml warning fixes * chore: merge fixes * chore: update tests * fix: fixed xray config processing * fix: fixed split tunneling processing * chore: rename sites controllers and model * chore: rename fixes * chore: minor fixes * chore: remove ability to load backup from "file with connection settings" button * fix: fixed api device revoke * fix: remove full model update when renaming a user * fix: fixed premium/free server rename * fix: fixed selfhosted new server install * fix: fixed updateContainer function * fix: fixed revoke for external premium configs * feat: add native configs qr processing * chore: codestyle fixes * fix: fixed admin config create * chore: again remove ability to load backup from "file with connection settings" button * chore: minor fixes * fix: fixed variables initialization * fix: fixed qml imports * fix: minor fixes * fix: fix vpnConnection function calls * feat: add buckup error handling * fix: fixed admin config revok * fix: fixed selfhosted awg installation * fix: ad visability * feat: add empty check for primary dns * chore: minor fixes
297 lines
9.2 KiB
C++
297 lines
9.2 KiB
C++
#include "apiServicesModel.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QHash>
|
|
#include <QJsonArray>
|
|
#include <QJsonObject>
|
|
|
|
#include "core/utils/constants/apiKeys.h"
|
|
#include "logger.h"
|
|
|
|
namespace
|
|
{
|
|
Logger logger("ApiServicesModel");
|
|
|
|
namespace configKey
|
|
{
|
|
constexpr char userCountryCode[] = "user_country_code";
|
|
constexpr char services[] = "services";
|
|
constexpr char serviceInfo[] = "service_info";
|
|
constexpr char serviceType[] = "service_type";
|
|
constexpr char serviceProtocol[] = "service_protocol";
|
|
constexpr char serviceDescription[] = "service_description";
|
|
|
|
constexpr char description[] = "description";
|
|
constexpr char cardDescription[] = "card_description";
|
|
constexpr char serviceName[] = "service_name";
|
|
|
|
constexpr char availableCountries[] = "available_countries";
|
|
|
|
constexpr char storeEndpoint[] = "store_endpoint";
|
|
|
|
constexpr char isAvailable[] = "is_available";
|
|
|
|
constexpr char subscriptionPlans[] = "subscription_plans";
|
|
constexpr char minPriceLabel[] = "min_price_label";
|
|
constexpr char benefits[] = "benefits";
|
|
}
|
|
|
|
namespace serviceType
|
|
{
|
|
constexpr char amneziaFree[] = "amnezia-free";
|
|
constexpr char amneziaPremium[] = "amnezia-premium";
|
|
}
|
|
}
|
|
|
|
ApiServicesModel::ApiServicesModel(QObject *parent)
|
|
: QAbstractListModel(parent)
|
|
, m_selectedServiceIndex(0)
|
|
{
|
|
}
|
|
|
|
int ApiServicesModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
Q_UNUSED(parent)
|
|
return m_services.size();
|
|
}
|
|
|
|
QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
|
|
return QVariant();
|
|
|
|
auto apiServiceData = m_services.at(index.row());
|
|
auto serviceType = apiServiceData.type;
|
|
auto isServiceAvailable = apiServiceData.isServiceAvailable;
|
|
|
|
switch (role) {
|
|
case NameRole: {
|
|
return apiServiceData.serviceInfo.name;
|
|
}
|
|
case CardDescriptionRole: {
|
|
if (serviceType == serviceType::amneziaPremium) {
|
|
return apiServiceData.serviceInfo.cardDescription;
|
|
} else if (serviceType == serviceType::amneziaFree) {
|
|
QString description = apiServiceData.serviceInfo.cardDescription;
|
|
if (!isServiceAvailable) {
|
|
description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, "
|
|
"return to the previous screen, and try again.</a>");
|
|
}
|
|
return description;
|
|
}
|
|
}
|
|
case ServiceDescriptionRole: {
|
|
return apiServiceData.serviceInfo.description;
|
|
}
|
|
case IsServiceAvailableRole: {
|
|
if (serviceType == serviceType::amneziaFree) {
|
|
if (!isServiceAvailable) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
case IsPremiumRole: {
|
|
return serviceType == serviceType::amneziaPremium;
|
|
}
|
|
case HasSubscriptionPlansRole: {
|
|
return !apiServiceData.subscriptionPlansJson.isEmpty();
|
|
}
|
|
case PriceRole: {
|
|
return apiServiceData.minPriceLabel;
|
|
}
|
|
case EndDateRole: {
|
|
return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
|
|
}
|
|
case TermsOfUseUrlRole: {
|
|
return apiServiceData.serviceInfo.termsOfUseUrl;
|
|
}
|
|
case PrivacyPolicyUrlRole: {
|
|
return apiServiceData.serviceInfo.privacyPolicyUrl;
|
|
}
|
|
case ShowRecommendedRole: {
|
|
return serviceType == serviceType::amneziaPremium;
|
|
}
|
|
case OrderRole: {
|
|
if (serviceType == serviceType::amneziaPremium) {
|
|
return 0;
|
|
}
|
|
if (serviceType == serviceType::amneziaFree) {
|
|
return 1;
|
|
}
|
|
return QVariant();
|
|
}
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
void ApiServicesModel::updateModel(const QJsonObject &data)
|
|
{
|
|
beginResetModel();
|
|
|
|
m_services.clear();
|
|
|
|
m_countryCode = data.value(configKey::userCountryCode).toString();
|
|
auto services = data.value(configKey::services).toArray();
|
|
|
|
if (services.isEmpty()) {
|
|
m_services.push_back(getApiServicesData(data));
|
|
m_selectedServiceIndex = 0;
|
|
} else {
|
|
for (const auto &service : services) {
|
|
auto serviceObject = service.toObject();
|
|
m_services.push_back(getApiServicesData(serviceObject));
|
|
}
|
|
}
|
|
|
|
if (!m_services.isEmpty() && m_selectedServiceIndex >= m_services.size()) {
|
|
m_selectedServiceIndex = 0;
|
|
}
|
|
|
|
endResetModel();
|
|
|
|
emit serviceSelectionChanged();
|
|
}
|
|
|
|
void ApiServicesModel::setServiceIndex(const int index)
|
|
{
|
|
m_selectedServiceIndex = index;
|
|
emit serviceSelectionChanged();
|
|
}
|
|
|
|
ApiServicesModel::ApiServicesData ApiServicesModel::selectedServiceData() const
|
|
{
|
|
if (m_services.isEmpty() || m_selectedServiceIndex < 0 || m_selectedServiceIndex >= m_services.size()) {
|
|
return {};
|
|
}
|
|
return m_services.at(m_selectedServiceIndex);
|
|
}
|
|
|
|
QJsonObject ApiServicesModel::getSelectedServiceInfo()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.serviceInfo.object;
|
|
}
|
|
|
|
QString ApiServicesModel::getSelectedServiceType()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.type;
|
|
}
|
|
|
|
QString ApiServicesModel::getSelectedServiceProtocol()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.protocol;
|
|
}
|
|
|
|
QString ApiServicesModel::getSelectedServiceName()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.serviceInfo.name;
|
|
}
|
|
|
|
QJsonArray ApiServicesModel::getSelectedServiceCountries()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.availableCountries;
|
|
}
|
|
|
|
QString ApiServicesModel::getCountryCode()
|
|
{
|
|
return m_countryCode;
|
|
}
|
|
|
|
QString ApiServicesModel::getStoreEndpoint()
|
|
{
|
|
auto service = m_services.at(m_selectedServiceIndex);
|
|
return service.storeEndpoint;
|
|
}
|
|
|
|
QVariant ApiServicesModel::getSelectedServiceData(const QString roleString)
|
|
{
|
|
QModelIndex modelIndex = index(m_selectedServiceIndex);
|
|
auto roles = roleNames();
|
|
for (auto it = roles.begin(); it != roles.end(); it++) {
|
|
if (QString(it.value()) == roleString) {
|
|
return data(modelIndex, it.key());
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
int ApiServicesModel::serviceIndexForType(const QString &type) const
|
|
{
|
|
for (int serviceIndex = 0; serviceIndex < m_services.size(); ++serviceIndex) {
|
|
if (m_services.at(serviceIndex).type == type) {
|
|
return serviceIndex;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
|
{
|
|
QHash<int, QByteArray> roles;
|
|
roles[NameRole] = "name";
|
|
roles[CardDescriptionRole] = "cardDescription";
|
|
roles[ServiceDescriptionRole] = "serviceDescription";
|
|
roles[IsServiceAvailableRole] = "isServiceAvailable";
|
|
roles[IsPremiumRole] = "isPremium";
|
|
roles[HasSubscriptionPlansRole] = "hasSubscriptionPlans";
|
|
roles[PriceRole] = "price";
|
|
roles[EndDateRole] = "endDate";
|
|
roles[TermsOfUseUrlRole] = "termsOfUseUrl";
|
|
roles[PrivacyPolicyUrlRole] = "privacyPolicyUrl";
|
|
roles[ShowRecommendedRole] = "showRecommended";
|
|
roles[OrderRole] = "order";
|
|
|
|
return roles;
|
|
}
|
|
|
|
ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJsonObject &data)
|
|
{
|
|
auto serviceInfo = data.value(configKey::serviceInfo).toObject();
|
|
auto serviceType = data.value(configKey::serviceType).toString();
|
|
auto serviceProtocol = data.value(configKey::serviceProtocol).toString();
|
|
auto availableCountries = data.value(configKey::availableCountries).toArray();
|
|
auto serviceDescription = data.value(configKey::serviceDescription).toObject();
|
|
|
|
auto subscriptionObject = data.value(apiDefs::key::subscription).toObject();
|
|
|
|
ApiServicesData serviceData;
|
|
serviceData.serviceInfo.name = serviceDescription.value(configKey::serviceName).toString();
|
|
|
|
serviceData.serviceInfo.cardDescription = serviceDescription.value(configKey::cardDescription).toString();
|
|
serviceData.serviceInfo.description = serviceDescription.value(configKey::description).toString();
|
|
serviceData.serviceInfo.termsOfUseUrl = serviceDescription.value(apiDefs::key::termsOfUseUrl).toString();
|
|
serviceData.serviceInfo.privacyPolicyUrl = serviceDescription.value(apiDefs::key::privacyPolicyUrl).toString();
|
|
|
|
serviceData.subscriptionPlansJson = serviceDescription.value(configKey::subscriptionPlans).toArray();
|
|
serviceData.benefits = serviceDescription.value(configKey::benefits).toArray();
|
|
|
|
serviceData.minPriceLabel = serviceDescription.value(configKey::minPriceLabel).toString().trimmed();
|
|
|
|
serviceData.supportInfo = data.value(apiDefs::key::supportInfo).toObject();
|
|
|
|
serviceData.type = serviceType;
|
|
serviceData.protocol = serviceProtocol;
|
|
|
|
serviceData.storeEndpoint = data.value(configKey::storeEndpoint).toString();
|
|
|
|
if (data.value(configKey::isAvailable).isBool()) {
|
|
serviceData.isServiceAvailable = data.value(configKey::isAvailable).toBool();
|
|
} else {
|
|
serviceData.isServiceAvailable = true;
|
|
}
|
|
|
|
serviceData.serviceInfo.object = serviceInfo;
|
|
serviceData.availableCountries = availableCountries;
|
|
|
|
serviceData.subscription.endDate = subscriptionObject.value(apiDefs::key::endDate).toString();
|
|
|
|
return serviceData;
|
|
}
|