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.
216 lines
7.5 KiB
C++
216 lines
7.5 KiB
C++
#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> ¶ms) {
|
||
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;
|
||
}
|