This repository has been archived on 2024-10-16. You can view files and clone it, but cannot push or open issues or pull requests.
spetsresurs-viber-registry-.../mirzaev/spetsresurs/viber/registry/requests/system/public/robot.php

545 lines
16 KiB
PHP
Executable File
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.

<?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\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('../logs/robot.txt'));
/**
* Авторизация
*
* @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;
// Инициализация ребра: workers -> viber
if (
collection::init($arangodb->session, 'workers')
&& ($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-1')
->setText('🔍 Активные заявки')
]);
}
function generateNumberKeyboard(): Keyboard
{
return (new Keyboard())
->setButtons([
(new Button())
->setBgColor('#E9003A')
->setTextSize('large')
->setTextHAlign('center')
->setActionType('share-phone')
->setActionBody('reply')
->setText('🔐 Аутентификация'),
]);
}
function generateEmojis(): string
{
return '&#' . hexdec(trim(array_rand(file(__DIR__ . '/../emojis.txt')))) . ';';
}
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.date >= '%s' && d.date <= '%s' && d.worker == '' && d.confirmed != 'да' SORT d.created DESC LIMIT %d, %d RETURN d",
(new DateTime('now'))->setTime(7, 0)->format('d.m.Y'),
(new DateTime('tomorrow'))->setTime(7, 0)->format('d.m.Y'),
$offset,
$amount + $offset
),
"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) {
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 = 'да';
// Запись о том, что необходимо перенести изменения в 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 (принятие заявки)
$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;
// Инициализация номера страницы
preg_match('/btn-search-(\d+)/', $event->getMessage()->getText(), $matches);
$page = $matches[1] ?? 1;
$id = $event->getSender()->getId();
if (($worker = authorization($id)) instanceof _document) {
// Авторизован
// Поиск заявок из базы данных
$requests = requests(6, $page);
// Подсчёт количества прочитанных заявок из базы данных
$count = $requests->getCount();
// Проверка существования избытка
$excess = $count % 6 === 0;
// Обрезка заявок до размера страницы
$requests = array_slice($requests->getAll(), 0, 5);
if ($count === 0) {
$bot->getClient()->sendMessage(
(new Text())
->setSender($botSender)
->setReceiver($id)
->setText("📦 **Заявок нет**")
);
return;
}
// Инициализация буфера клавиатуры для ответа
$keyboard = [];
// Генерация кнопки: "Следующая страница"
if ($excess) $keyboard[] = (new Button())
->setBgColor('#dce537')
->setTextSize('large')
->setActionType('reply')
->setActionBody('btn-search-' . $page + 1)
->setText('Следующая страница');
// Генерация кнопки: "Предыдущая страница"
if ($page > 1) $keyboard[] =
(new Button())
->setBgColor('#dce537')
->setTextSize('large')
->setActionType('reply')
->setActionBody('btn-search-' . $page - 1)
->setText('Предыдущая страница');
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) {
// Найден магазин
// Генерация эмодзи
/* $emoji = generateEmojis(); */
// Отправка сообщения с данной заявки
$bot->getClient()->sendMessage(
(new Text())
->setSender($botSender)
->setReceiver($id)
->setText("**#{$request->getKey()}**\n\n" . ($request->date['converted'] ?? $request->date) . " (" . ($request->start['converted'] ?? $request->start) . " - " . ($request->end['converted'] ?? $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('large')
->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) {
$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('⛔ **Вы не авторизованы**')
);
}
} 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());
}
}