Merge commit '172fe23e21da2c618a1260d7f462a14cd6b62c03' into stable

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2022-11-15 09:37:00 +10:00
commit 1e2e580b7e
9 changed files with 470 additions and 138 deletions

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
/**
* Программа: "генератор кнопок"
*
* Обрабатывает "[название|авторизованные|*ролевое действие*] в кнопку и
* соответствующее ей действие или сообщение, в зависимости от параметров
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class buttons_generator extends program
{
/**
* Конструктор
*
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update, string ...$buttons): void {
var_dump($buttons); die;
}, $robot, $accounts);
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
/**
* Программа: "экранирование символов"
*
* Находит символ "\" и конвертирует следующий за ним в HTML-код
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class character_escaping extends program
{
/**
* Конструктор
*
* @param callable $program Программа выполняемая командой
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update, string ...$text): void {
// Инициализация буфера текста
$buffer = '';
// Конвертация текста
foreach ($text as $part) $buffer .= mb_substr($part, 0, 1) === '\\' ? self::convert($part = mb_substr($part, 1)) : $part;
// Запись текста из буфера в событие (для того, чтобы передать на выполнение следующим программам)
$update['object']['message']['text'] = $buffer;
}, $robot, $accounts);
}
protected static function convert(string $text): string
{
// Инициализация буфера вывода
$buffer = '';
foreach ([mb_convert_encoding($text, 'UTF-32', 'UTF-8')] as $symbol) {
// Перебор символов
$c = 0;
for ($i = 0; $i < 4; $i++) {
$c |= ord($symbol[$i]) << (8 * (3 - $i));
}
// Запись в буфер вывода
$buffer .= "&#" . $c . ";";
}
return $buffer;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
/**
* Программа: "конвертер упоминаний"
*
* Принцип работы:
*
* 1. Пользователь отправляет: "@id123456789 (Имя)"
* 2. Сервер получает: "[id123456789|Имя]"
* 3. Программа конвертирует: "[id123456789|Имя]" в "@id123456789 (Имя)"
*
* Это нужно для того, чтобы упоминание понял препроцессор ВКонтакте
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class mentions_converter extends program
{
/**
* Конструктор
*
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update): void {
// Конвертация упоминаний
$update['object']['message']['text'] = preg_replace_callback('/(*UTF8)(?=[^\[]+)[^\[]+|\[(id\d+)\|([^\]]+)\]/', fn (array $matches) => isset($matches[2]) ? '@' . $matches[1] . ' (' . $matches[2] . ')' : $matches[0] ?? $update['object']['message']['text'], $update['object']['message']['text'], 500);
}, $robot, $accounts);
}
}

View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
/**
* Программа: "ответ группе"
*
* Обрабатывает ответ напрвленный не пользователю, а группе
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class reply_to_group extends program
{
/**
* Конструктор
*
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update): void {
if (isset($update['object']['message']['reply_message'])) {
// Найдено сообщение для ответа
if ($update['object']['message']['reply_message']['from_id'] < 0) {
// Ответ на сообщение группы
// Инициализация данных аккаунта отправителя
$sender = $robot->user()->get($update['object']['message']['from_id'], name_case: 'gen');
if ($update['object']['message']['reply_message']['from_id'] === -217012993) {
// Ответ на сообщение Бобби Мирзаева
// Отправка сообщения с ролевым действием
$core->message($robot->message()->destination($update['object']['message']['peer_id'])->text("@club217012993 (Бобби) избил @id$sender->id ($sender->first_name) до полусмерти")->mentions(false));
} else if ($update['object']['message']['reply_message']['from_id'] === -191417381) {
// Ответ на сообщение Шамиля Мирзаева
// Отправка сообщения с ролевым действием
$core->message($robot->message()->destination($update['object']['message']['peer_id'])->text('Как дела, @club191417381 (брат)? Давай свалим отсюда?')->mentions(false));
} else {
// Ответ на сообщение другой группы
// Отправка сообщения с ролевым действием
$core->message($robot->message()->destination($update['object']['message']['peer_id'])->text('@club' . $update['object']['message']['reply_message']['from_id'] . ' (Слышь), здристни отсюда')->mentions(false));
}
// Завершение выполнения команд
$core->break();
return;
}
}
}, $robot, $accounts);
}
}

View File

@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
// Встроенные библиотеки
use Exception;
/**
* Программа: "ролевое действие"
*
* Удаляет запрос и отправляет в чат выполняемое действие.
* Можно использовать псевдонимы и падежи
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class roleplay_action extends program
{
/**
* Конструктор
*
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update, string $original, string $text = ''): void {
try {
// Инициализация длины сообщения
$original_length = strlen($update['object']['message']['text']);
// Инициализция длины распознанных команд
$command_length = strlen($text) + 2; // +2 это два символа "*" - особенность регулярного выражения
if (!empty($buttons)) $command_length += strlen($buttons);
if (!empty($parameters)) $command_length += strlen($parameters);
// Удаление сообщения, если в нём нет лишнего текста
if ($original_length === $command_length) $robot->message()->delete($update['object']['message']['conversation_message_id'], $update['object']['message']['peer_id']);
} catch (Exception $e) {
}
if (empty($text = trim($text))) {
// Пустой текст сообщения
// Инициализация данных аккаунта отправителя
$sender = $robot->user()->get($update['object']['message']['from_id']);
// Инициализация сообщения с ролевым действием
$core->message($robot->message()->destination($update['object']['message']['peer_id'])->text("@id$sender->id ($sender->first_name) тупит")->disable_mentions(true));
return;
}
// Инициализация индикаторов наличия изменённого псевдонима у получателя и отпрвителя
$sender_changed = $receiver_changed = false;
// Инициализация псевдонима получателя
$receiver_alias = '';
if (isset($update['object']['message']['reply_message'])) {
// Найдено сообщение для ответа
// Инициализация данных аккаунта получателя
$receiver = $robot->user()->get($update['object']['message']['reply_message']['from_id']);
if (isset($receiver)) {
// Найден получатель
// Обработка падежа получателя
$text = preg_replace_callback('/(*UTF8)^(.*)\|([^$]+)$/', function (array $matches) use ($text, &$receiver_alias, $receiver): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[2], 300);
// Инициализация псевдонима получателя
$receiver_alias = " @id$receiver->id ($receiver->first_name" . (empty($alias) ? '' : $alias) . ')';
return $matches[1] ?? $matches[0] ?? $text;
}, $text, 1);
if (empty($receiver_alias)) {
// Не найден псевдоним получателя
// Обработка псевдонима получателя
$text = preg_replace_callback('/(*UTF8)^(.*)\(([^\)]*)\)$/', function (array $matches) use ($text, &$receiver_alias, $receiver): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[2], 300);
// Инициализация псевдонима получателя
$receiver_alias = " @id$receiver->id (" . (empty($alias) ? $receiver->first_name : $alias) . ')';
return $matches[1] ?? $matches[0] ?? $text;
}, $text, 1);
}
}
// Проверка на пустого получателя
if (empty(trim($receiver_alias))) {
// Пустой текст получателя
// Реинициализация текста получателя
$receiver_alias = " @id$receiver->id ($receiver->first_name)";
} else $receiver_changed = true;
}
// Инициализация псевдонима отправителя
$sender_alias = '';
// Инициализация данных аккаунта отправителя
$sender = $robot->user()->get($update['object']['message']['from_id']);
// Обработка падежа отправителя
$text = preg_replace_callback('/(*UTF8)^\|([^\s]+)(.*)$/', function (array $matches) use ($text, $sender, &$sender_alias): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[1], 300);
// Инициализация ссылки на отправителя
$sender_alias = "@id$sender->id ($sender->first_name" . (empty($alias) ? '' : $alias) . ') ';
return $matches[2] ?? $matches[0] ?? $text;
}, $text, 1);
if (empty($sender_alias)) {
// Не найден псевдоним отправителя
// Обработка псевдонима отправителя
$text = preg_replace_callback('/(*UTF8)^\(([^\)]*)\)(.*)$/', function (array $matches) use ($text, $sender, &$sender_alias): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[1], 300);
// Инициализация ссылки на отправителя
$sender_alias = "@id$sender->id (" . (empty($alias) ? $sender->first_name : $alias) . ') ';
return $matches[2] ?? $matches[0] ?? $text;
}, $text, 1);
}
if (empty(trim($sender_alias))) {
// Пустой текст отправителя
// Реинициализация текста отправителя
$sender_alias = "@id$sender->id ($sender->first_name) ";
} else $sender_changed = true;
// Удаление команд падежей из строки
$text = preg_replace('/(*UTF8)\|[А-яё\w]+/', '', $text, 500);
// Инициализация сообщения с ролевым действием
if (empty($text = trim($text)) && !$sender_changed && !$receiver_changed) $core->message($robot->message()->destination($update['object']['message']['peer_id'])->text("@id$sender->id ($sender->first_name) тупит")->mentions(false));
else $core->message($robot->message()->destination($update['object']['message']['peer_id'])->text("$sender_alias$text$receiver_alias")->mentions(false), 'roleplay_action');
}, $robot, $accounts);
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\robot\bobby\programs;
// Фреймворк ВКонтакте
use mirzaev\vk\robots\robot;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core,
mirzaev\vk\chat\program;
// Встроенные библиотеки
use Closure,
Exception;
/**
* Программа: "переменные"
*
* Обрабатывает (название: значение) в переменные хранимые в ядре
*
* @package mirzaev\vk\robot\bobby\programs
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
class variables extends program
{
/**
* Конструктор
*
* @param callable $program Программа выполняемая командой
* @param robot $robot Робот, который будет выполнять команду
* @param array $accounts Реестр аккаунтов которым разрешено выполнять команду
*/
public function __construct(
public robot $robot,
public array $accounts = []
) {
parent::__construct(function (core $core, robot $robot, array &$update, string ...$text): void {
}, $robot, $accounts);
}
}

View File

@ -2,6 +2,15 @@
declare(strict_types=1);
// Файлы проекта
use mirzaev\vk\robot\bobby\programs\roleplay_action,
mirzaev\vk\robot\bobby\programs\character_escaping,
mirzaev\vk\robot\bobby\programs\reply_to_group,
mirzaev\vk\robot\bobby\programs\mentions_converter,
mirzaev\vk\robot\bobby\programs\variables,
mirzaev\vk\robot\bobby\programs\buttons_generator,
mirzaev\vk\robot\bobby\programs\postprocessor;
// Фреймворк ВКонтакте
use mirzaev\vk\core,
mirzaev\vk\api\longpoll;
@ -13,8 +22,7 @@ use mirzaev\arangodb\connection;
use mirzaev\vk\arangodb\longpoll as database;
// Модуль чат-робота для фреймворка ВКонтакте
use mirzaev\vk\chat\core as chat,
mirzaev\vk\chat\command;
use mirzaev\vk\chat\core as chat;
// Инициализация
defined('SYSTEM_PATH_ROOT') or define('SYSTEM_PATH_ROOT', __DIR__ . '/../');
@ -32,154 +40,45 @@ $robot = $core->group(217012993)->key('');
// Инициализация обработчика LongPoll API
$longpoll = new longpoll($robot);
// Инициализация базы данных
$database = new database(new connection(require SYSTEM_PATH_ROOT . 'settings/arangodb.php'));
// Инициализация базы данных ВКонтакте
$vk = new database(new connection(require SYSTEM_PATH_ROOT . 'settings/vk.php'));
// Очистка базы данных (тестирование)
$database->truncate();
// Инициализация базы данных Бобби
$bobby = new database(new connection(require SYSTEM_PATH_ROOT . 'settings/bobby.php'));
// Очистка базы данных ВКонтакте (тестирование)
$vk->truncate();
// Очистка базы данных Бобби (тестирование)
$bobby->truncate();
// Инициализация модуля "чат-робот"
$chat = new chat;
// Инициализация команды "ролевое действие"
$chat->pattern('/(*UTF8)^\*([^\*]*)\*$/', new command(function (array $update, string $text) use ($robot) {
try {
// Удаление сообщения
$robot->message()->delete($update['object']['message']['conversation_message_id'], $update['object']['message']['peer_id']);
} catch (Exception $e) {
}
// Инициализация программы "экранирование символов"
$chat->command('/(*UTF8)\\\[^\\\]|[^\\\]+/', new character_escaping($robot));
// Обработка ссылок на аккаунты
$text = preg_replace_callback('/(*UTF8)(?=[^\[]+)[^\[]+|\[(id\d+)\|([^\]]+)\]/', fn (array $matches) => isset($matches[2]) ? '@' . $matches[1] . ' (' . $matches[2] . ')' : $matches[0] ?? $text, $text, 500);
// Инициализация программ: "ответ на сообщение группы", "конвертация упоминаний" и "переменные"
$chat->command(
'/(*UTF8)^.*$/',
new reply_to_group($robot),
new mentions_converter($robot)
);
// Инициализация индикаторов наличия изменённого псевдонима у получателя и отпрвителя
$sender_changed = $receiver_changed = false;
// Инициализация программы "переменные"
$chat->command('/(*UTF8)^\(.*\)$/', new variables($robot));
// Инициализация псевдонима получателя
$receiver_alias = '';
// Инициализация программы "ролевое действие"
$chat->command('/(*UTF8)^\*([^\*]*)\*(?=\n|\r|$|\s*\[|\s*\()/', new roleplay_action($robot));
if (isset($update['object']['message']['reply_message'])) {
// Найдено сообщение для ответа
// Инициализация программы "генератор кнопок"
$chat->command('/(*UTF8){.+\*[^}]+\*}/', new buttons_generator($robot));
if ($update['object']['message']['reply_message']['from_id'] > 0) {
// Ответ на сообщение пользователя
// Инициализация данных аккаунта получателя
$receiver = $robot->user()->get($update['object']['message']['reply_message']['from_id']);
if (isset($receiver)) {
// Найден получатель
// Обработка падежа получателя
$text = preg_replace_callback('/(*UTF8)^(.*)\|([^$]+)$/', function (array $matches) use ($text, &$receiver_alias, $receiver): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[2], 300);
// Инициализация псевдонима получателя
$receiver_alias = " @id$receiver->id ($receiver->first_name" . (empty($alias) ? '' : $alias) . ')';
return $matches[1] ?? $matches[0] ?? $text;
}, $text, 1);
if (empty($receiver_alias)) {
// Не найден псевдоним получателя
// Обработка псевдонима получателя
$text = preg_replace_callback('/(*UTF8)^(.*)\(([^\)]*)\)$/', function (array $matches) use ($text, &$receiver_alias, $receiver): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[2], 300);
// Инициализация псевдонима получателя
$receiver_alias = " @id$receiver->id (" . (empty($alias) ? $receiver->first_name : $alias) . ')';
return $matches[1] ?? $matches[0] ?? $text;
}, $text, 1);
}
}
// Проверка на пустого получателя
if (empty(trim($receiver_alias))) {
// Пустой текст получателя
// Реинициализация текста получателя
$receiver_alias = " @id$receiver->id ($receiver->first_name)";
} else $receiver_changed = true;
} else {
// Ответ на сообщение группы (подразумевается $update['object']['message']['reply_message']['from_id'] < 0)
// Инициализация данных аккаунта отправителя
$sender = $robot->user()->get($update['object']['message']['from_id'], name_case: 'gen');
// Отправка сообщения с ролевым действием
$robot->message()->send($update['object']['message']['peer_id'], "@club217012993 (Бобби) избил @id$sender->id ($sender->first_name) до полусмерти", disable_mentions: true);
return;
}
}
// Инициализация псевдонима отправителя
$sender_alias = '';
// Инициализация данных аккаунта отправителя
$sender = $robot->user()->get($update['object']['message']['from_id']);
// Обработка падежа отправителя
$text = preg_replace_callback('/(*UTF8)^\|([^\s]+)(.*)$/', function (array $matches) use ($text, $sender, &$sender_alias): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[1], 300);
// Инициализация ссылки на отправителя
$sender_alias = "@id$sender->id ($sender->first_name" . (empty($alias) ? '' : $alias) . ') ';
return $matches[2] ?? $matches[0] ?? $text;
}, $text, 1);
if (empty($sender_alias)) {
// Не найден псевдоним отправителя
// Обработка псевдонима отправителя
$text = preg_replace_callback('/(*UTF8)^\(([^\)]*)\)(.*)$/', function (array $matches) use ($text, $sender, &$sender_alias): string {
// Инициализация псевдонима отправителя
$alias = preg_replace('/\)/', '&#41;', $matches[1], 300);
// Инициализация ссылки на отправителя
$sender_alias = "@id$sender->id (" . (empty($alias) ? $sender->first_name : $alias) . ') ';
return $matches[2] ?? $matches[0] ?? $text;
}, $text, 1);
}
if (empty(trim($sender_alias))) {
// Пустой текст отправителя
// Реинициализация текста отправителя
$sender_alias = "@id$sender->id ($sender->first_name) ";
} else $sender_changed = true;
// Удаление команд падежей из строки
$text = preg_replace('/(*UTF8)\|[А-яё\w]+/', '', $text, 500);
if (empty($text = trim($text)) && !$sender_changed && !$receiver_changed) {
// Пустой текст сообщения, а у получателя и отправителя не изменены псевдонимы
// Удаление пробела у отправителя
$sender_alias = trim($sender_alias);
// Реинициализация текста сообщения
$text = ', мне @club191417381 (Шамиля) позвать?';
}
// Отправка сообщения с ролевым действием
$robot->message()->send($update['object']['message']['peer_id'], "$sender_alias$text$receiver_alias", disable_mentions: true);
}));
$longpoll->handle(function (array $update) use ($robot, $database, $chat) {
$longpoll->handle(function (array $update) use ($robot, $vk, $bobby, $chat) {
// Обработка события
// var_dump($update);
// Сохранение события в базе данных
// $database->save($update);
// Сохранение в базе данных
$vk->save($update);
// Обработка команды
$chat->handle($update);

View File

@ -0,0 +1,8 @@
<?php
return [
'endpoint' => '',
'database' => '',
'name' => '',
'password' => ''
];