робот создан на базе mirzaev/spetsresurs-viber-registry-requests
This commit is contained in:
parent
d7ccbcd57f
commit
389e4ab574
|
@ -1,16 +1,16 @@
|
||||||
{
|
{
|
||||||
"name": "mirzaev/spetsresurs-viber-registry-requests",
|
"name": "mirzaev/spetsresurs-telegram-registry-requests",
|
||||||
"type": "robot",
|
"type": "robot",
|
||||||
"require": {
|
"require": {
|
||||||
"bogdaan/viber-bot-php": "^0.0.15",
|
|
||||||
"triagens/arangodb": "^3.8",
|
"triagens/arangodb": "^3.8",
|
||||||
"mirzaev/arangodb": "^1.0",
|
"mirzaev/arangodb": "^1.0",
|
||||||
"monolog/monolog": "^3.3"
|
"badfarm/zanzara": "^0.9.1",
|
||||||
|
"nyholm/psr7": "^1.8"
|
||||||
},
|
},
|
||||||
"license": "WTFPL",
|
"license": "WTFPL",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"mirzaev\\spetsresurs\\viber\\registry\\requests\\": "mirzaev/spetsresurs/viber/registry/requests/system/"
|
"mirzaev\\spetsresurs\\telegram\\registry\\requests\\": "mirzaev/spetsresurs/telegram/registry/requests/system/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
|
@ -19,5 +19,10 @@
|
||||||
"email": "arsen@mirzaev.sexy"
|
"email": "arsen@mirzaev.sexy"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"minimum-stability": "stable"
|
"minimum-stability": "stable",
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"php-http/discovery": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,401 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Фреймворк ArangoDB
|
||||||
|
use mirzaev\arangodb\connection,
|
||||||
|
mirzaev\arangodb\collection,
|
||||||
|
mirzaev\arangodb\document;
|
||||||
|
|
||||||
|
// Библиотека для ArangoDB
|
||||||
|
use ArangoDBClient\Document as _document,
|
||||||
|
ArangoDBClient\Cursor,
|
||||||
|
ArangoDBClient\Statement as _statement;
|
||||||
|
|
||||||
|
// Фреймворк Telegram
|
||||||
|
use Zanzara\Zanzara;
|
||||||
|
use Zanzara\Context;
|
||||||
|
use Zanzara\Config;
|
||||||
|
|
||||||
|
require __DIR__ . '/../../../../../../../vendor/autoload.php';
|
||||||
|
|
||||||
|
$arangodb = new connection(require __DIR__ . '/../settings/arangodb.php');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Авторизация
|
||||||
|
*
|
||||||
|
* @param string $id Идентификатор Telegram
|
||||||
|
*
|
||||||
|
* @return _document|null|false (инстанция аккаунта, если подключен и авторизован; null, если не подключен; false, если подключен но неавторизован)
|
||||||
|
*/
|
||||||
|
function authorization(string $id): _document|null|false
|
||||||
|
{
|
||||||
|
global $arangodb;
|
||||||
|
|
||||||
|
if (collection::init($arangodb->session, 'telegram'))
|
||||||
|
if (
|
||||||
|
($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == '%s' RETURN d", $id)))
|
||||||
|
|| $telegram = collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN telegram FILTER d._id == '%s' RETURN d",
|
||||||
|
document::write($arangodb->session, 'telegram', ['id' => $id, 'status' => 'inactive'])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if ($telegram->number === null) return null;
|
||||||
|
else if (
|
||||||
|
$telegram->status === 'active'
|
||||||
|
&& collection::init($arangodb->session, 'workers')
|
||||||
|
&& $worker = collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN workers LET e = (FOR e IN connections FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d",
|
||||||
|
$telegram->getId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) return $worker;
|
||||||
|
else return false;
|
||||||
|
else throw new exception('Не удалось найти или создать аккаунт');
|
||||||
|
else throw new exception('Не удалось инициализировать коллекцию');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function registration(string $id, string $number): bool
|
||||||
|
{
|
||||||
|
global $arangodb;
|
||||||
|
|
||||||
|
if (collection::init($arangodb->session, 'telegram')) {
|
||||||
|
if ($telegram = collection::search($arangodb->session, sprintf("FOR d IN telegram FILTER d.id == '%s' RETURN d", $id))) {
|
||||||
|
// Найден аккаунт
|
||||||
|
|
||||||
|
// Запись номера
|
||||||
|
$telegram->number = $number;
|
||||||
|
if (!document::update($arangodb->session, $telegram)) return false;
|
||||||
|
} else if (!collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN telegram FILTER d._id == '%s' RETURN d",
|
||||||
|
document::write($arangodb->session, 'telegram', ['id' => $id, 'status' => 'inactive', 'number' => $number])
|
||||||
|
)
|
||||||
|
)) return false;
|
||||||
|
|
||||||
|
// Инициализация ребра: workers -> telegram
|
||||||
|
if (
|
||||||
|
collection::init($arangodb->session, 'workers')
|
||||||
|
&& ($worker = collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN workers FILTER d.phone == '%d' RETURN d",
|
||||||
|
$telegram->number
|
||||||
|
)
|
||||||
|
))
|
||||||
|
&& collection::init($arangodb->session, 'connections', true)
|
||||||
|
&& (collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN connections FILTER d._from == '%s' && d._to == '%s' RETURN d",
|
||||||
|
$worker->getId(),
|
||||||
|
$telegram->getId()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
?? collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN connections FILTER d._id == '%s' RETURN d",
|
||||||
|
document::write(
|
||||||
|
$arangodb->session,
|
||||||
|
'connections',
|
||||||
|
['_from' => $worker->getId(), '_to' => $telegram->getId()]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
// Инициализировано ребро: workers -> telegram
|
||||||
|
|
||||||
|
// Активация
|
||||||
|
$telegram->status = 'active';
|
||||||
|
return document::update($arangodb->session, $telegram);
|
||||||
|
}
|
||||||
|
} else throw new exception('Не удалось инициализировать коллекцию');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateAuthenticationKeyboard(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'reply_markup' => [
|
||||||
|
'keyboard' => [
|
||||||
|
[
|
||||||
|
['text' => '🔐 Аутентификация', 'request_contact' => true]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'resize_keyboard' => true
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateMenu(Context $ctx): void
|
||||||
|
{
|
||||||
|
if ($worker = authorization($ctx->getMessage()?->getFrom()?->getId() ?? $ctx->getCallbackQuery()->getFrom()->getId())) {
|
||||||
|
// Успешная авторизация
|
||||||
|
|
||||||
|
$ctx->sendMessage('👋 Здравствуйте, ' . $worker->name, [
|
||||||
|
'reply_markup' => [
|
||||||
|
'inline_keyboard' => [
|
||||||
|
[
|
||||||
|
['text' => '🔍 Активные заявки', 'callback_data' => 'search']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'remove_keyboard' => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function requests(int $amount = 5, int $page = 1): Cursor
|
||||||
|
{
|
||||||
|
global $arangodb;
|
||||||
|
|
||||||
|
// Фильтрация номера страницы
|
||||||
|
if ($page < 1) $page = 1;
|
||||||
|
|
||||||
|
// Инициализация номера страницы для вычислний
|
||||||
|
--$page;
|
||||||
|
|
||||||
|
// Инициализация сдвига
|
||||||
|
$offset = $page === 0 ? 0 : $page * $amount;
|
||||||
|
|
||||||
|
return (new _statement(
|
||||||
|
$arangodb->session,
|
||||||
|
[
|
||||||
|
'query' => sprintf(
|
||||||
|
"FOR d IN works FILTER d.confirmed != 'да' SORT d.created DESC LIMIT %d, %d RETURN d",
|
||||||
|
$offset,
|
||||||
|
$amount + $offset
|
||||||
|
),
|
||||||
|
"batchSize" => 1000,
|
||||||
|
"sanitize" => true
|
||||||
|
]
|
||||||
|
))->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateEmojis(): string
|
||||||
|
{
|
||||||
|
return '&#' . hexdec(trim(array_rand(file(__DIR__ . '/../emojis.txt')))) . ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
function requests_next(Context $ctx): void
|
||||||
|
{
|
||||||
|
$ctx->getChatDataItem('requests_page')->then(function ($page) use ($ctx) {
|
||||||
|
$ctx->setChatDataItem('requests_page', ($page ?? 1) + 1)->then(function () use ($ctx) {
|
||||||
|
search($ctx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function requests_previous(Context $ctx): void
|
||||||
|
{
|
||||||
|
$ctx->getChatDataItem('requests_page')->then(function ($page) use ($ctx) {
|
||||||
|
$ctx->setChatDataItem('requests_page', ($page ?? 2) - 1)->then(function () use ($ctx) {
|
||||||
|
search($ctx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function request_choose(Context $ctx): void
|
||||||
|
{
|
||||||
|
global $arangodb;
|
||||||
|
|
||||||
|
if (($worker = authorization($ctx->getCallbackQuery()->getFrom()->getId())) instanceof _document) {
|
||||||
|
// Авторизован
|
||||||
|
|
||||||
|
// Инициализация ключа инстанции works в базе данных
|
||||||
|
preg_match('/^#(\d+)\n/', $ctx->getCallbackQuery()->getMessage()->getText(), $matches);
|
||||||
|
$_key = $matches[1];
|
||||||
|
|
||||||
|
// Инициализация инстанции works в базе данных (выбранного задания)
|
||||||
|
$work = collection::search($arangodb->session, sprintf("FOR d IN works FILTER d._key == '%s' RETURN d", $_key));
|
||||||
|
|
||||||
|
// Запись о том, что задание подтверждено (в будущем здесь будет отправка на потдверждение модераторам)
|
||||||
|
$work->confirmed = 'да';
|
||||||
|
|
||||||
|
// Запись о том, что необходимо перенести изменения в Google Sheets
|
||||||
|
$work->transfer_to_sheets = 'да';
|
||||||
|
|
||||||
|
// Запись идентификатора Google Sheets нового сотрудника
|
||||||
|
$work->worker = $worker->id;
|
||||||
|
|
||||||
|
if (document::update($arangodb->session, $work)) {
|
||||||
|
// Записано обновление в базу данных
|
||||||
|
|
||||||
|
if (collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN readinesses FILTER d._id == '%s' RETURN d",
|
||||||
|
document::write($arangodb->session, 'readinesses', ['_from' => $worker->getId(), '_to' => $work->getId()])
|
||||||
|
)
|
||||||
|
)) {
|
||||||
|
// Записано ребро: worker -> work (принятие заявки)
|
||||||
|
|
||||||
|
$ctx->sendMessage("✅ *Заявка принята:* \#$_key", ['reply_markup' => ['remove_keyboard' => true]])->then(function () use ($ctx) {
|
||||||
|
generateMenu($ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(Context $ctx): void
|
||||||
|
{
|
||||||
|
global $arangodb;
|
||||||
|
|
||||||
|
if (authorization($ctx->getMessage()?->getFrom()?->getId() ?? $ctx->getCallbackQuery()->getFrom()->getId()) instanceof _document) {
|
||||||
|
// Авторизован
|
||||||
|
|
||||||
|
$ctx->getChatDataItem('requests_page')->then(function ($page) use ($ctx, $arangodb) {
|
||||||
|
// Найдена текущая страница
|
||||||
|
|
||||||
|
// Значение страницы по умолчанию
|
||||||
|
if (empty($page)) {
|
||||||
|
$page = 1;
|
||||||
|
$ctx->setChatDataItem('requests_page', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Поиск заявок из базы данных
|
||||||
|
$requests = requests(6, $page);
|
||||||
|
|
||||||
|
// Подсчёт количества прочитанных заявок из базы данных
|
||||||
|
$count = $requests->getCount();
|
||||||
|
|
||||||
|
// Проверка существования избытка
|
||||||
|
$excess = $count % 6 === 0;
|
||||||
|
|
||||||
|
// Обрезка заявок до размера страницы
|
||||||
|
$requests = array_slice($requests->getAll(), 0, 5);
|
||||||
|
|
||||||
|
if ($count === 0) $ctx->sendMessage('📦 *Заявок нет*');
|
||||||
|
else {
|
||||||
|
// Найдены заявки
|
||||||
|
|
||||||
|
foreach ($requests as $i => $request) {
|
||||||
|
// Перебор найденных заявок
|
||||||
|
|
||||||
|
if (($market = collection::search(
|
||||||
|
$arangodb->session,
|
||||||
|
sprintf(
|
||||||
|
"FOR d IN markets LET e = (FOR e IN requests FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d",
|
||||||
|
$request->getId()
|
||||||
|
)
|
||||||
|
)) instanceof _document) {
|
||||||
|
// Найден магазин
|
||||||
|
|
||||||
|
$ctx->getChatDataItem("request_$i")->then(function ($message) use ($ctx) {
|
||||||
|
// Удаление предыдущего сообщения на этой позиции
|
||||||
|
$ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Генерация эмодзи
|
||||||
|
/* $emoji = generateEmojis(); */
|
||||||
|
|
||||||
|
// Отправка сообщения
|
||||||
|
$ctx->sendMessage(
|
||||||
|
preg_replace(
|
||||||
|
'/([._\-()!#])/',
|
||||||
|
'\\\$1',
|
||||||
|
"*#{$request->getKey()}*\n" . $request->date['converted'] . " (" . $request->start['converted'] . " - " . $request->end['converted'] . ")\n\n*Город:* $market->city\n*Адрес:* $market->address\n*Работа:* \"$request->work\""
|
||||||
|
),
|
||||||
|
[
|
||||||
|
'reply_markup' => [
|
||||||
|
'inline_keyboard' => [
|
||||||
|
[
|
||||||
|
['text' => '✅ Отправить запрос', 'callback_data' => 'request_choose']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)->then(function ($message) use ($ctx, $requests, $i, $page, $excess) {
|
||||||
|
// Запись сообщения в кеш (на случай необходимости его удаления при смене страницы)
|
||||||
|
$ctx->setChatDataItem("request_$i", $message)->then(function () use ($ctx, $requests, $i, $page, $excess) {
|
||||||
|
if ($i === array_key_last($requests)) {
|
||||||
|
// Удаление предыдущего меню
|
||||||
|
$ctx->getChatDataItem("request_menu")->then(function ($message) use ($ctx) {
|
||||||
|
$ctx->deleteMessage($message->getChat()->getId(), $message->getMessageId());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Инициализация буфера для меню поиска
|
||||||
|
$keyboard = [];
|
||||||
|
|
||||||
|
// Генерация кнопки: "Предыдущая страница"
|
||||||
|
if ($page > 1) $keyboard[] = ['text' => 'Назад ⬅️', 'callback_data' => 'requests_previous'];
|
||||||
|
|
||||||
|
// Генерация кнопки: "Следующая страница"
|
||||||
|
if ($excess) $keyboard[] = ['text' => '➡️ Вперёд', 'callback_data' => 'requests_next'];
|
||||||
|
|
||||||
|
// Отправка меню
|
||||||
|
$ctx->sendMessage('🔍 Выберите заявку', [
|
||||||
|
'reply_markup' => [
|
||||||
|
'inline_keyboard' => [
|
||||||
|
$keyboard
|
||||||
|
]
|
||||||
|
]
|
||||||
|
])->then(function ($message) use ($ctx) {
|
||||||
|
// Запись сообщения в кеш (на случай необходимости его удаления при смене страницы)
|
||||||
|
$ctx->setChatDataItem("request_menu", $message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = new Config();
|
||||||
|
$config->setParseMode(Config::PARSE_MODE_MARKDOWN);
|
||||||
|
|
||||||
|
$bot = new Zanzara(require(__DIR__ . '/../settings/key.php'), $config);
|
||||||
|
|
||||||
|
$stop = false;
|
||||||
|
|
||||||
|
$bot->onUpdate(function (Context $ctx) use (&$stop): void {
|
||||||
|
$message = $ctx->getMessage();
|
||||||
|
|
||||||
|
if (
|
||||||
|
isset($message)
|
||||||
|
&& ($contact = $message->getContact())
|
||||||
|
&& $contact->getUserId() === $message->getFrom()->getId()
|
||||||
|
) {
|
||||||
|
// Передан контакт со своими данными (подразумевается второй шаг аутентификации и запуск регистрации)
|
||||||
|
|
||||||
|
// Запуск регистрации
|
||||||
|
if (registration($contact->getUserId(), $contact->getPhoneNumber())) {
|
||||||
|
// Успешная регистрация
|
||||||
|
|
||||||
|
$ctx->sendMessage('✅ *Аккаунт подключен*', ['reply_markup' => ['remove_keyboard' => true]])->then(function () use ($ctx) {
|
||||||
|
generateMenu($ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
$stop = true;
|
||||||
|
} else $ctx->sendMessage('⛔ *Вы не авторизованы*', generateAuthenticationKeyboard());
|
||||||
|
} else if ($message?->getText() !== '🔐 Аутентификация' && !authorization($message?->getFrom()?->getId() ?? $ctx->getCallbackQuery()->getFrom()->getId())) {
|
||||||
|
$ctx->sendMessage('⛔ *Вы не авторизованы*', generateAuthenticationKeyboard());
|
||||||
|
|
||||||
|
$stop = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$bot->onCommand('start', function (Context $ctx) use ($stop): void {
|
||||||
|
if ($stop) return;
|
||||||
|
generateMenu($ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
$bot->onCommand('search', fn ($ctx) => search($ctx));
|
||||||
|
$bot->onCbQueryData(['search'], fn ($ctx) => search($ctx));
|
||||||
|
$bot->onCbQueryData(['requests_next'], fn ($ctx) => requests_next($ctx));
|
||||||
|
$bot->onCbQueryData(['requests_previous'], fn ($ctx) => requests_previous($ctx));
|
||||||
|
$bot->onCbQueryData(['request_choose'], fn ($ctx) => request_choose($ctx));
|
||||||
|
|
||||||
|
$bot->run();
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// Фреймворк для Viber API
|
|
||||||
use Viber\Client;
|
|
||||||
|
|
||||||
require __DIR__ . '/../../../../../../../vendor/autoload.php';
|
|
||||||
|
|
||||||
try {
|
|
||||||
$client = new Client(['token' => require('../settings/key.php')]);
|
|
||||||
$result = $client->setWebhook(require('../settings/url.php'));
|
|
||||||
echo "Установлено!\n";
|
|
||||||
} catch (Exception $e) {
|
|
||||||
echo 'Ошибка: ' . $e->getMessage() . "\n";
|
|
||||||
}
|
|
|
@ -1,478 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// Фреймворк ArangoDB
|
|
||||||
use mirzaev\arangodb\connection,
|
|
||||||
mirzaev\arangodb\collection,
|
|
||||||
mirzaev\arangodb\document;
|
|
||||||
|
|
||||||
// Библиотека для ArangoDB
|
|
||||||
use ArangoDBClient\Document as _document,
|
|
||||||
ArangoDBClient\Cursor,
|
|
||||||
ArangoDBClient\Statement as _statement;
|
|
||||||
|
|
||||||
// Фреймворк для Viber API
|
|
||||||
use Viber\Bot,
|
|
||||||
Viber\Api\Sender,
|
|
||||||
Viber\Api\Event,
|
|
||||||
Viber\Api\Keyboard,
|
|
||||||
Viber\Api\Keyboard\Button,
|
|
||||||
Viber\Api\Message\Contact,
|
|
||||||
Viber\Api\Event\Message,
|
|
||||||
Viber\Api\Message\Text;
|
|
||||||
|
|
||||||
use Monolog\Logger;
|
|
||||||
use Monolog\Handler\StreamHandler;
|
|
||||||
|
|
||||||
require __DIR__ . '/../../../../../../../vendor/autoload.php';
|
|
||||||
|
|
||||||
$arangodb = new connection(require '../settings/arangodb.php');
|
|
||||||
|
|
||||||
$botSender = new Sender([
|
|
||||||
'name' => 'Requests register',
|
|
||||||
'avatar' => 'https://developers.viber.com/img/favicon.ico',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$log = new Logger('bot');
|
|
||||||
$log->pushHandler(new StreamHandler('../bot.log'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Авторизация
|
|
||||||
*
|
|
||||||
* @param string $id Идентификатор Viber
|
|
||||||
*
|
|
||||||
* @return _document|null|false (инстанция аккаунта, если подключен и авторизован; null, если не подключен; false, если подключен но неавторизован)
|
|
||||||
*/
|
|
||||||
function authorization(string $id): _document|null|false
|
|
||||||
{
|
|
||||||
global $arangodb;
|
|
||||||
|
|
||||||
if (collection::init($arangodb->session, 'viber'))
|
|
||||||
if (
|
|
||||||
($viber = collection::search($arangodb->session, sprintf("FOR d IN viber FILTER d.id == '%s' RETURN d", $id)))
|
|
||||||
|| $viber = collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN viber FILTER d._id == '%s' RETURN d",
|
|
||||||
document::write($arangodb->session, 'viber', ['id' => $id, 'status' => 'inactive'])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ($viber->number === null) return null;
|
|
||||||
else if (
|
|
||||||
$viber->status === 'active'
|
|
||||||
&& collection::init($arangodb->session, 'workers')
|
|
||||||
&& $worker = collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN workers LET e = (FOR e IN connections FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d",
|
|
||||||
$viber->getId()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) return $worker;
|
|
||||||
else return false;
|
|
||||||
else throw new exception('Не удалось найти или создать аккаунт');
|
|
||||||
else throw new exception('Не удалось инициализировать коллекцию');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function registration(string $id, string $number): bool
|
|
||||||
{
|
|
||||||
global $arangodb;
|
|
||||||
|
|
||||||
if (collection::init($arangodb->session, 'viber')) {
|
|
||||||
// Инициализация аккаунта
|
|
||||||
if ($viber = collection::search($arangodb->session, sprintf("FOR d IN viber FILTER d.id == '%s' RETURN d", $id))) {
|
|
||||||
// Запись номера
|
|
||||||
$viber->number = $number;
|
|
||||||
if (!document::update($arangodb->session, $viber)) return false;
|
|
||||||
} else if (!collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN viber FILTER d._id == '%s' RETURN d",
|
|
||||||
document::write($arangodb->session, 'viber', ['id' => $id, 'status' => 'inactive', 'number' => $number])
|
|
||||||
)
|
|
||||||
)) return false;
|
|
||||||
else throw new exception('Не удалось создать аккаунт или записать номер в существующий');
|
|
||||||
|
|
||||||
// Инициализация ребра: workers -> viber
|
|
||||||
if (($worker = collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN workers FILTER d.phone == '%d' RETURN d",
|
|
||||||
$viber->number
|
|
||||||
)
|
|
||||||
))
|
|
||||||
&& collection::init($arangodb->session, 'connections', true)
|
|
||||||
&& (collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN connections FILTER d._from == '%s' && d._to == '%s' RETURN d",
|
|
||||||
$worker->getId(),
|
|
||||||
$viber->getId()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
?? collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN connections FILTER d._id == '%s' RETURN d",
|
|
||||||
document::write(
|
|
||||||
$arangodb->session,
|
|
||||||
'connections',
|
|
||||||
['_from' => $worker->getId(), '_to' => $viber->getId()]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
// Инициализировано ребро: workers -> viber
|
|
||||||
|
|
||||||
// Активация
|
|
||||||
$viber->status = 'active';
|
|
||||||
return document::update($arangodb->session, $viber);
|
|
||||||
}
|
|
||||||
} else throw new exception('Не удалось инициализировать коллекцию');
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateMenuKeyboard(): Keyboard
|
|
||||||
{
|
|
||||||
return (new Keyboard())
|
|
||||||
->setButtons([
|
|
||||||
(new Button())
|
|
||||||
->setBgColor('#97d446')
|
|
||||||
->setActionType('reply')
|
|
||||||
->setActionBody('btn-search')
|
|
||||||
->setText('🔍 Активные заявки')
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateNumberKeyboard(): Keyboard
|
|
||||||
{
|
|
||||||
return (new Keyboard())
|
|
||||||
->setButtons([
|
|
||||||
(new Button())
|
|
||||||
->setBgColor('#E9003A')
|
|
||||||
->setTextSize('large')
|
|
||||||
->setTextHAlign('center')
|
|
||||||
->setActionType('share-phone')
|
|
||||||
->setActionBody('reply')
|
|
||||||
->setText('🔐 Аутентификация'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function requests(int $amount = 5): Cursor
|
|
||||||
{
|
|
||||||
global $arangodb;
|
|
||||||
|
|
||||||
return (new _statement(
|
|
||||||
$arangodb->session,
|
|
||||||
[
|
|
||||||
'query' => sprintf(
|
|
||||||
"FOR d IN works FILTER d.confirmed != 'да' LIMIT %d RETURN d",
|
|
||||||
$amount
|
|
||||||
),
|
|
||||||
"batchSize" => 1000,
|
|
||||||
"sanitize" => true
|
|
||||||
]
|
|
||||||
))->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$bot = new Bot(['token' => require('../settings/key.php')]);
|
|
||||||
|
|
||||||
$bot
|
|
||||||
->onText('|btn-request-choose-*|s', function ($event) use ($bot, $botSender, $log) {
|
|
||||||
global $arangodb;
|
|
||||||
|
|
||||||
$id = $event->getSender()->getId();
|
|
||||||
|
|
||||||
if (($worker = authorization($id)) instanceof _document) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
// Инициализация ключа инстанции works в базе данных
|
|
||||||
preg_match('/btn-request-choose-(\d+)/', $event->getMessage()->getText(), $matches);
|
|
||||||
$_key = $matches[1];
|
|
||||||
|
|
||||||
// Инициализация инстанции works в базе данных (выбранного задания)
|
|
||||||
$work = collection::search($arangodb->session, sprintf("FOR d IN works FILTER d._key == '%s' RETURN d", $_key));
|
|
||||||
|
|
||||||
// Запись о том, что задание подтверждено (в будущем здесь будет отправка на потдверждение модераторам)
|
|
||||||
$work->confirmed = 'да';
|
|
||||||
|
|
||||||
if (document::update($arangodb->session, $work)) {
|
|
||||||
// Записано обновление в базу данных
|
|
||||||
|
|
||||||
if (collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN readinesses FILTER d._id == '%s' RETURN d",
|
|
||||||
document::write($arangodb->session, 'readinesses', ['_from' => $worker->getId(), '_to' => $work->getId()])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// Записано ребро: worker -> work (принятие заявки)
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText("✅ **Заявка принята:** #$_key")
|
|
||||||
->setKeyboard(generateMenuKeyboard())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ($worker === null) {
|
|
||||||
// Не подключен
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText('⚠️ **Вы не подключили аккаунт**')
|
|
||||||
->setKeyboard(generateNumberKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->onText('|btn-search|s', function ($event) use ($bot, $botSender) {
|
|
||||||
global $arangodb;
|
|
||||||
|
|
||||||
$id = $event->getSender()->getId();
|
|
||||||
|
|
||||||
if (($worker = authorization($id)) instanceof _document) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
$keyboard = [];
|
|
||||||
|
|
||||||
$requests = requests(5);
|
|
||||||
|
|
||||||
if ($requests->getCount() < 1) {
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText("📦 **Заявок нет**")
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($requests as $request) {
|
|
||||||
// Перебор найденных заявок
|
|
||||||
|
|
||||||
if (($market = collection::search(
|
|
||||||
$arangodb->session,
|
|
||||||
sprintf(
|
|
||||||
"FOR d IN markets LET e = (FOR e IN requests FILTER e._to == '%s' RETURN e._from)[0] FILTER d._id == e RETURN d",
|
|
||||||
$request->getId()
|
|
||||||
)
|
|
||||||
)) instanceof _document) {
|
|
||||||
// Найден магазин
|
|
||||||
|
|
||||||
// Отправка сообщения с данной заявки
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText("**#{$request->getKey()}**\n\n$request->date ($request->start - $request->end)\n**Работа:** \"$request->work\"\n\n**Город:** $market->city\n**Адрес:** $market->address")
|
|
||||||
);
|
|
||||||
|
|
||||||
// Запись выбора заявки в клавиатуру
|
|
||||||
$keyboard[] = (new Button())
|
|
||||||
->setBgColor(sprintf("#%02x%02x%02x", mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255)))
|
|
||||||
->setTextSize('small')
|
|
||||||
->setActionType('reply')
|
|
||||||
->setActionBody("btn-request-choose-{$request->getKey()}")
|
|
||||||
->setText("#{$request->getKey()}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText("🔍 Выберите заявку")
|
|
||||||
->setKeyboard((new Keyboard())->setButtons($keyboard ?? []))
|
|
||||||
);
|
|
||||||
} else if ($worker === null) {
|
|
||||||
// Не подключен
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText('⚠️ **Вы не подключили аккаунт**')
|
|
||||||
->setKeyboard(generateNumberKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->onText('|.*|si', function ($event) use ($bot, $botSender) {
|
|
||||||
$id = $event->getSender()->getId();
|
|
||||||
|
|
||||||
if (($worker = authorization($id)) instanceof _document) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('👋 Здравствуйте, ' . $worker->name)
|
|
||||||
->setKeyboard(generateMenuKeyboard($event))
|
|
||||||
);
|
|
||||||
} else if ($worker === null) {
|
|
||||||
// Не подключен
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText('⚠️ **Вы не подключили аккаунт**')
|
|
||||||
->setKeyboard(generateNumberKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->onConversation(function ($event) use ($bot, $botSender) {
|
|
||||||
$id = $event->getUser()->getId();
|
|
||||||
|
|
||||||
if (($worker = authorization($id)) instanceof _document) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('👋 Здравствуйте, ' . $worker->name)
|
|
||||||
->setKeyboard(generateMenuKeyboard($event))
|
|
||||||
);
|
|
||||||
} else if ($worker === null) {
|
|
||||||
// Не подключен
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText('⚠️ **Вы не подключили аккаунт**')
|
|
||||||
->setKeyboard(generateNumberKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->onSubscribe(function ($event) use ($bot, $botSender) {
|
|
||||||
$id = $event->getUser()->getId();
|
|
||||||
|
|
||||||
if (($worker = authorization($id)) instanceof _document) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('Здравствуйте, ' . $worker->name)
|
|
||||||
->setKeyboard(generateMenuKeyboard($event))
|
|
||||||
);
|
|
||||||
} else if ($worker === null) {
|
|
||||||
// Не подключен
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setMinApiVersion(3)
|
|
||||||
->setText('⚠️ **Вы не подключили аккаунт**')
|
|
||||||
->setKeyboard(generateNumberKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->on(function ($event) {
|
|
||||||
return ($event instanceof Message && $event->getMessage() instanceof Contact);
|
|
||||||
}, function ($event) use ($bot, $botSender, $log) {
|
|
||||||
$id = $event->getSender()->getId();
|
|
||||||
|
|
||||||
if (registration($id, $event->getMessage()->getPhoneNumber())) {
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('✅ **Аккаунт подключен**')
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($worker = authorization($id)) {
|
|
||||||
// Авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('👋 Здравствуйте, ' . $worker->name)
|
|
||||||
->setKeyboard(generateMenuKeyboard($event))
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Не авторизован
|
|
||||||
|
|
||||||
$bot->getClient()->sendMessage(
|
|
||||||
(new Text())
|
|
||||||
->setSender($botSender)
|
|
||||||
->setReceiver($id)
|
|
||||||
->setText('⛔️ **Вы не авторизованы**')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
->run();
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$log->warning('Exception: ' . $e->getMessage());
|
|
||||||
if ($bot) {
|
|
||||||
$log->warning('Actual sign: ' . $bot->getSignHeaderValue());
|
|
||||||
$log->warning('Actual body: ' . $bot->getInputBody());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return '';
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Telegram-robot
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=sudo -u www-data /usr/bin/php /var/www/spetsresurs-telegram-registry-requests/mirzaev/spetsresurs/telegram/registry/requests/system/public/robot.php
|
||||||
|
PIDFile=/var/run/php/telegram-robot.pid
|
||||||
|
RemainAfterExit=no
|
||||||
|
RuntimeMaxSec=3600s
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5s
|
Reference in New Issue