From fbac4a31f490a5ea5f001c68f942bddb66e03333 Mon Sep 17 00:00:00 2001 From: Picred Date: Sat, 21 Oct 2023 00:37:15 +0200 Subject: [PATCH 1/4] refactor: changed general project tree --- .github/workflows/ci.yml | 2 +- README.md | 2 +- {src => data}/welcome.json | 0 main.py | 16 +++++++++++++ module/commands/welcome.py | 28 +++++++++++++++++++++++ module/shared.py | 4 ++++ requirements.txt | 2 +- src/__init__.py | 0 src/main.py | 46 -------------------------------------- tests/main_test.py | 2 +- 10 files changed, 52 insertions(+), 50 deletions(-) rename {src => data}/welcome.json (100%) create mode 100644 main.py create mode 100644 module/commands/welcome.py create mode 100644 module/shared.py delete mode 100644 src/__init__.py delete mode 100644 src/main.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da360a3..b37fa16 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: if [ -f requirements_dev.txt ]; then pip install -r requirements_dev.txt; fi - name: Test with pytest run: | - pytest --cov src tests/ --cov-fail-under=100 --cov-report xml + pytest --cov . tests/ - name: Upload to CodeCoverage uses: codecov/codecov-action@v2 with: diff --git a/README.md b/README.md index 430566f..5e7f4bd 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Just set a `QDBotToken` env variable, this is your bot token obtained from [BotF ### Example in bash ```bash -export QDBotToken="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" # Your bot token +export TOKEN="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" # Your bot token ``` ## Write Unit Tests diff --git a/src/welcome.json b/data/welcome.json similarity index 100% rename from src/welcome.json rename to data/welcome.json diff --git a/main.py b/main.py new file mode 100644 index 0000000..a4713b7 --- /dev/null +++ b/main.py @@ -0,0 +1,16 @@ +from os import getenv +from telegram.ext import MessageHandler, Updater, Filters +from module.commands.welcome import send_welcome + +def main() -> None: + TOKEN = getenv("TOKEN") + updater = Updater(TOKEN, use_context=True) + dp = updater.dispatcher + + dp.add_handler(MessageHandler(Filters.status_update.new_chat_members, send_welcome)) + + updater.start_polling() + updater.idle() + +if __name__ == '__main__': + main() diff --git a/module/commands/welcome.py b/module/commands/welcome.py new file mode 100644 index 0000000..3d50da3 --- /dev/null +++ b/module/commands/welcome.py @@ -0,0 +1,28 @@ +from telegram import Update, User +from telegram.ext import CallbackContext +from module.shared import welcome +from random import randrange + + +def get_new_user_name(user: User) -> str: + return f"@{user['username']}" if user['username'] is not None else user['first_name'] + + +def generate_welcome(new_member: User) -> str: + new_member_username = get_new_user_name(new_member) + + match new_member["language_code"]: + case "en": + lan_code = "en" + case "it" | _ : + lan_code = "it" + + wlc_mess_list = welcome[lan_code] + + return wlc_mess_list[randrange(0, len(wlc_mess_list))].replace("USER", new_member_username) + + +def send_welcome(update: Update, _: CallbackContext) -> None: + for new_member in update['message']['new_chat_members']: + if not new_member['is_bot']: + update.message.reply_text(f'{generate_welcome(new_member)}') diff --git a/module/shared.py b/module/shared.py new file mode 100644 index 0000000..dfb5180 --- /dev/null +++ b/module/shared.py @@ -0,0 +1,4 @@ +from json import load + +with open("data/welcome.json", "r") as f: + welcome = load(f) diff --git a/requirements.txt b/requirements.txt index f7d1183..eb70bfe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -python-telegram-bot == 20.0a0 +python-telegram-bot==13.8.1 diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/main.py b/src/main.py deleted file mode 100644 index 2288e6e..0000000 --- a/src/main.py +++ /dev/null @@ -1,46 +0,0 @@ -from os import getenv -from telegram import Update, User -from telegram.ext import ApplicationBuilder, MessageHandler, CallbackContext, filters -from json import load -from random import randrange - - -def get_new_user_name(user: User) -> str: - return f"@{user['username']}" if user['username'] is not None else user['first_name'] - - -def generate_welcome(new_member: User) -> str: - new_member_username = get_new_user_name(new_member) - - match new_member["language_code"]: - case "en": - lan_code = "en" - case "it" | _ : - lan_code = "it" - - with open("src/welcome.json", "r") as f: - wlc_mess_list = load(f)[lan_code] - - return wlc_mess_list[randrange(0, len(wlc_mess_list))].replace("USER", new_member_username) - - -async def send_welcome(update: Update, _: CallbackContext) -> None: - for new_member in update['message']['new_chat_members']: - if not new_member['is_bot']: - await update.message.reply_text(f'{generate_welcome(new_member)}') - -def main() -> None: - token = getenv("QDBotToken") - app = ApplicationBuilder().token(token).build() - app.add_handler(MessageHandler( - filters.ChatType.GROUPS & filters.StatusUpdate.NEW_CHAT_MEMBERS, - send_welcome - )) - app.run_polling() - - -def init() -> None: - if __name__ == '__main__': - main() - -init() diff --git a/tests/main_test.py b/tests/main_test.py index 9b602fd..40b79b4 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -3,7 +3,7 @@ from telegram import Message, Chat from telegram.ext import Application from datetime import datetime -import src.main as main +import main as main def get_wel(lan_code: str) -> str: From 186a8b3d0664e1c1253eb138b1df32ca76582843 Mon Sep 17 00:00:00 2001 From: Andrei <102211437+Picred@users.noreply.github.com> Date: Sat, 21 Oct 2023 00:38:46 +0200 Subject: [PATCH 2/4] docs: updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e7f4bd..388be1b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A simple Telegram bot built with [python-telegram-bot](https://python-telegram-b It simply sends a randomized welcome message from a pre-defined message list each time a new user joins a specific group. ## How to use? -Just set a `QDBotToken` env variable, this is your bot token obtained from [BotFather](https://t.me/botfather) +Just set a `TOKEN` env variable, this is your bot token obtained from [BotFather](https://t.me/botfather) ### Example in bash ```bash @@ -33,4 +33,4 @@ To add a new unit test without mocking, there are some examples at the beginning If is necessary one or more mock(s), it's possible to append three more keys to the unit test. The test should have the same keys with three more keys: - `mock_obj`: it's a list of the objects in which there are the functions to mock. In our examples they often refer to the main object (the one imported from src.main) - `mock_func`: an array of strings, it indicates the functions to mock -- `mock_ret`: a list of the returned values \ No newline at end of file +- `mock_ret`: a list of the returned values From c2b5def149b87a8925866d339e136b4c92107ee0 Mon Sep 17 00:00:00 2001 From: Picred Date: Sat, 21 Oct 2023 09:04:07 +0200 Subject: [PATCH 3/4] feat: welcome message enhancement --- data/welcome.json | 9 ++++++++- module/commands/welcome.py | 14 +++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/data/welcome.json b/data/welcome.json index 35a6bae..cf8a575 100644 --- a/data/welcome.json +++ b/data/welcome.json @@ -1,4 +1,11 @@ { "it": ["Benvenuto USER nel nostro gruppo ^-^","Ciao USER!","Salve USER!"], - "en": ["Welcome USER to our group ^-^","Hello USER!","Howdy USER!"] + "en": ["Welcome USER to our group ^-^","Hello USER!","Howdy USER!"], + "readme": "https://t.me/c/1095167198/67194", + "utils": [ + "Se hai idee o suggerimenti, condividili con noi. Siamo aperti a nuove prospettive!", + "Non esitare a fare domande se hai bisogno di aiuto.", + "Speriamo che ti possa sentire come a casa tua.", + "Ricorda di rispettare le opinioni degli altri membri, anche se non sempre concordi. La diversità ci arricchisce." + ] } \ No newline at end of file diff --git a/module/commands/welcome.py b/module/commands/welcome.py index 3d50da3..4e80358 100644 --- a/module/commands/welcome.py +++ b/module/commands/welcome.py @@ -23,6 +23,14 @@ def generate_welcome(new_member: User) -> str: def send_welcome(update: Update, _: CallbackContext) -> None: - for new_member in update['message']['new_chat_members']: - if not new_member['is_bot']: - update.message.reply_text(f'{generate_welcome(new_member)}') + if update.message.new_chat_members: + for new_member in update.message.new_chat_members: + if not new_member.is_bot: + handle_welcome(update, new_member) + + +def handle_welcome(update: Update, new_member: User) -> None: + welcome_msg = f'{generate_welcome(new_member)}\n' + \ + f"- Dai un'occhiata al [README]({welcome['readme']})\n" + \ + f"- {welcome['utils'][randrange(0, len(welcome['utils']))]}" + update.message.reply_markdown(welcome_msg, disable_web_page_preview=True) From b1c0130a224d6295e23ecc10e9104565facbdbcb Mon Sep 17 00:00:00 2001 From: Andrei <102211437+Picred@users.noreply.github.com> Date: Tue, 24 Oct 2023 13:31:16 +0000 Subject: [PATCH 4/4] test: test adapting --- tests/main_test.py | 58 +++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/tests/main_test.py b/tests/main_test.py index 40b79b4..a269b6b 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -1,44 +1,44 @@ import pytest from pytest_mock import MockerFixture -from telegram import Message, Chat -from telegram.ext import Application +from telegram import Message, Chat, User, Update +from telegram.ext import Updater from datetime import datetime -import main as main +from main import main +from module.shared import welcome +from module.commands.welcome import send_welcome, generate_welcome, get_new_user_name def get_wel(lan_code: str) -> str: + wlc_mess_list = welcome[lan_code] - with open("src/welcome.json", "r") as f: - wlc_mess_list = main.load(f)[lan_code] - #first element of the list return wlc_mess_list[0].replace("USER","@user") possible_users = [ - main.User(id=0, first_name='user', is_bot=True, username='user'), # bot with username - main.User(id=0, first_name='user', is_bot=True), # bot without username - main.User(id=0, first_name='user', is_bot=False, username='user'), # user with username - main.User(id=0, first_name='user', is_bot=False), # user without username - main.User(id=0, first_name='user', is_bot=False, username='user', language_code='it'), # italian user - main.User(id=0, first_name='user', is_bot=False, username='user', language_code='en') # english user (same codepath as language_code=None) + User(id=0, first_name='user', is_bot=True, username='user'), # bot with username + User(id=0, first_name='user', is_bot=True), # bot without username + User(id=0, first_name='user', is_bot=False, username='user'), # user with username + User(id=0, first_name='user', is_bot=False), # user without username + User(id=0, first_name='user', is_bot=False, username='user', language_code='it'), # italian user + User(id=0, first_name='user', is_bot=False, username='user', language_code='en') # english user (same codepath as language_code=None) ] tests = [ - {'func': main.get_new_user_name, 'expected_res': '@user', 'arg': (possible_users[0],)}, - {'func': main.get_new_user_name, 'expected_res': 'user', 'arg': (possible_users[1],)}, - {'func': main.get_new_user_name, 'expected_res': '@user', 'arg': (possible_users[2],)}, - {'func': main.get_new_user_name, 'expected_res': 'user', 'arg': (possible_users[3],)}, + {'func': get_new_user_name, 'expected_res': '@user', 'arg': (possible_users[0],)}, + {'func': get_new_user_name, 'expected_res': 'user', 'arg': (possible_users[1],)}, + {'func': get_new_user_name, 'expected_res': '@user', 'arg': (possible_users[2],)}, + {'func': get_new_user_name, 'expected_res': 'user', 'arg': (possible_users[3],)}, { - 'func': main.send_welcome, + 'func': send_welcome, 'expected_res': None, - 'arg': (main.Update(0, message=Message(0, new_chat_members=possible_users, chat=Chat(0, type='GROUP'), date=datetime.now())), None), + 'arg': (Update(0, message=Message(0, new_chat_members=possible_users, chat=Chat(0, type='GROUP'), date=datetime.now())), None), 'mock_obj': [Message], 'mock_func': ['reply_text'], 'mock_ret': [True], 'is_async': True }, { - 'func': main.generate_welcome, + 'func': generate_welcome, 'expected_res': get_wel('it'), 'arg': (possible_users[4],), 'mock_obj': [main], @@ -46,19 +46,19 @@ def get_wel(lan_code: str) -> str: 'mock_ret': [0] }, { - 'func': main.generate_welcome, + 'func': generate_welcome, 'expected_res': get_wel('en'), - 'arg': (possible_users[5],), + 'arg': (possible_users[5]), 'mock_obj': [main], 'mock_func': ['randrange'], 'mock_ret': [0] }, { - 'func': main.main, + 'func': main, 'expected_res': None, 'arg': tuple(), - 'mock_obj': [main, Application], - 'mock_func': ['getenv', 'run_polling'], + 'mock_obj': [main, Updater], + 'mock_func': ['getenv', 'start_polling'], 'mock_ret': ['123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', True] } ] @@ -79,13 +79,3 @@ async def test_generic(mocker: MockerFixture, test: dict) -> None: assert res == test['expected_res'] for index, spy in enumerate(spyed_objects): assert spy.spy_return == test['mock_ret'][index] - - -def test_init(mocker: MockerFixture) -> None: - mocker.patch.object(main, '__name__', '__main__') - mocker.patch.object(main, 'main', return_value=None) - spy = mocker.spy(main, 'main') - - assert main.init() == None - assert spy.spy_return == None -