diff --git a/src/admin_commands.py b/src/admin_commands.py
index 32530b6..f79bd16 100644
--- a/src/admin_commands.py
+++ b/src/admin_commands.py
@@ -78,9 +78,7 @@ async def enable_stan(message: types.Message):
add_chat(message.chat.id, message.chat.title)
await bot.send_message(
message.chat.id,
- f"""Группа "{message.chat.title}" добавлена в БД.
-/get_group_info - узнать текущие настройки""",
- )
+ f'Группа "{message.chat.title}" добавлена в БД.\n/get_group_info - узнать текущие настройки')
else:
await bot.send_message(message.chat.id, "Отказ. Группа уже включена")
@@ -119,7 +117,7 @@ async def get_quotes(message: types.Message):
logging.info(f"[{message.chat.id}] {message.from_user.first_name} {message.text}.")
quotes = all_chat_quotes(message.chat.id)
if quotes:
- text = f"Количество цитат: {len(quotes)}\n\Последние добавленные\n\n"
+ text = f"Количество цитат: {len(quotes)}\n\nПоследние добавленные:\n\n"
text += "\n".join(f"· {quote}" for quote in quotes[-10:])
await bot.send_message(message.chat.id, f"{text}")
else:
@@ -132,17 +130,9 @@ async def get_group_info(message: types.Message):
if group:
await bot.send_message(
message.chat.id,
- f"""Группа: {group.title}
-ID группы: {group.chat_id}
-
-Количество цитат: {len(group.quotes)}
-Последние добавленные: /get_quotes
-
-Текущие настройки:
- Антиспам: {group.antispam}
- Ежедневные отчёты: {group.report}
- Праздники: {group.reminder}""",
- )
+ f"Группа: {group.title}\nID группы: {group.chat_id}\n\nКоличество цитат: {len(group.quotes)}\n"
+ f"Последние добавленные: /get_quotes\n\nТекущие настройки:\n Антиспам: {group.antispam}\n "
+ f"Ежедневные отчёты: {group.report}\n Праздники: {group.reminder}")
else:
await bot.send_message(message.chat.id, "Группа не включена. Включить: /enable_stan")
diff --git a/src/commands.py b/src/commands.py
index 1edec03..623c4e6 100644
--- a/src/commands.py
+++ b/src/commands.py
@@ -6,7 +6,7 @@ from telebot import types
from .admin_commands import bot
from .constants import (LOG_COMM, FAQ, LIB, RULES, RUS, RUS_ENG_TABLE, ENG_RUS_TABLE, PYTHONCHATRU, ZEN, LUTZ_ID,
BDMTSS_ID)
-from .filters import in_spam_list, in_caption_spam_list, in_delete_list
+from .filters import in_spam_list, in_caption_spam_list, in_delete_list, is_hello_text, is_empty_name
from .helpers import represent_as_get, detect_args, is_admin, fetch_rule
from .report import update_stats, increment
from .stan import act, speak
@@ -19,6 +19,16 @@ async def send_or_reply(message: types.Message, answer, **kwargs):
await bot.send_message(message.chat.id, answer, **kwargs)
+async def _neprivet(message: types.Message, forced_reply: bool = False):
+ markup = types.InlineKeyboardMarkup()
+ markup.add(types.InlineKeyboardButton("👋 Непривет", url="https://neprivet.com/"), row_width=1)
+ text = "Пожалуйста, не пишите просто «Привет» в чате."
+ if forced_reply:
+ await bot.reply_to(message, text, reply_markup=markup)
+ else:
+ await send_or_reply(message, text, reply_markup=markup)
+
+
""" [ ANTISPAM ] """
@@ -66,11 +76,7 @@ async def send_rules(message: types.Message):
logging.info(LOG_COMM % (message.chat.title, message.from_user.id, message.from_user.first_name, message.text))
if len(args) > 1 and args[-1].isdigit():
index = int(args[-1])
- await send_or_reply(
- message,
- f"Правило {args[-1]}\n{fetch_rule(index)}",
- reply_markup=markup,
- )
+ await send_or_reply(message, f"Правило {index}\n{fetch_rule(index)}", reply_markup=markup)
else:
await send_or_reply(message, "Читай...", reply_markup=markup)
await bot.delete_message(message.chat.id, message.id)
@@ -225,9 +231,7 @@ async def send_neprivet(message: types.Message):
message.text,
)
)
- markup = types.InlineKeyboardMarkup()
- markup.add(types.InlineKeyboardButton("👋 Непривет", url="https://neprivet.com/"), row_width=1)
- await send_or_reply(message, "Пожалуйста, не пишите просто «Привет» в чате.", reply_markup=markup)
+ await _neprivet(message)
await bot.delete_message(message.chat.id, message.id)
@@ -348,6 +352,19 @@ async def default_query(inline_query):
await bot.answer_inline_query(inline_query.id, zen, cache_time=1200)
+@bot.message_handler(func=is_empty_name, chat_types=["supergroup", "group"])
+async def handle_hello(message: types.Message):
+ await bot.delete_message(message.chat.id, message.id)
+ nick_rule = 6
+ await bot.send_message(message.chat.id, f"@{message.from_user.username}\n"
+ f"Напоминаем правило: {fetch_rule(nick_rule)}")
+
+
+@bot.message_handler(func=is_hello_text, chat_types=["supergroup", "group"])
+async def handle_hello(message: types.Message):
+ await _neprivet(message, forced_reply=True)
+
+
""" [ COUNTER ] """
diff --git a/src/constants.py b/src/constants.py
index 690b882..82c063c 100644
--- a/src/constants.py
+++ b/src/constants.py
@@ -35,6 +35,7 @@ ALLOWED_WORDS = [
"support",
"jetbrains",
]
+HELLO_EXAMPLES = ('привет', 'привет всем', 'ку', 'здравствуйте', 'прив', 'всем прив', 'ребята всем привет', 'прива')
ONLY_RUS_LETTERS = "ёйцукенгшщзхъфывапролджэячсмитьбю"
ONLY_ENG_LETTERS = string.ascii_lowercase
@@ -59,7 +60,7 @@ SPAM = {"me.sv/", "tg.sv/", "goo.by/", "go.sv/", "intim.video/", "uclck.ru/", '
'P2P', 'Идет набор', 'в лс', 'нaбop', 'комaндy', 'kpuпт', 'бupж', '💰', 'пишитe', '💸',
'$ в неделю', 'обучаю с нуля', 'доходы для всех', 'по трейдингу', 'фальшивые рубли', '‼️',
'зароботку', 'Набuраю', 'цuфр', 'Обучу вас', 'прuб', 'остались курсы', 'Crypt', 'kр', 'рu',
- 'в лc', "в личные сообщения"}
+ 'в лc', "в личные сообще"}
NON_GRATA = {"дудар", "хауди", "dudar"}
BAN_WORDS = {"GREEN"}
diff --git a/src/filters.py b/src/filters.py
index 87f68bb..2ca0be2 100644
--- a/src/filters.py
+++ b/src/filters.py
@@ -3,8 +3,8 @@ import logging.handlers
from telebot import types
from .config import WHITEIDS
-from .constants import LOG_COMM, ALLOWED_WORDS, URL_RX
-from .helpers import is_spam, is_in_not_allowed, is_ban_words_in_caption
+from .constants import LOG_COMM, ALLOWED_WORDS, URL_RX, HELLO_EXAMPLES
+from .helpers import is_spam, is_in_not_allowed, is_ban_words_in_caption, cleaned_text, remove_spaces
from .models import is_antispam_enabled
@@ -45,3 +45,12 @@ def in_delete_list(message: types.Message) -> bool:
def is_white_id(message: types.Message) -> bool:
return message.from_user.id in WHITEIDS
+
+
+def is_hello_text(message: types.Message) -> bool:
+ text = remove_spaces(cleaned_text(message.text))
+ return any(hello == text for hello in HELLO_EXAMPLES)
+
+
+def is_empty_name(message: types.Message) -> bool:
+ return message.from_user.full_name.strip() == ''
diff --git a/src/helpers.py b/src/helpers.py
index 612532d..c09bed5 100644
--- a/src/helpers.py
+++ b/src/helpers.py
@@ -30,9 +30,8 @@ def is_mixed(text: str) -> bool:
Разбивает текст на слова и проверяет на смешанный алфавит, спамеры используют его. Слово допускается только
полностью на русском или русский + знаки пунктуации
"""
- cleaned_text = ''.join(letter if letter not in SYMBOLS else ' ' for letter in text)
- for word in cleaned_text.split():
- word = word.strip().lower()
+ for word in cleaned_text(text).split():
+ word = word.strip()
if not word:
continue
if any(e in ONLY_RUS_LETTERS for e in word) and any(e in ONLY_ENG_LETTERS for e in word):
@@ -40,6 +39,14 @@ def is_mixed(text: str) -> bool:
return False
+def cleaned_text(text: str) -> str:
+ return ''.join(letter.lower() if letter not in SYMBOLS else ' ' for letter in text)
+
+
+def remove_spaces(text: str) -> str:
+ return ' '.join(word.strip() for word in text.split() if word.strip())
+
+
def is_in_not_allowed(word_list: list, msg: str) -> bool:
for word in word_list:
if word in msg.casefold():
diff --git a/tests/test_bot.py b/tests/test_bot.py
index a5d61c7..35bbafd 100644
--- a/tests/test_bot.py
+++ b/tests/test_bot.py
@@ -17,7 +17,7 @@ from src import helpers
# нужно не дать делать реальные запросы в тестах, конкретно тут -за Правилами чата
helpers.is_url_reachable = lambda a: True
from src.commands import bot
-from src.constants import BDMTSS_ID, LUTZ_ID, ADMIN_ID
+from src.constants import BDMTSS_ID, LUTZ_ID, ADMIN_ID, HELLO_EXAMPLES
from src.filters import is_white_id
# отключаем логи бота, в тестах они не нужны
@@ -45,11 +45,11 @@ def _all_nones():
shipping_query, pre_checkout_query, poll, poll_answer, my_chat_member, chat_member, chat_join_request)
-def get_update(text, reply_to=None, user_id=10):
+def get_update(text, reply_to=None, user_id=10, first_name='Some User'):
"""Хелпер, генерирующий событие обновления для бота"""
params = {'text': text}
chat = types.Chat(id=11, type='group')
- user = types.User(id=user_id, is_bot=False, first_name='Some User')
+ user = types.User(id=user_id, is_bot=False, first_name=first_name, full_name=first_name)
if reply_to:
params["reply_to_message"] = types.Message(message_id=2, from_user=user, date=None, chat=chat,
content_type='text', options={'text': reply_to}, json_string="")
@@ -155,6 +155,15 @@ class TestBot(IsolatedAsyncioTestCase):
await self.bot.process_new_updates([get_update('/neprivet', reply_to="привет всем")])
self.assertEqual(RESULTS[0][0]['text'], "Пожалуйста, не пишите просто «Привет» в чате.")
self.assertTrue("https://neprivet.com/" in RESULTS[0][0]['reply_markup'])
+ self.assertEqual(RESULTS[1][1], "deleteMessage")
+
+ async def test_neprivet_auto(self):
+ for hello in HELLO_EXAMPLES:
+ with self.subTest(f"neprivet auto {hello}"):
+ await self.bot.process_new_updates([get_update(hello)])
+ self.assertEqual(RESULTS[0][0]['text'], "Пожалуйста, не пишите просто «Привет» в чате.")
+ self.assertTrue("https://neprivet.com/" in RESULTS[0][0]['reply_markup'])
+ RESULTS.clear()
async def test_lutz(self):
await self.bot.process_new_updates([get_update('/lutz', reply_to="привет всем")])
@@ -441,8 +450,8 @@ class TestBot(IsolatedAsyncioTestCase):
async def test_get_quotes(self):
params = (
("Цитаты отсутствуют. Подробнее: /get_group_info", []),
- ("Количество цитат: 1\n\\Последние добавленные\n\n· one", ['one']),
- ("Количество цитат: 2\n\\Последние добавленные\n\n· one\n· two", ['one', 'two']),
+ ("Количество цитат: 1\n\nПоследние добавленные:\n\n· one", ['one']),
+ ("Количество цитат: 2\n\nПоследние добавленные:\n\n· one\n· two", ['one', 'two']),
)
for expected, quotes in params:
with self.subTest(f"get_quotes {quotes}"):
@@ -453,7 +462,7 @@ class TestBot(IsolatedAsyncioTestCase):
RESULTS.clear()
async def test_get_group_info(self):
- exp = f"Группа: Title\nID группы: 11 \n\nКоличество цитат: 0\nПоследние добавленные: /get_quotes\n\n" \
+ exp = f"Группа: Title\nID группы: 11\n\nКоличество цитат: 0\nПоследние добавленные: /get_quotes\n\n" \
f"Текущие настройки:\n Антиспам: 1\n Ежедневные отчёты: 1\n Праздники: 1"
params = (
("Группа не включена. Включить: /enable_stan", None),
@@ -467,6 +476,12 @@ class TestBot(IsolatedAsyncioTestCase):
self.assertEqual(expected, RESULTS[0][0]['text'])
RESULTS.clear()
+ async def test_empty_name_user(self):
+ await self.bot.process_new_updates([get_update('новый текст', first_name='')])
+ self.assertEqual(RESULTS[0], ({'chat_id': 11, 'message_id': 1}, 'deleteMessage'))
+ self.assertEqual(RESULTS[1][1], 'sendMessage')
+ self.assertEqual(RESULTS[1][0]['text'], '@None\nНапоминаем правило: Твой ник должен быть читаемым и понятным')
+
if __name__ == '__main__':
main()
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
index a1540aa..4fd6c15 100644
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -1,12 +1,14 @@
from unittest import TestCase, main
from unittest.mock import MagicMock
from src.constants import SPAM, BAN_WORDS, ADMIN_ID, RULES_TEXT
-from src.helpers import is_spam, is_mixed, is_ban_words_in_caption, is_in_not_allowed, is_nongrata, is_admin, fetch_rule
+from src.helpers import is_spam, is_mixed, is_ban_words_in_caption, is_in_not_allowed, is_nongrata, is_admin, \
+ fetch_rule, cleaned_text, remove_spaces
CASES = (
"Оформим резидeнтствo ОАЭ без предoплаты за 5000 дирхам. Пoдробнoсти в лc",
"Всем привет Я в поисках людей в kpиптo кoмaнду У нас вы пройдете 6ecплaтноe обученue 1-3 дня Можно совмещать с основной paбoтoй",
"Здравствуйте! Нужны 2 человека от 200 $/день. Можно без опыта Пишите в личные сообщения +",
+ "Здравствуйте!Нужны 2 человека от 200 $/день.Пишите в личные сообщение +"
)
@@ -44,7 +46,6 @@ class TestSpam(TestCase):
self.assertFalse(is_mixed("text='слово'"))
-
class TestOthers(TestCase):
def test_ban(self):
for word in BAN_WORDS:
@@ -86,7 +87,7 @@ class TestOthers(TestCase):
self.assertEqual(is_admin(m), expected)
def test_fetch_rule(self):
- for index, text in enumerate(RULES_TEXT,1):
+ for index, text in enumerate(RULES_TEXT, 1):
with self.subTest(f"fetch rule {index}"):
self.assertEqual(fetch_rule(index), text)
@@ -94,6 +95,26 @@ class TestOthers(TestCase):
self.assertEqual(fetch_rule(0), 'Пока не придумали')
self.assertEqual(fetch_rule(100), 'Пока не придумали')
+ def test_cleaned_text(self):
+ params = (
+ ('f1 b2 print text ', 'f1!, b2# print("text")'),
+ ('text', 'text'),
+ (' ', '!@#$'),
+ )
+ for expected, text in params:
+ with self.subTest(f"cleaned_text {text}"):
+ self.assertEqual(expected, cleaned_text(text))
+
+ def test_remove_spaces(self):
+ params = (
+ ('f1 b2 print text', 'f1 b2 print text '),
+ ('text', 'text'),
+ ('!@#$', '!@#$'),
+ )
+ for expected, text in params:
+ with self.subTest(f"remove_spaces {text}"):
+ self.assertEqual(expected, remove_spaces(text))
+
if __name__ == '__main__':
main()