huesos/mirzaev/arming_bot/system/models/telegram.php

704 lines
20 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
declare(strict_types=1);
namespace mirzaev\arming_bot\models;
// Files of the project
use mirzaev\arming_bot\models\core,
mirzaev\arming_bot\controllers\core as controller,
mirzaev\arming_bot\models\catalog,
mirzaev\arming_bot\models\suspension,
mirzaev\arming_bot\models\account,
mirzaev\arming_bot\models\enumerations\language,
mirzaev\arming_bot\models\enumerations\currency;
// Framework for Telegram
use Zanzara\Zanzara,
Zanzara\Context as context,
Zanzara\Telegram\Type\Input\InputFile,
Zanzara\Telegram\Type\File\Document as telegram_document,
Zanzara\Middleware\MiddlewareNode as Node,
Zanzara\Telegram\Type\User as user;
/**
* Model of chat (telegram)
*
* @package mirzaev\arming_bot\models
*
* @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
*/
final class telegram extends core
{
/**
* Экранирование символов для Markdown
*
* @param string $text Текст для экранирования
* @param array $exception Символы которые будут исключены из списка для экранирования
*
* @return string Экранированный текст
*/
public static function unmarkdown(string $text, array $exceptions = []): string
{
// Инициализация реестра символом для конвертации
$from = array_diff(
[
'#',
'*',
'_',
'=',
'.',
'[',
']',
'(',
')',
'-',
'>',
'<',
'!',
'`'
],
$exceptions
);
// Инициализация реестра целей для конвертации
$to = [];
foreach ($from as $symbol) $to[] = "\\$symbol";
// Конвертация и выход (успех)
return str_replace($from, $to, $text);
}
/**
* Инициализация запчасти
*
* Проверяет существование запчасти
*
* @param string $spare Запчасть
*
* @return string|bool Запчасть, если найдена, иначе false
*/
public static function spares(string $spare): string|bool
{
// Поиск запчастей и выход (успех)
return match (mb_strtolower($spare)) {
'цевьё' => 'Цевьё',
default => false
};
}
/**
* Главное меню
*
* Команда: /start
*
* @param context $ctx
*
* @return void
*/
public static function menu(context $ctx): void
{
// Инициализация клавиатуры
$keyboard = [
[
['text' => '🛒 Каталог', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy']]
],
[
['text' => '🏛️ О компании'],
['text' => '💬 Контакты']
],
[
['text' => '🎯 Сообщество']
]
];
if ($ctx->get('account')?->access['settings']) $keyboard[] = [['text' => '⚙️ Настройки']];
// Отправка сообщения
$ctx->sendMessage(
static::unmarkdown(<<<TXT
Это сообщение будет отображаться (оно должно быть обязательно) при вызове главного меню командой /start (создаёт кнопки меню снизу)
TXT),
[
'reply_markup' => [
'keyboard' => $keyboard,
'resize_keyboard' => true
],
'disable_notification' => true
]
);
}
/**
* Начало работы с чат-роботом
*
* Команда: /start
*
* @param context $ctx
*
* @return void
*/
public static function start(context $ctx): void
{
// Главное меню
static::menu($ctx);
}
/**
* Контакты
*
* Команда: /contacts
*
* @param context $ctx
*
* @return void
*/
public static function contacts(context $ctx): void
{
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown(<<<TXT
Здесь придумать текст для раздела "Контакты"
TXT), [
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '⚡ Связь с менеджером', 'url' => 'https://t.me/iarming'],
],
[
['text' => '📨 Почта', 'callback_data' => 'mail']
],
[
['text' => '🪖 Сайт', 'url' => 'https://arming.ru'],
['text' => '🛒 Wildberries', 'url' => 'https://www.wildberries.ru/seller/137386'],
['text' => '🛒 Ozon', 'url' => 'https://www.ozon.ru/seller/arming-1086587/products/?miniapp=seller_1086587'],
]
]
],
'link_preview_options' => [
'is_disabled' => true
],
'disable_notification' => true
]);
}
/**
* Почта
*
* @param context $ctx
*
* @return void
*/
public static function _mail(context $ctx): void
{
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown(<<<TXT
[info@arming.ru](mailto::info@arming.ru)
TXT, ['[', ']', '(', ')']), [
'link_preview_options' => [
'is_disabled' => true
],
'disable_notification' => true
]);
}
/**
* Компания
*
* Команда: /company
*
* @param context $ctx
*
* @return void
*/
public static function company(context $ctx): void
{
// Отправка сообщения
$ctx->sendMessage(
static::unmarkdown(<<<TXT
Здесь придумать текст для раздела "Компания"
TXT),
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '📄 Публичная оферта', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy/offer']],
]
]
],
'link_preview_options' => [
'is_disabled' => true
]
]
);
}
/**
* Сообщество
*
* Команда: /community
*
* @param context $ctx
*
* @return void
*/
public static function community(context $ctx): void
{
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown(<<<TXT
Здесь придумать текст для раздела "Сообщество"
TXT), [
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '💬 Основной чат', 'url' => 'https://t.me/arming_zone'],
]
]
],
'link_preview_options' => [
'is_disabled' => true
],
'disable_notification' => true
]);
}
/**
* Настройки (доступ только авторизованным)
*
* Команда: /settings
*
* @param context $ctx
*
* @return void
*/
public static function settings(context $ctx): void
{
if ($ctx->get('account')?->access['settings']) {
// Авторизован доступ к настройкам
// Отправка сообщения
$ctx->sendMessage(
static::unmarkdown(<<<TXT
Панель управления чат-роботом ARMING
TXT),
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '📦 Импорт товаров', 'callback_data' => 'import_request'],
]
]
],
'link_preview_options' => [
'is_disabled' => true
],
'disable_notification' => true
]
);
} else {
// Не авторизован доступ к настройкам
// Отправка сообщения
$ctx->sendMessage('⛔ *Нет доступа*');
}
}
/**
* Запросить файл для импорта товаров (доступ только авторизованным)
*
* @param context $ctx
*
* @return void
*/
public static function import_request(context $ctx): void
{
if ($ctx->get('account')?->access['settings']) {
// Авторизован доступ к настройкам
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров'))
->then(function ($message) use ($ctx) {
// Отправка файла
$ctx->sendDocument(new InputFile(CATALOG_EXAMPLE), ['disable_notification' => true]);
// Импорт файла
$ctx->nextStep([static::class, 'import'], true);
});
} else {
// Не авторизован доступ к настройкам
// Отправка сообщения
$ctx->sendMessage('⛔ *Нет доступа*');
}
}
/**
* Импорт товаров (доступ только авторизованным)
*
* @param context $ctx
*
* @return void
*/
public static function import(context $ctx): void
{
if (($account = $ctx->get('account'))?->access['settings']) {
// Авторизован доступ к настройкам
// Инициализация документа
$document = $ctx->getMessage()?->getDocument();
if ($document instanceof telegram_document) {
// Инициализирован документ
// Инициализация файла
$ctx->getFile($document->getFileId())->then(function ($file) use ($ctx, $document, $account) {
if ($file->getFileSize() <= 50000000) {
// Не превышает 50 мегабайт (50 000 000 байт) размер файла
if (pathinfo(parse_url($file->getFilePath())['path'], PATHINFO_EXTENSION) === 'xlsx') {
// Имеет расширение xlsx файл
// Initializing the directory in the storage
if (!file_exists($storage = STORAGE . DIRECTORY_SEPARATOR . 'import' . DIRECTORY_SEPARATOR . $account->getKey() . DIRECTORY_SEPARATOR . time()))
mkdir($storage, 0775, true);
// Сохранение файла
file_put_contents(
$import = $storage . DIRECTORY_SEPARATOR . 'import.xlsx',
file_get_contents('https://api.telegram.org/file/bot' . KEY . '/' . parse_url($file->getFilePath())['path'])
);
// Отправка сообщения
$ctx->sendMessage(sprintf(
<<<'TXT'
🔬 *Выполняется анализ:* %s \(%s байт\)
TXT,
static::unmarkdown($document->getFileName()),
static::unmarkdown((string) $file->getFileSize())
))
->then(function ($message) use ($ctx, $import) {
// Инициализация счётчика загруженных товаров
$categories_loaded
= $products_loaded
= $categories_created
= $products_created
= $categories_updated
= $products_updated
= $categories_deleted
= $products_deleted
= $categories_old
= $products_old
= $categories_new
= $products_new
= 0;
// Import
catalog::import(
$import,
$categories_loaded,
$categories_created,
$categories_updated,
$categories_deleted,
$categories_old,
$categories_new,
$products_loaded,
$products_created,
$products_updated,
$products_deleted,
$products_old,
$products_new,
language: $account->language ?? settings::active()?->language ?? language::en, // @todo add languages
currency: $account->currency ?? settings::active()?->currency ?? currency::usd // @todo add currencies
);
// Отправка сообщения
$ctx->sendMessage(<<<TXT
🏷 *Категории*
*Загружено:* $categories_loaded
*Добавлено:* $categories_created
*Обновлено:* $categories_updated
*Удалено:* $categories_deleted
*Было:* $categories_old
*Стало:* $categories_new
TXT)
->then(function ($message) use ($ctx, $products_loaded, $products_created, $products_updated, $products_deleted, $products_old, $products_new) {
$ctx->sendMessage(<<<TXT
📦 *Товары*
*Загружено:* $products_loaded
*Добавлено:* $products_created
*Обновлено:* $products_updated
*Удалено:* $products_deleted
*Было:* $products_old
*Стало:* $products_new
TXT)
->then(function ($message) use ($ctx) {
// Завершение диалога
$ctx->endConversation();
});
});
});
} else {
// Не имеет расширение xlsx файл
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown('Файл должен иметь расширение xlsx'));
}
} else {
// Превышает 50 мегабайт (50000000 байт) размер файла
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown('Размер файла не должен превышать 50 мегабайт'));
}
});
} else {
// Не инициализирован документ
// Отправка сообщения
$ctx->sendMessage(static::unmarkdown('Отправьте документ в формате xlsx со списком товаров'));
}
} else {
// Не авторизован доступ к настройкам
// Отправка сообщения
$ctx->sendMessage('⛔ *Нет доступа*');
}
}
/**
* Инициализация аккаунта (middleware)
*
* @param context $ctx
* @param Node $next
*
* @return void
*/
public static function account(context $ctx, Node $next): void
{
// Выполнение заблокировано?
if ($ctx->get('stop')) return;
// Инициализация аккаунта Telegram
$telegram = $ctx->getEffectiveUser();
// Инициализация аккаунта
$account = account::initialize($telegram->getId(), $telegram);
if ($account) {
// Инициализирован аккаунт
if ($account->banned) {
// Заблокирован аккаунт
// Отправка сообщения
$ctx->sendMessage('⛔ *Ты заблокирован*')
->then(function ($message) use ($ctx) {
// Завершение диалога
$ctx->endConversation();
});
// Блокировка дальнейшего выполнения
$ctx->set('stop', true);
} else {
// Не заблокирован аккаунт
// Запись в буфер
$ctx->set('account', $account);
// Продолжение выполнения
$next($ctx);
}
} else {
// Не инициализирован аккаунт
}
}
/**
* Инициализация статуса технических работ (middleware)
*
* @param context $ctx
* @param Node $next
*
* @return void
*/
public static function suspension(context $ctx, Node $next): void
{
// Выполнение заблокировано?
if ($ctx->get('stop')) return;
// Поиск технических работ
$suspension = suspension::search();
if ($suspension && $suspension->targets['telegram-robot']) {
// Найдена активная приостановка
// Инициализация аккаунта
$account = $ctx->get('account');
if ($account) {
// Инициализирован аккаунт
foreach ($suspension->access as $type => $status) {
// Перебор статусов доступа
if ($status && $account->{$type}) {
// Авторизован аккаунт
// Продолжение выполнения
$next($ctx);
// Выход (успех)
return;
}
}
}
// Инициализация сообщения
$message = "⚠️ *Работа приостановлена*\n*Оставшееся время\:* " . $suspension->message($account->language ?? settings::active()?->language ?? 'en');
// Добавление описания причины приостановки, если найдена
if (!empty($suspension->description))
$message .= "\n\n" . $suspension->description[$account->language ?? settings::active()?->language ?? 'en'] ?? array_values($suspension->description)[0];
// Отправка сообщения
$ctx->sendMessage($message)
->then(function ($message) use ($ctx) {
// Завершение диалога
$ctx->endConversation();
});
// Блокировка дальнейшего выполнения
$ctx->set('stop', true);
} else {
// Не найдена активная приостановка
// Продолжение выполнения
$next($ctx);
}
}
/**
* Cart attach
*
* @param context $ctx
* @param string $share Sharing hash
*
* @return void
*/
public static function cart_attach(context $ctx, string $share): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
// Initializing cart
$cart = cart::_read(
filter: 'd.share == @share',
sort: 'd.updated DESC, d.created DESC, d._key DESC',
amount: 1,
page: 1,
parameters: ['share' => $share]
);
// Deinitializing unnecessary variables
unset($share);
// Unsharing the cart
$cart->unshare();
if ($cart instanceof cart) {
// Initialized the cart
// Connecting the cart to the account
$edge = $account->connect($cart);
if (!empty($edge)) {
// Connected the cart to the account
// Initializing products in the cart
$products = $cart->products(language: $account->language ?? language::ru, currency: $account->currency ?? currency::rub);
if (!empty($products)) {
// Initialized products in the cart
// Declaring total cost of products
$cost = 0;
// Declaring formatted list of products for message
$list = '';
// Initializing iterator of rows
$row = 0;
foreach ($products as $product) {
// Iterating over products
// Generating formatted list of products for message
$list .= static::unmarkdown(++$row . '. ' . $product['document']['name'] . ' (' . $product['amount'] . 'шт)') . "\n";
// Generating total cost of products
$cost += $product['document']['cost'] * $product['amount'];
}
// Deinitializing unnecessary variables
unset($products, $product, $row);
// Initializing currency symbol
$symbol = ($account->currency ?? currency::rub)->symbol();
// Initializing delivery cost for message
$delivery_cost = $cart->buffer['delivery']['cost'];
// Initializing delivery days for message
$delivery_days = $cart->buffer['delivery']['days'];
// Initializing delivery address for message
$delivery_address = $cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street'];
// Deinitializing unnecessary variables
unset($cart);
$ctx->sendMessage(
<<<TXT
🛒 *Добавлена корзина*
$list
*Стоимость:* $cost$symbol \+ $delivery_cost$symbol \($delivery_days дней\)
*Адрес доставки:* $delivery_address
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
/* ['text' => '🧾 Оплатить', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy']] */
['text' => '📦 Оформить заказ', 'url' => 'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=demo&OutSum=11&Description=Покупка в демо магазине&SignatureValue=2c113e992e2c985e43e348ff3c12f32b'],
]
],
'disable_notification' => true
]
]
);
}
// Deinitializing unnecessary variables
unset($cart, $list);
}
}
// Deinitializing unnecessary variables
unset($cart);
}
// Deinitializing unnecessary variables
unset($account);
}
}