From bc0945d96c92673e8d0c1c2f99d6ff3bb826ef88 Mon Sep 17 00:00:00 2001 From: Arsen Mirzaev Tatyano-Muradovich Date: Sun, 5 May 2024 15:57:19 +0700 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=BA=D0=B0=2020=D0=BA=20=D0=BF=D0=BE=D0=B4=20=D0=B0=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B3=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.lock | 98 ++-- .../robot/entry/system/public/robot.php | 540 +++++++++++++----- .../entry/system/settings/arangodb.php.sample | 8 + 3 files changed, 465 insertions(+), 181 deletions(-) create mode 100644 mirzaev/spetsresurs/telegram/robot/entry/system/settings/arangodb.php.sample diff --git a/composer.lock b/composer.lock index 2c6ddc2..91419f8 100755 --- a/composer.lock +++ b/composer.lock @@ -308,7 +308,7 @@ }, { "name": "flow-php/array-dot", - "version": "0.7.3", + "version": "0.7.4", "source": { "type": "git", "url": "https://github.com/flow-php/array-dot.git", @@ -350,22 +350,22 @@ ], "support": { "issues": "https://github.com/flow-php/array-dot/issues", - "source": "https://github.com/flow-php/array-dot/tree/0.7.3" + "source": "https://github.com/flow-php/array-dot/tree/0.7.4" }, "time": "2024-03-10T14:05:42+00:00" }, { "name": "flow-php/etl", - "version": "0.7.3", + "version": "0.7.4", "source": { "type": "git", "url": "https://github.com/flow-php/etl.git", - "reference": "ba942170d44b9034edbf0ebea71a9241b92a755b" + "reference": "277033c341f9fa4cb64e7acdb66a190ffb3198ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/flow-php/etl/zipball/ba942170d44b9034edbf0ebea71a9241b92a755b", - "reference": "ba942170d44b9034edbf0ebea71a9241b92a755b", + "url": "https://api.github.com/repos/flow-php/etl/zipball/277033c341f9fa4cb64e7acdb66a190ffb3198ad", + "reference": "277033c341f9fa4cb64e7acdb66a190ffb3198ad", "shasum": "" }, "require": { @@ -417,9 +417,9 @@ ], "support": { "issues": "https://github.com/flow-php/etl/issues", - "source": "https://github.com/flow-php/etl/tree/0.7.3" + "source": "https://github.com/flow-php/etl/tree/0.7.4" }, - "time": "2024-03-29T21:50:09+00:00" + "time": "2024-04-18T09:51:27+00:00" }, { "name": "flow-php/etl-adapter-google-sheet", @@ -473,13 +473,13 @@ ], "support": { "issues": "https://github.com/flow-php/etl-adapter-google-sheet/issues", - "source": "https://github.com/flow-php/etl-adapter-google-sheet/tree/1.x" + "source": "https://github.com/flow-php/etl-adapter-google-sheet/tree/0.7.4" }, "time": "2024-04-02T18:26:10+00:00" }, { "name": "flow-php/rdsl", - "version": "0.7.3", + "version": "0.7.4", "source": { "type": "git", "url": "https://github.com/flow-php/rdsl.git", @@ -519,37 +519,37 @@ ], "support": { "issues": "https://github.com/flow-php/rdsl/issues", - "source": "https://github.com/flow-php/rdsl/tree/0.7.3" + "source": "https://github.com/flow-php/rdsl/tree/0.7.4" }, "time": "2024-03-10T14:06:05+00:00" }, { "name": "google/apiclient", - "version": "v2.15.3", + "version": "v2.16.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client.git", - "reference": "e70273c06d18824de77e114247ae3102f8aec64d" + "reference": "017400f609c1fb71ab5ad824c50eabd4c3eaf779" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/e70273c06d18824de77e114247ae3102f8aec64d", - "reference": "e70273c06d18824de77e114247ae3102f8aec64d", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/017400f609c1fb71ab5ad824c50eabd4c3eaf779", + "reference": "017400f609c1fb71ab5ad824c50eabd4c3eaf779", "shasum": "" }, "require": { "firebase/php-jwt": "~6.0", - "google/apiclient-services": "~0.200", - "google/auth": "^1.33", + "google/apiclient-services": "~0.350", + "google/auth": "^1.37", "guzzlehttp/guzzle": "^6.5.8||^7.4.5", - "guzzlehttp/psr7": "^1.8.4||^2.2.1", + "guzzlehttp/psr7": "^1.9.1||^2.2.1", "monolog/monolog": "^2.9||^3.0", "php": "^7.4|^8.0", - "phpseclib/phpseclib": "^3.0.34" + "phpseclib/phpseclib": "^3.0.36" }, "require-dev": { "cache/filesystem-adapter": "^1.1", - "composer/composer": "^1.10.22", + "composer/composer": "^1.10.23", "phpcompatibility/php-compatibility": "^9.2", "phpspec/prophecy-phpunit": "^2.0", "phpunit/phpunit": "^9.5", @@ -588,22 +588,22 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client/issues", - "source": "https://github.com/googleapis/google-api-php-client/tree/v2.15.3" + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.16.0" }, - "time": "2024-01-04T19:15:22+00:00" + "time": "2024-04-24T00:59:47+00:00" }, { "name": "google/apiclient-services", - "version": "v0.344.0", + "version": "v0.351.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "d5813b1a64a8a73daf7ab307dc640e2efb046131" + "reference": "a053f7dd118e46845fcefa9036c5b97b1050dfaa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/d5813b1a64a8a73daf7ab307dc640e2efb046131", - "reference": "d5813b1a64a8a73daf7ab307dc640e2efb046131", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/a053f7dd118e46845fcefa9036c5b97b1050dfaa", + "reference": "a053f7dd118e46845fcefa9036c5b97b1050dfaa", "shasum": "" }, "require": { @@ -632,40 +632,42 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.344.0" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.351.0" }, - "time": "2024-04-12T01:04:09+00:00" + "time": "2024-04-23T21:58:18+00:00" }, { "name": "google/auth", - "version": "v1.37.1", + "version": "v1.39.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-auth-library-php.git", - "reference": "1a7de77b72e6ac60dccf0e6478c4c1005bb0ff46" + "reference": "23e8e696d87f8d7dfefbd347ca1c99ce17ecb368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/1a7de77b72e6ac60dccf0e6478c4c1005bb0ff46", - "reference": "1a7de77b72e6ac60dccf0e6478c4c1005bb0ff46", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/23e8e696d87f8d7dfefbd347ca1c99ce17ecb368", + "reference": "23e8e696d87f8d7dfefbd347ca1c99ce17ecb368", "shasum": "" }, "require": { "firebase/php-jwt": "^6.0", - "guzzlehttp/guzzle": "^6.5.8||^7.4.5", + "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.4.5", - "php": "^7.4||^8.0", - "psr/cache": "^1.0||^2.0||^3.0", + "php": "^8.0", + "psr/cache": "^2.0||^3.0", "psr/http-message": "^1.1||^2.0" }, "require-dev": { "guzzlehttp/promises": "^2.0", "kelvinmo/simplejwt": "0.7.1", - "phpseclib/phpseclib": "^3.0", - "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.0.0", + "phpseclib/phpseclib": "^3.0.35", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", "sebastian/comparator": ">=1.2.3", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^6.0||^7.0", + "webmozart/assert": "^1.11" }, "suggest": { "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." @@ -690,9 +692,9 @@ "support": { "docs": "https://googleapis.github.io/google-auth-library-php/main/", "issues": "https://github.com/googleapis/google-auth-library-php/issues", - "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.37.1" + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.39.0" }, - "time": "2024-04-03T18:41:12+00:00" + "time": "2024-05-02T16:03:51+00:00" }, { "name": "guzzlehttp/guzzle", @@ -3047,16 +3049,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -3065,7 +3067,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3094,7 +3096,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -3110,7 +3112,7 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "triagens/arangodb", diff --git a/mirzaev/spetsresurs/telegram/robot/entry/system/public/robot.php b/mirzaev/spetsresurs/telegram/robot/entry/system/public/robot.php index 521aa83..d73b13f 100644 --- a/mirzaev/spetsresurs/telegram/robot/entry/system/public/robot.php +++ b/mirzaev/spetsresurs/telegram/robot/entry/system/public/robot.php @@ -1,5 +1,15 @@ setParseMode(Config::PARSE_MODE_MARKDOWN); $bot = new Zanzara(require(__DIR__ . '/../settings/key.php'), $config); -$bot->onMessage(function (Context $ctx) { +$bot->onMessage(function (Context $ctx) use ($arangodb) { + // Инициализация сообщения + $message = $ctx->getMessage(); + if ($members = $ctx->getMessage()->getNewChatMembers()) { // Новый аккаунт в чате - echo "Обнаружен новый участник в чате" . PHP_EOL; - $ctx->sendMessage("⚠️ Введите ваш табельный номер", ['reply_to_message_id' => $ctx->getMessage()->getMessageId()]) - ->then(function ($message) use ($ctx, $members) { - // Инициализация идентификатора сотрудника - $id = $members[0]->getId(); - echo "Отправлено сообщение ({$message->getMessageId()}) с запросом ID у сотрудника ($id)" . PHP_EOL; - - $ctx->getGlobalDataItem("member_{$id}_request") - ->then( - function ($old) use ($ctx, $id, $message) { - - $timer = function ($ctx, $id, $message) { - $ctx->setGlobalDataItem("member_{$id}_request", $message) - ->then(function () use ($ctx, $id, $message) { - echo "Записано сообщение ({$message->getMessageId()}) с запросом ID у сотрудника ($id) в сессионное хранилище" . PHP_EOL; - - // Инициализация таймера - React\Promise\Timer\sleep(180)->then( - function () use ($ctx, $id) { - - $ctx->getGlobalDataItem("member_{$id}_request") - ->then( - function ($message) use ($ctx, $id) { - if ($message) { - // Изгнание из чата - $ctx->kickChatMember($message->getChat()->getId(), $id) - ->then(function () use ($ctx, $id, $message) { - echo "Сотрудник ($id) изгнан из чата ({$message->getChat()->getId()})" . PHP_EOL; - - // Удаление сообщения из сессионного хранилища - $ctx->deleteGlobalDataItem("member_{$id}_request"); - - echo "Удалено сообщение ({$message->getMessageId()}?) (member_{$id}_request) с запросом ID у сотрудника ($id) из сессионного хранилища" . PHP_EOL; - - // Удаление сообщения - $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); - - echo "Удалено сообщение ({$message->getMessageId()}) с запросом ID у сотрудника ($id) из чата ({$message->getChat()->getId()})" . PHP_EOL; - }); - } - }, - function () { - } - ); - } - ); - - echo "Инициализирован таймер изгнания сотрудника ($id)" . PHP_EOL; - }); - }; - - if ($old) { - echo "Найдено сообщение ({$old->getMessageId()}) с запросом ID у сотрудника ($id) в сессионном хранилище" . PHP_EOL; - - $ctx->deleteGlobalDataItem("member_{$id}_request") - ->then(function () use ($ctx, $id, $message, $timer, $old) { - echo "Удалено сообщение ({$old->getMessageId()}?) (member_{$id}_request) с запросом ID у сотрудника ($id) из сессионного хранилища" . PHP_EOL; - - $ctx->deleteMessage($old->getChat()->getId(), $old->getMessageId()) - ->then(function () use ($ctx, $id, $message, $timer, $old) { - echo "Удалено сообщение ({$old->getMessageId()}) с запросом ID у сотрудника ($id) из чата ({$old->getChat()->getId()})" . PHP_EOL; - $timer($ctx, $id, $message); - }); - }); - } else { - echo "Не найдено сообщение с запросом ID у сотрудника ($id) в сессионном хранилище" . PHP_EOL; - $timer($ctx, $id, $message); - } - } - ); - }); - } else { + // Инициализация идентификатора сотрудника + $id = $members[0]->getId(); + } else if ($ctx->getMessage()->getLeftChatMember()) return; + else { // Любое сообщение - // Инициализация сообщения - $message = $ctx->getMessage(); - // Инициализация идентификатора отправителя сообщения $id = $message->getFrom()->getId(); + } - $ctx->getGlobalDataItem("member_{$id}_request") - ->then( - function ($_message) use ($ctx, $id, $message) { - if ($_message) { - // Инициализация переданного идентификатора (только цифры) - $worker = preg_replace('/[^\d]/', '', $message->getText() ?? ''); + if (collection::init($arangodb->session, 'telegram')) { + // Инициализирована коллекция telegram-аккаунтов в ArangoDB - $settings = json_decode(require(__DIR__ . '/../settings/workers/google.php'), true); - $document = require(__DIR__ . '/../settings/workers/document.php'); - $sheets = require(__DIR__ . '/../settings/workers/sheets.php'); + if (!$telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s && !d.deleted RETURN d", $id))) { + // Не найден telegram-аккаунт в базе данных - $client = new Client(); - $client->setScopes(Sheets::SPREADSHEETS); - $client->setAuthConfig($settings); - $api = new Sheets($client); + // Запись telegram-аккаунта в базу данных (не привязан сотрудник и активность - прямо сейчас) + document::write($arangodb->session, 'telegram', ['id' => $id, 'worker' => null, 'activity' => time(), 'welcome' => false]); - foreach ($sheets as $sheet) { - $rows = (new Flow())->read(new GoogleSheetExtractor($api, $document, new Columns($sheet, 'A', 'A'), true, 1000)); + if (!$telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s && !d.deleted RETURN d", $id))) { + // Не найден telegram-аккаунт в базе данных - foreach ($rows->fetch(10000) as $row) { - // Перебор строк + throw new exception('чё бля происходит'); + } + } - if ($worker === $row->toArray()['ID']) { - $ctx->sendMessage("✅ Авторизован сотрудник: $worker", ['reply_to_message_id' => $message->getMessageId()]) + if ($telegram->worker === null) { + // Не авторизован telegram-аккаунт + + if ($telegram->welcome && $telegram->activity - time() < 0 && !$telegram->ban) { + // Повторный запрос авторизации + прошло более 10800 секунд (3 часа) с последней активности (подразумевается отправка сообщения) + // Подразумевается, что если $telegram->ban === true, то уже идёт процесс авторизации и это сообщение уже было отправлено + + $ctx->sendMessage("⚠️ Введите ваш табельный номер\nТребуется дополнительная проверка", ['reply_to_message_id' => $ctx->getMessage()->getMessageId()]) + ->then(function ($message) use ($ctx, $id, $arangodb, $telegram) { + // Запись в реестр сообщений + $telegram->messages = [ + $message->getChat()->getId() => [ + $message->getMessageId() => $message->getText() + ] + ($telegram->messages[$message->getChat()->getId()] ?? []) + ] + ($telegram->messages ?? []); + + // Инициализация таймера изгнания из чата (180 секунд - 3 минуты) + $telegram->ban = time() + 180; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + + // Инициализация таймера изгнания сотрудника и удаления сообщения + React\Promise\Timer\sleep(180)->then( + function () use ($ctx, $id, $message, $arangodb) { + if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s RETURN d", $id))) { + // Найден telegram-аккаунт в базе данных (повторное чтение для обновления буфера сообщений) + + if ($telegram->messages[(string) $message->getChat()->getId()][(string) $message->getMessageId()]) { + // Найдено сообщение в ArangoDB (подразумевается, что оно есть и в чате) + + // Удаление сообщения из чата + $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + + // Удаление сообщения из ArangoDB + $buffer = $telegram->messages; + unset($buffer[(string) $message->getChat()->getId()][(string) $message->getMessageId()]); + + // По первому уровню массива (чату) ArangoDB думает, что изменений нет и не перезаписывает (лень разбираться) + $telegram->messages = []; + document::update($arangodb->session, $telegram); + + $telegram->messages = $buffer; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + } + + if ($telegram->ban) { + // Прошло более 180 секунд (3 минуты) без авторизации после запроса + + // Изгнание из чата + $ctx->kickChatMember($message->getChat()->getId(), $id) + ->then(function () use ($ctx, $id, $message, $arangodb, $telegram) { + // Изгнан из чата + + // Удаление всех сообщений из чата + foreach ($telegram->messages ?? [] as $chat => $messages) + foreach ($messages as $_message => $text) + $ctx->deleteMessage($chat, $_message); + + // Удаление всех сообщений в чате из ArangoDB + $telegram->messages = [(string) $message->getChat()->getId() => []] + ($telegram->messages ?? []); + + // Запись статуса удаления в ArangoDB + $telegram->deleted = true; + + // Запись таймера изгнания + $telegram->ban = false; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + }); + } + } + }, + fn () => null + ); + }); + + // Возврат (успех) + return; + } else if (!$telegram->welcome) { + // Первый запрос авторизации + + $ctx->sendMessage("⚠️ Введите ваш табельный номер", ['reply_to_message_id' => $ctx->getMessage()->getMessageId()]) + ->then(function ($message) use ($ctx, $id, $arangodb, $telegram) { + // Запись статуса первого запроса авторизации + $telegram->welcome = true; + + // Запись в реестр сообщений + $telegram->messages = [ + $message->getChat()->getId() => [ + $message->getMessageId() => $message->getText() + ] + ($telegram->messages[$message->getChat()->getId()] ?? []) + ] + ($telegram->messages ?? []); + + // Инициализация таймера изгнания из чата (180 секунд - 3 минуты) + $telegram->ban = time() + 180; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + + // Инициализация таймера изгнания сотрудника и удаления сообщения + React\Promise\Timer\sleep(180)->then( + function () use ($ctx, $id, $message, $arangodb) { + if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s RETURN d", $id))) { + // Найден telegram-аккаунт в базе данных (повторное чтение для обновления буфера сообщений) + + if ($telegram->messages[(string) $message->getChat()->getId()][(string) $message->getMessageId()]) { + // Найдено сообщение в ArangoDB (подразумевается, что оно есть и в чате) + + // Удаление сообщения из чата + $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + + // Удаление сообщения из ArangoDB + $buffer = $telegram->messages; + unset($buffer[(string) $message->getChat()->getId()][(string) $message->getMessageId()]); + + // По первому уровню массива (чату) ArangoDB думает, что изменений нет и не перезаписывает (лень разбираться) + $telegram->messages = []; + document::update($arangodb->session, $telegram); + + $telegram->messages = $buffer; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + } + + if ($telegram->ban) { + // Прошло более 180 секунд (3 минуты) без авторизации после завпроса + + // Изгнание из чата + $ctx->kickChatMember($message->getChat()->getId(), $id) + ->then(function () use ($ctx, $id, $message, $arangodb, $telegram) { + // Изгнан из чата + + // Удаление всех сообщений из чата + foreach ($telegram->messages ?? [] as $chat => $messages) + foreach ($messages as $_message => $text) + $ctx->deleteMessage($chat, $_message); + + // Удаление всех сообщений в чате из ArangoDB + $telegram->messages = [(string) $message->getChat()->getId() => []] + ($telegram->messages ?? []); + + // Запись статуса удаления в ArangoDB + $telegram->deleted = true; + + // Запись таймера изгнания + $telegram->ban = false; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + }); + } + } + }, + fn () => null + ); + }); + + // Возврат (успех) + return; + } + + if ($telegram->ban && $telegram->ban - time() < 0) { + // Прошло более 180 секунд (3 минуты) без авторизации после завпроса + + // Изгнание из чата + $ctx->kickChatMember($message->getChat()->getId(), $id) + ->then(function () use ($ctx, $id, $message, $arangodb, $telegram) { + // Изгнан из чата + + // Удаление всех сообщений из чата + foreach ($telegram->messages ?? [] as $chat => $messages) + foreach ($messages as $_message => $text) + $ctx->deleteMessage($chat, $_message); + + // Удаление всех сообщений в чате из ArangoDB + $telegram->messages = [(string) $message->getChat()->getId() => []] + ($telegram->messages ?? []); + + // Запись статуса удаления в ArangoDB + $telegram->deleted = true; + + // Запись таймера изгнания + $telegram->ban = false; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + }); + + // Возврат (успех) + return; + } else { + // Не прошло 180 секунд (3 минуты) без авторизации после запроса (либо запроса ещё не было) + + // Инициализация переданного идентификатора (только цифры) + $worker = preg_replace('/[^\d]/', '', $message->getText() ?? ''); + + if (!empty($worker)) { + // Инициализирован идентификатор сотрудника для поиска + + $settings = json_decode(require(__DIR__ . '/../settings/workers/google.php'), true); + $document = require(__DIR__ . '/../settings/workers/document.php'); + $sheets = require(__DIR__ . '/../settings/workers/sheets.php'); + + $client = new Client(); + $client->setScopes(Sheets::SPREADSHEETS); + $client->setAuthConfig($settings); + $api = new Sheets($client); + + foreach ($sheets as $sheet) { + $rows = (new Flow())->read(new GoogleSheetExtractor($api, $document, new Columns($sheet, 'A', 'A'), true, 1000)); + + foreach ($rows->fetch(10000) as $row) { + // Перебор строк + + if ($worker === $row->toArray()['ID']) { + // Найден идентификатор + + if (collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.worker == %s RETURN d", $worker))) + $ctx->sendMessage("🪪 Сотрудник \\($worker\\) уже привязан к другому telegram\\-аккаунту", ['reply_to_message_id' => $message->getMessageId()]) ->then( - function ($message) use ($ctx, $id) { - // Инициализация таймера - React\Promise\Timer\sleep(10)->then( - function () use ($ctx, $id, $message) { - // Удаление сообщения - $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + function ($message) use ($ctx, $id, $arangodb, $telegram) { + // Запись в реестр сообщений + $telegram->messages = [ + $message->getChat()->getId() => [ + $message->getMessageId() => $message->getText() + ] + ($telegram->messages[$message->getChat()->getId()] ?? []) + ] + ($telegram->messages ?? []); - echo "Удалено сообщение ({$message->getMessageId()}) с подтверждением авторизации сотрудника ($id) в чате ({$message->getChat()->getId()})" . PHP_EOL; + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + + // Инициализация таймера удаления сообщения + React\Promise\Timer\sleep(10)->then( + function () use ($ctx, $id, $message, $arangodb) { + if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s RETURN d", $id))) { + // Найден telegram-аккаунт в базе данных (повторное чтение для обновления буфера сообщений) + + if ($telegram->messages[(string) $message->getChat()->getId()][(string) $message->getMessageId()]) { + // Найдено сообщение в ArangoDB (подразумевается, что оно есть и в чате) + + // Удаление сообщения из чата + $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + + // Удаление сообщения из ArangoDB + $buffer = $telegram->messages; + unset($buffer[(string) $message->getChat()->getId()][(string) $message->getMessageId()]); + + // По первому уровню массива (чату) ArangoDB думает, что изменений нет и не перезаписывает (лень разбираться) + $telegram->messages = []; + document::update($arangodb->session, $telegram); + + $telegram->messages = $buffer; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + } + } }, - function () { - } + fn () => null ); } ); - echo "Авторизован сотрудник ($id) по идентификатору ($worker)" . PHP_EOL; + else { + // Не занят идентификатор - // Удаление сообщения из сессионного хранилища - $ctx->deleteGlobalDataItem("member_{$id}_request"); + // Запись статуса изгнания (остановка процесса) + $telegram->ban = false; - echo "Удалено сообщение ({$_message->getMessageId()}) с запросом ID у сотрудника ($id) из сессионного хранилища после успешной авторизации" . PHP_EOL; + // Запись сотрудника (привязка) + $telegram->worker = (int) $worker; - // Удаление сообщения - $ctx->deleteMessage($_message->getChat()->getId(), $_message->getMessageId()); + // Удаление всех сообщений из чата + foreach ($telegram->messages ?? [] as $chat => $messages) + foreach ($messages as $_message => $text) + $ctx->deleteMessage($chat, $_message); - echo "Удалено сообщение ({$_message->getMessageId()}) с запросом ID у сотрудника ($id) из чата ({$_message->getChat()->getId()}) после успешной авторизации" . PHP_EOL; + // Удаление всех сообщений в чате из ArangoDB + $telegram->messages = [(string) $message->getChat()->getId() => []] + ($telegram->messages ?? []); - return; - } - } - } + // Запись в ArangoDB + document::update($arangodb->session, $telegram); - if (!empty($worker)) { - echo "Не удалось авторизовать сотрудника ($id) по номеру ($worker)" . PHP_EOL; - $ctx->sendMessage("⛔ Не найден сотрудник: $worker", ['reply_to_message_id' => $message->getMessageId()]) - ->then( - function ($message) use ($ctx, $id) { - // Инициализация таймера - React\Promise\Timer\sleep(10)->then( - function () use ($ctx, $id, $message) { - // Удаление сообщения - $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + $ctx->sendMessage("✅ Авторизован сотрудник: $worker", ['reply_to_message_id' => $message->getMessageId()]) + ->then( + function ($message) use ($ctx, $id, $arangodb, $telegram) { + // Запись в реестр сообщений + $telegram->messages = [ + $message->getChat()->getId() => [ + $message->getMessageId() => $message->getText() + ] + ($telegram->messages[$message->getChat()->getId()] ?? []) + ] + ($telegram->messages ?? []); - echo "Удалено сообщение ({$message->getMessageId()}) с провалом авторизации сотрудника ($id) в чате ({$message->getChat()->getId()})" . PHP_EOL; - }, - function () { + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + + // Инициализация таймера удаления сообщения + React\Promise\Timer\sleep(10)->then( + function () use ($ctx, $id, $message, $arangodb) { + if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s RETURN d", $id))) { + // Найден telegram-аккаунт в базе данных (повторное чтение для обновления буфера сообщений) + + if ($telegram->messages[(string) $message->getChat()->getId()][(string) $message->getMessageId()]) { + // Найдено сообщение в ArangoDB (подразумевается, что оно есть и в чате) + + // Удаление сообщения из чата + $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + + // Удаление сообщения из ArangoDB + $buffer = $telegram->messages; + unset($buffer[(string) $message->getChat()->getId()][(string) $message->getMessageId()]); + + // По первому уровню массива (чату) ArangoDB думает, что изменений нет и не перезаписывает (лень разбираться) + $telegram->messages = []; + document::update($arangodb->session, $telegram); + + $telegram->messages = $buffer; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + } + } + }, + fn () => null + ); } ); - } - ); + } + + // Возврат (успех) + return; + } } } + + $ctx->sendMessage("⛔ Не найден сотрудник: $worker", ['reply_to_message_id' => $message->getMessageId()]) + ->then( + function ($message) use ($ctx, $id, $arangodb, $telegram) { + // Запись в реестр сообщений + $telegram->messages = [ + $message->getChat()->getId() => [ + $message->getMessageId() => $message->getText() + ] + ($telegram->messages[$message->getChat()->getId()] ?? []) + ] + ($telegram->messages ?? []); + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + + // Инициализация таймера + React\Promise\Timer\sleep(10)->then( + function () use ($ctx, $id, $message, $arangodb) { + if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == %s RETURN d", $id))) { + // Найден telegram-аккаунт в базе данных (повторное чтение для обновления буфера сообщений) + + if ($telegram->messages[(string) $message->getChat()->getId()][(string) $message->getMessageId()]) { + // Найдено сообщение в ArangoDB (подразумевается, что оно есть и в чате) + + // Удаление сообщения из чата + $ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId()); + + // Удаление сообщения из ArangoDB + $buffer = $telegram->messages; + unset($buffer[(string) $message->getChat()->getId()][(string) $message->getMessageId()]); + + // По первому уровню массива (чату) ArangoDB думает, что изменений нет и не перезаписывает (лень разбираться) + $telegram->messages = []; + document::update($arangodb->session, $telegram); + + $telegram->messages = $buffer; + + // Запись в ArangoDB + document::update($arangodb->session, $telegram); + } + } + }, + fn () => null + ); + } + ); + + // Возврат (успех) + return; } - ); + } + } + + // Запись активности + $telegram->activity = time(); + document::update($arangodb->session, $telegram); } }); diff --git a/mirzaev/spetsresurs/telegram/robot/entry/system/settings/arangodb.php.sample b/mirzaev/spetsresurs/telegram/robot/entry/system/settings/arangodb.php.sample new file mode 100644 index 0000000..fc1c2d1 --- /dev/null +++ b/mirzaev/spetsresurs/telegram/robot/entry/system/settings/arangodb.php.sample @@ -0,0 +1,8 @@ + 'unix:///var/run/arangodb3/arango.sock', + 'database' => '', + 'name' => '', + 'password' => '' +];