1
0
forked from BRT/arc
arc/services/net/NetworkService.cpp
slava 27ce69d094 Refactor account handling and add TutorialWindow feature
Removed redundant "numbers" field from Account model and database queries to simplify account structure. Introduced a TutorialWindow class for displaying application tutorials, integrated into the main window, and updated file paths accordingly. Improved string handling and logic in Payment routines and enhanced overall UI structure.
2025-05-23 19:25:02 +07:00

216 lines
7.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "NetworkService.h"
#include <QUrlQuery>
#include <QHttpPart>
#include <QNetworkReply>
#include <QJsonObject>
#include <QJsonArray>
#include <QThread>
#include <QSettings>
#include <QTimer>
#include <QTimeZone>
#include "dao/AccountDAO.h"
#include "dao/EventDAO.h"
#include "dao/TransactionDAO.h"
#include "db/EventInfo.h"
NetworkService::NetworkService(QObject *parent) : QObject(parent) {
const QSettings settings("config.ini", QSettings::IniFormat);
m_urlAccountUpdate = settings.value("net/accountUpdate").toString();
m_urlPaymentsGet = settings.value("net/paymentsGet").toString();
m_urlTransactionUpdate = settings.value("net/transactionUpdate").toString();
m_urlTransactionInsert = settings.value("net/transactionInsert").toString();
m_manager = new QNetworkAccessManager(this);
}
NetworkService::~NetworkService() = default;
// FIXME доделать работу с экстра
void NetworkService::addExtra(const QString &key, const QVariant &value) {
m_extraData[key] = value;
}
void addFormField(QHttpMultiPart *multiPart, const QString &fieldName, const QString &fieldValue) {
QHttpPart formField;
formField.setHeader(
QNetworkRequest::ContentDispositionHeader,QStringLiteral("form-data; name=\"%1\"").arg(fieldName)
);
formField.setBody(fieldValue.toUtf8());
multiPart->append(formField);
}
void addFormMetadata(QHttpMultiPart *multiPart, const QByteArray &fieldValue) {
QHttpPart jsonPart;
jsonPart.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="metadata")");
jsonPart.setBody(fieldValue);
multiPart->append(jsonPart);
}
QJsonValue NetworkService::post(QHttpMultiPart *multiPart, const QString &path) {
const QUrl url(path);
const QNetworkRequest request(url);
QNetworkReply *reply = m_manager->post(request, multiPart);
multiPart->setParent(reply);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::errorOccurred, [&loop](QNetworkReply::NetworkError) {
loop.quit();
});
loop.exec(); // <- здесь и запускается event-loop потока
QJsonValue result;
if (reply->error() == QNetworkReply::NoError) {
const QByteArray raw = reply->readAll();
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
if (err.error == QJsonParseError::NoError && doc.isObject()) {
const QJsonObject root = doc.object();
if (root.value("success").toBool()) {
result = root.value("data");
} else {
qCritical() << "Ошибка:" << root;
}
}
} else {
qCritical() << "Ошибка:" << reply->errorString() << path;
}
reply->deleteLater();
return result;
}
QJsonArray NetworkService::get(const QString &path, const QMap<QString, QString> &params) {
QUrl url(path);
QUrlQuery query;
for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
query.addQueryItem(it.key(), it.value());
}
url.setQuery(query);
const QNetworkRequest request(url);
QNetworkReply *reply = m_manager->get(request);
QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> guard(reply);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::errorOccurred, [&loop](QNetworkReply::NetworkError) {
loop.quit();
});
loop.exec(); // <- здесь и запускается event-loop потока
QJsonArray result;
if (reply->error() == QNetworkReply::NoError) {
const QByteArray raw = reply->readAll();
QJsonParseError err;
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
if (err.error == QJsonParseError::NoError && doc.isObject()) {
const QJsonObject root = doc.object();
if (root.value("success").toBool()) {
result = root.value("data").toArray();
} else {
qWarning() << "Ошибка:" << root;
}
}
} else {
qWarning() << "Ошибка:" << reply->errorString();
}
reply->deleteLater();
return result;
}
void NetworkService::postAccountsData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
const bool isSuccess = post(multiPart, m_urlAccountUpdate).toBool();
if (!isSuccess) {
qCritical() << "Cant post accounts data";
}
emit finished();
}
void NetworkService::getPayments() {
QMap<QString, QString> params;
params["desktopUniqueName"] = m_desktopId;
const QJsonArray data = get(m_urlPaymentsGet, params);
for (QJsonValue item: data) {
QJsonObject obj = item.toObject();
EventInfo eventInfo;
eventInfo.status = EventStatus::Wait;
eventInfo.externalId = obj["id"].toInt();
eventInfo.timestamp = QDateTime::fromMSecsSinceEpoch(obj["timestamp"].toDouble(), QTimeZone::utc());
eventInfo.amount = obj["amount"].toDouble();
eventInfo.bankName = obj["bankName"].toString();
eventInfo.phone = obj["phone"].toString();
QString deviceId = obj["deviceId"].toString();
QString appName = obj["appName"].toString();
QString lastNumbers = obj["lastNumbers"].toString();
AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumbers);
eventInfo.accountId = account.id;
eventInfo.deviceId = account.deviceId;
if (int id = EventDAO::insertEvent(eventInfo); id == -1) {
qCritical() << "Cant insert event: " << eventInfo.externalId;
}
}
if (!m_running) {
emit finished();
}
}
void NetworkService::updateTransactionData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
const bool isSuccess = post(multiPart, m_urlTransactionUpdate).toBool();
if (!isSuccess) {
qCritical() << "Cant update transaction: updateTransactionData";
}
emit finished();
}
void NetworkService::insertTransactionData() {
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
addFormMetadata(multiPart, m_json);
addFormField(multiPart, "desktopUniqueName", m_desktopId);
addFormField(multiPart, "androidUniqueName", m_deviceId);
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
const int id = post(multiPart, m_urlTransactionInsert).toInt();
if (id > 0) {
const int transactionId = m_extraData["transactionId"].toInt();
if (!TransactionDAO::updateExternalTransactionId(transactionId, id)) {
qCritical() << "Cant update transaction id: " << id;
}
}
emit finished();
}
void NetworkService::start() {
QTimer *poller = new QTimer(this);
poller->setInterval(1000);
connect(poller, &QTimer::timeout, this, &NetworkService::getPayments);
poller->start();
}
void NetworkService::stop() {
m_running = false;
}