Added handling for event types (Balance, Phone) and respective processing logic in EventHandler. Introduced support for tracking and updating event statuses both locally and through network APIs. Enhanced data integrity and clarity by expanding the EventInfo model and associated database management.
293 lines
11 KiB
C++
293 lines
11 KiB
C++
#include "CommonScript.h"
|
||
|
||
#include <QJsonArray>
|
||
#include <QJsonObject>
|
||
#include <QRandomGenerator>
|
||
#include <QThread>
|
||
|
||
#include "adb/AdbUtils.h"
|
||
#include "net/NetworkService.h"
|
||
|
||
CommonScript::CommonScript(QObject *parent)
|
||
: QObject(parent) {
|
||
}
|
||
|
||
CommonScript::~CommonScript() = default;
|
||
|
||
void CommonScript::start() {
|
||
doStart();
|
||
emit finished();
|
||
}
|
||
|
||
Node CommonScript::swipeToButton(
|
||
const QString &deviceId,
|
||
const QString &text, int &counter, const int width, const int height
|
||
) {
|
||
for (int i = 0; i < 10; ++i) {
|
||
if (Node button = xmlScreenParser.findButtonNode(text, true); button.x() > 0 && button.y() > 0) {
|
||
return button;
|
||
}
|
||
const int x = width / 2;
|
||
const int offset = height / 4;
|
||
AdbUtils::makeSwipe(deviceId, x, height - offset, x, offset);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
|
||
}
|
||
return {};
|
||
}
|
||
|
||
bool CommonScript::inputPinCode(const QString &deviceId, const QList<Node> &pincode) {
|
||
for (const Node &node: pincode) {
|
||
const bool completePincode = AdbUtils::makeTap(deviceId, node.x(), node.y());
|
||
if (!completePincode) {
|
||
AdbUtils::makeTap(deviceId, node.x(), node.y());
|
||
}
|
||
QThread::msleep(QRandomGenerator::global()->bounded(100, 901));
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool CommonScript::runAppAndGoToHomeScreen(
|
||
const QString &deviceId,
|
||
const QString &packageName,
|
||
const QString &pinCode,
|
||
const int width,
|
||
const int height
|
||
) {
|
||
// Запустить устройство
|
||
if (const QString pid = AdbUtils::tryToGetRunningAppPid(deviceId, packageName); !pid.isEmpty()) {
|
||
qDebug() << "Process already running, pid: " << pid;
|
||
AdbUtils::getScreenDumpAsXml(deviceId, 1000);
|
||
AdbUtils::tryToKillApplication(deviceId, packageName);
|
||
}
|
||
if (!AdbUtils::tryToStartApplication(deviceId, packageName)) {
|
||
AdbUtils::takeScreenshot(deviceId, "run_app_error");
|
||
qWarning() << "Process has not started";
|
||
return false;
|
||
}
|
||
|
||
// Даем минимальное время на запуск
|
||
QThread::msleep(4500);
|
||
int counter = 0;
|
||
bool findAndInputPincode = false;
|
||
|
||
while (true) {
|
||
counter++;
|
||
|
||
// Если более 10 раз мы пытаемся перейти на домашнюю
|
||
if (counter > 10) {
|
||
AdbUtils::takeScreenshot(deviceId, "too_many_attempts");
|
||
return false;
|
||
}
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
|
||
if (xmlScreenParser.isHomeScreen()) {
|
||
return true;
|
||
}
|
||
|
||
// Проверяем на банеры после пин-кодом
|
||
Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(width, height);
|
||
if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) {
|
||
AdbUtils::makeTap(deviceId, closeBannerOrDialogNode.x(), closeBannerOrDialogNode.y());
|
||
QThread::msleep(1000);
|
||
continue;
|
||
}
|
||
|
||
// Проверяем на банеры перед пин-кодом
|
||
Node closeBannerNode = xmlScreenParser.tryToFindSecurityBanner();
|
||
if (!closeBannerNode.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, closeBannerNode.x(), closeBannerNode.y());
|
||
QThread::msleep(1000);
|
||
continue;
|
||
}
|
||
|
||
|
||
// Проверяем, что это экран ввода пин-кода
|
||
if (!findAndInputPincode) {
|
||
if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите ПИН");
|
||
pincode.size() == 4) {
|
||
// чтобы пробудить экран
|
||
if (Node textPinCodeNode = xmlScreenParser.findTextNode("Введите ПИН"); !textPinCodeNode.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, textPinCodeNode.x(), textPinCodeNode.y());
|
||
}
|
||
inputPinCode(deviceId, pincode);
|
||
// После ввода пин-код нужно сделать задержку, пока подгрузка идет, чтобы снова не спарсить
|
||
findAndInputPincode = true;
|
||
QThread::msleep(3000);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
QThread::msleep(1000);
|
||
}
|
||
}
|
||
|
||
bool CommonScript::tryToCloseAllBannersOnHomePage(const QString &deviceId, const int width, const int height) {
|
||
Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(width, height);
|
||
if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) {
|
||
AdbUtils::makeTap(deviceId, closeBannerOrDialogNode.x(), closeBannerOrDialogNode.y());
|
||
return true;
|
||
}
|
||
|
||
// TODO тут все другие банеры попробовать закрыть
|
||
return false;
|
||
}
|
||
|
||
bool CommonScript::goToAllProducts(
|
||
const QString &deviceId,
|
||
const int width,
|
||
const int height
|
||
) {
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, m_counter));
|
||
if (tryToCloseAllBannersOnHomePage(deviceId, width, height)) {
|
||
QThread::msleep(500);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
if (xmlScreenParser.isHomeScreen()) {
|
||
// идем на экран "Все продукты"
|
||
if (Node allCardTitle = xmlScreenParser.findTextNode("Счета и карты"); !allCardTitle.isEmpty()) {
|
||
// 1. Если нет кнопки видимой, свайпаем. Кликаем на "Все продукты"
|
||
for (int i = 0; i < 5; ++i) {
|
||
Node allProductsBtn = xmlScreenParser.findButtonNode("Все продукты", false);
|
||
if (allProductsBtn.x() > 0 && allProductsBtn.y() > 0 && allProductsBtn.y() < height - 200) {
|
||
AdbUtils::makeTap(deviceId, allProductsBtn.x(), allProductsBtn.y());
|
||
QThread::msleep(1000);
|
||
break;
|
||
}
|
||
AdbUtils::makeSwipe(deviceId,
|
||
allCardTitle.x(), allCardTitle.y(),
|
||
allCardTitle.x(), allCardTitle.y() - 200);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
for (int i = 0; i < 5; ++i) {
|
||
Node allProductsTitle = xmlScreenParser.findTextNode("Все продукты");
|
||
// Проверяем что вверху заголовок
|
||
if (!allProductsTitle.isEmpty() && allProductsTitle.y() < 300) {
|
||
return true;
|
||
}
|
||
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
} else {
|
||
// FIXME пишем в БД, что не дошли до домашней страницы, и завершаемся
|
||
// сохраняем скрин приложения
|
||
// дделаем алерт
|
||
}
|
||
} else {
|
||
// FIXME
|
||
qDebug() << "Not home screen...";
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool CommonScript::findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers) {
|
||
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
|
||
for (auto &[account, node]: accounts) {
|
||
// FIXME будем считать что числа последние везде уникальные
|
||
if (accountNumbers == account.lastNumbers) {
|
||
qDebug() << "findAndTapOnAccount: " << accountNumbers;
|
||
AdbUtils::makeTap(deviceId, node.x(), node.y());
|
||
QThread::msleep(1000);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
void CommonScript::postAccountsData(const QList<QPair<AccountInfo, Node> > &accounts) {
|
||
if (accounts.isEmpty()) {
|
||
return;
|
||
}
|
||
|
||
auto *thread = new QThread;
|
||
auto *worker = new NetworkService;
|
||
|
||
QJsonArray list;
|
||
for (const QPair<AccountInfo, Node> &pair: accounts) {
|
||
QJsonObject obj;
|
||
AccountInfo account = pair.first;
|
||
obj["appName"] = account.appCode;
|
||
obj["lastNumbers"] = account.lastNumbers;
|
||
obj["amount"] = account.amount;
|
||
obj["description"] = account.description;
|
||
obj["status"] = accountStatusToString(account.status);
|
||
|
||
list.append(obj);
|
||
}
|
||
// FIXME доставить десктоп ид из настроеек
|
||
worker->setDeviceId(accounts.first().first.deviceId);
|
||
worker->setPayload(QJsonDocument(list).toJson());
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &NetworkService::postAccountsData);
|
||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void CommonScript::postNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction) {
|
||
auto *thread = new QThread;
|
||
auto *worker = new NetworkService;
|
||
|
||
QJsonObject obj;
|
||
obj["id"] = transaction.id;
|
||
obj["amount"] = transaction.amount;
|
||
obj["name"] = transaction.name;
|
||
obj["fee"] = transaction.fee;
|
||
obj["status"] = transactionStatusToString(transaction.status);
|
||
obj["type"] = transactionTypeToString(transaction.type);
|
||
obj["phone"] = transaction.phone;
|
||
obj["description"] = transaction.description;
|
||
obj["updatedDescription"] = transaction.updatedDescription;
|
||
obj["bankName"] = transaction.bankName;
|
||
obj["bankTime"] = transaction.bankTime;
|
||
obj["bankTransactionId"] = transaction.bankTrExternalId;
|
||
|
||
// FIXME доставить десктоп ид из настроеек
|
||
worker->setDeviceId(account.deviceId);
|
||
worker->addExtra("lastNumbers", account.lastNumbers);
|
||
worker->addExtra("transactionId", transaction.id);
|
||
worker->setPayload(QJsonDocument(obj).toJson());
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &NetworkService::insertTransactionData);
|
||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void CommonScript::updateTransactionData(
|
||
const AccountInfo &account,
|
||
const int transactionId,
|
||
const TransactionStatus status,
|
||
const QString &oldDesc,
|
||
const QString &newDesc
|
||
) {
|
||
auto *thread = new QThread;
|
||
auto *worker = new NetworkService;
|
||
|
||
QJsonObject obj;
|
||
obj["id"] = transactionId;
|
||
obj["status"] = transactionStatusToString(status);
|
||
obj["description"] = newDesc;
|
||
obj["updatedDescription"] = oldDesc;
|
||
|
||
// FIXME доставить десктоп ид из настроеек
|
||
worker->setDeviceId(account.deviceId);
|
||
worker->addExtra("lastNumbers", account.lastNumbers);
|
||
worker->setPayload(QJsonDocument(obj).toJson());
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &NetworkService::updateTransactionData);
|
||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void CommonScript::stop() {
|
||
m_running = false;
|
||
}
|