diff --git a/docs/source/additional.rst b/docs/source/additional.rst index 7e4de35..f742141 100644 --- a/docs/source/additional.rst +++ b/docs/source/additional.rst @@ -19,6 +19,9 @@ Dash: История изменений ---------------- +- `2022-08-01` Защита от флуда +- `2022-07-23` Автоответчик не пишет сообщение лишний раз +- `2022-07-04` Поддержка двух ботов в одном чате - `2022-06-25` Поддержка HTML\Markdown в стартовом сообщении и автоответчике - `2022-06-25` Пересылка отредактированных сообщений - `2022-06-16` User info по возможности отправляется в том же сообщении, что и сообщение пользователя diff --git a/docs/source/options.rst b/docs/source/options.rst index c4c6ec0..dead073 100644 --- a/docs/source/options.rst +++ b/docs/source/options.rst @@ -41,3 +41,11 @@ Olgram пересылает сообщения так, чтобы сообщен Включение этой опции меняет текст политики конфиденциальности вашего feedback бота (команда /security_policy) и может отпугнуть некоторых пользователей. Не включайте эту опцию без необходимости. + +.. _antiflood: + +Защита от флуда +--------------- + +При включении этой опции пользователю запрещается отправлять больше одного сообщения в минуту. Используйте её, если +не успеваете обрабатывать входящие сообщения. diff --git a/locales/en/LC_MESSAGES/olgram.po b/locales/en/LC_MESSAGES/olgram.po index 66f190d..bad1c2c 100644 --- a/locales/en/LC_MESSAGES/olgram.po +++ b/locales/en/LC_MESSAGES/olgram.po @@ -643,3 +643,9 @@ msgstr "" msgid "Не удаётся связаться с владельцем бота" msgstr "Cannot contact the owner of the bot" + +msgid "Слишком много сообщений, подождите одну минуту" +msgstr "Too many messages, wait one minute" + +msgid "Антифлуд" +msgstr "Antiflood" diff --git a/locales/uk/LC_MESSAGES/olgram.po b/locales/uk/LC_MESSAGES/olgram.po index e7f361d..c7311d2 100644 --- a/locales/uk/LC_MESSAGES/olgram.po +++ b/locales/uk/LC_MESSAGES/olgram.po @@ -654,3 +654,9 @@ msgstr "" msgid "Не удаётся связаться с владельцем бота" msgstr "Не вдається зв'язатися з власником бота" + +msgid "Слишком много сообщений, подождите одну минуту" +msgstr "Забагато повідомлень, зачекайте одну хвилину" + +msgid "Антифлуд" +msgstr "Антифлуд" diff --git a/olgram/commands/bot_actions.py b/olgram/commands/bot_actions.py index ec20f93..8bb3027 100644 --- a/olgram/commands/bot_actions.py +++ b/olgram/commands/bot_actions.py @@ -86,3 +86,8 @@ async def olgram_text(bot: Bot, call: types.CallbackQuery): if await bot.is_promo(): bot.enable_olgram_text = not bot.enable_olgram_text await bot.save(update_fields=["enable_olgram_text"]) + + +async def antiflood(bot: Bot, call: types.CallbackQuery): + bot.enable_antiflood = not bot.enable_antiflood + await bot.save(update_fields=["enable_antiflood"]) diff --git a/olgram/commands/menu.py b/olgram/commands/menu.py index 079c239..0ba160d 100644 --- a/olgram/commands/menu.py +++ b/olgram/commands/menu.py @@ -162,6 +162,11 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery): callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="additional_info", chat=empty)) ) + keyboard.insert( + types.InlineKeyboardButton(text=_("Антифлуд"), + callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="antiflood", + chat=empty)) + ) is_promo = await bot.is_promo() if is_promo: keyboard.insert( @@ -178,10 +183,12 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery): thread_turn = _("включены") if bot.enable_threads else _("выключены") info_turn = _("включены") if bot.enable_additional_info else _("выключены") + antiflood_turn = _("включен") if bot.enable_antiflood else _("выключен") text = dedent(_(""" Потоки сообщений: {0} Данные пользователя: {1} - """)).format(thread_turn, info_turn) + Антифлуд: {2} + """)).format(thread_turn, info_turn, antiflood_turn) if is_promo: olgram_turn = _("включена") if bot.enable_olgram_text else _("выключена") @@ -425,6 +432,9 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon if operation == "threads": await bot_actions.threads(bot, call) return await send_bot_settings_menu(bot, call) + if operation == "antiflood": + await bot_actions.antiflood(bot, call) + return await send_bot_settings_menu(bot, call) if operation == "additional_info": await bot_actions.additional_info(bot, call) return await send_bot_settings_menu(bot, call) diff --git a/olgram/models/models.py b/olgram/models/models.py index 6fab6ed..2209bd1 100644 --- a/olgram/models/models.py +++ b/olgram/models/models.py @@ -45,6 +45,7 @@ class Bot(Model): enable_threads = fields.BooleanField(default=False) enable_additional_info = fields.BooleanField(default=False) enable_olgram_text = fields.BooleanField(default=True) + enable_antiflood = fields.BooleanField(default=False) def decrypted_token(self): cryptor = DatabaseSettings.cryptor() diff --git a/server/custom.py b/server/custom.py index 4c8f86b..8ae69e8 100644 --- a/server/custom.py +++ b/server/custom.py @@ -46,6 +46,10 @@ def _last_message_uid(bot_id: int, chat_id: int) -> str: return f"lm_{bot_id}_{chat_id}" +def _antiflood_marker_uid(bot_id: int, chat_id: int) -> str: + return f"af_{bot_id}_{chat_id}" + + def _on_security_policy(message: types.Message, bot): _ = _get_translator(message) text = _("Политика конфиденциальности\n\n" @@ -130,6 +134,13 @@ async def handle_user_message(message: types.Message, super_chat_id: int, bot): return SendMessage(chat_id=message.chat.id, text=_("Вы заблокированы в этом боте")) + # Проверить анти-флуд + if bot.enable_antiflood: + if await _redis.get(_antiflood_marker_uid(bot.pk, message.chat.id)): + return SendMessage(chat_id=message.chat.id, + text=_("Слишком много сообщений, подождите одну минуту")) + await _redis.setex(_antiflood_marker_uid(bot.pk, message.chat.id), 60, 1) + # Пересылаем сообщение в супер-чат try: await send_to_superchat(is_super_group, message, super_chat_id, bot) @@ -144,8 +155,8 @@ async def handle_user_message(message: types.Message, super_chat_id: int, bot): # И отправить пользователю специальный текст, если он указан и если давно не отправляли if bot.second_text: - send_auto = not await _redis.get(_last_message_uid(message.bot.id, message.chat.id)) - await _redis.setex(_last_message_uid(message.bot.id, message.chat.id), 60 * 60 * 3, 1) + send_auto = not await _redis.get(_last_message_uid(bot.pk, message.chat.id)) + await _redis.setex(_last_message_uid(bot.pk, message.chat.id), 60 * 60 * 3, 1) if send_auto: return SendMessage(chat_id=message.chat.id, text=bot.second_text, parse_mode="HTML")