|
| 1 | +#!/usr/bin/enb python3 |
| 2 | + |
| 3 | +from datetime import datetime as DateTime |
| 4 | +import argparse |
1 | 5 | import logging |
2 | | -from time import sleep |
| 6 | +import sys |
| 7 | +import time |
3 | 8 |
|
4 | 9 | import telegram |
5 | | -from telegram.ext import Updater, Filters, MessageHandler, CommandHandler |
6 | 10 | from telegram import Update |
| 11 | +from telegram.ext import ApplicationBuilder, filters, MessageHandler, CommandHandler, ContextTypes |
| 12 | +from telegram.constants import ParseMode |
7 | 13 |
|
8 | 14 | import config |
9 | 15 | import utils |
10 | 16 |
|
11 | 17 |
|
12 | | -logger = logging.getLogger('bot') |
13 | | - |
14 | | - |
15 | | -def command_start(update, context): |
16 | | - logger.info('Received command /start') |
17 | | - context.bot.send_message(chat_id=update.message.chat_id, text=config.BOT_GREETING) |
18 | | - |
19 | | - |
20 | | -def command_help(update, context): |
21 | | - logger.info('Received command /help') |
22 | | - context.bot.send_message( |
23 | | - chat_id=update.message.chat_id, |
24 | | - text="Available commands:\n" |
25 | | - " - /start - start intereaction with the bot\n" |
26 | | - " - /help - Show commands\n" |
27 | | - " - /status - Show status and alive time\n" |
28 | | - ) |
29 | | - |
30 | | - |
31 | | -def command_status(update, context): |
32 | | - logger.info('bot asked to execute /status commamd') |
33 | | - context.bot.send_message( |
34 | | - chat_id=update.message.chat_id, |
35 | | - text=f'Status is OK, running since {utils.since()}', |
36 | | - ) |
37 | | - |
38 | | - |
39 | | -def welcome(update: Update, context): |
40 | | - logger.info('Received new user event') |
41 | | - new_member = update.message.new_chat_members[0] |
42 | | - |
43 | | - logger.info(f'Waiting {config.WELCOME_DELAY} seconds until user completes captcha...') |
44 | | - sleep(config.WELCOME_DELAY) |
45 | | - membership_info = context.bot.get_chat_member(update.message.chat_id, new_member.id) |
46 | | - if membership_info['status'] == 'left': |
47 | | - logger.info(f'Skipping welcome message, user {new_member.name} is no longer in the chat') |
48 | | - return |
49 | | - |
50 | | - logger.info(f'send welcome message for {new_member.name}') |
51 | | - msg = None |
52 | | - |
53 | | - if new_member.is_bot: |
54 | | - msg = f"{new_member.name} is a *bot*!! " \ |
55 | | - "-> It could be kindly removed 🗑" |
56 | | - else: |
57 | | - if utils.is_bot(new_member): |
58 | | - context.bot.delete_message(update.message.chat_id, |
59 | | - update.message.message_id) |
60 | | - if context.bot.kick_chat_member(update.message.chat_id, new_member.id): |
61 | | - msg = (f"*{new_member.username}* has been banned because I " |
62 | | - "considered it was a bot. ") |
| 18 | +class DeckardBot(): |
| 19 | + |
| 20 | + def __init__(self): |
| 21 | + self.get_options() |
| 22 | + self.set_logger() |
| 23 | + self.started_at = DateTime.now() |
| 24 | + |
| 25 | + def get_options(self): |
| 26 | + parser = argparse.ArgumentParser( |
| 27 | + prog='bot', |
| 28 | + description='PyDeckard Bot', |
| 29 | + epilog='Text at the bottom of help', |
| 30 | + ) |
| 31 | + parser.add_argument('-v', '--verbose', action='store_true') |
| 32 | + args = parser.parse_args() |
| 33 | + self.verbose = args.verbose |
| 34 | + |
| 35 | + def set_logger(self): |
| 36 | + self.logger = logging.getLogger('bot') |
| 37 | + logging.basicConfig( |
| 38 | + level=config.LOG_LEVEL, |
| 39 | + format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', |
| 40 | + ) |
| 41 | + config.log(self.logger.info) |
| 42 | + |
| 43 | + def trace(self, msg): |
| 44 | + self.logger.info('bot asked to execute /status commamd') |
| 45 | + if self.verbose: |
| 46 | + print(msg) |
| 47 | + |
| 48 | + async def command_status(self, update: Update, context: ContextTypes.DEFAULT_TYPE): |
| 49 | + self.trace('bot asked to execute /status commamd') |
| 50 | + python_version = sys.version.split(maxsplit=1)[0] |
| 51 | + text = '\n'.join([ |
| 52 | + config.BOT_GREETING, |
| 53 | + f'Status is <b>OK</b>, running since {utils.since(self.started_at)}', |
| 54 | + f'Python version is {python_version}', |
| 55 | + ]) |
| 56 | + await context.bot.send_message( |
| 57 | + chat_id=update.effective_chat.id, |
| 58 | + text=text, |
| 59 | + parse_mode=ParseMode.HTML, |
| 60 | + ) |
| 61 | + self.trace(text) |
| 62 | + |
| 63 | + async def command_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE): |
| 64 | + self.trace('Received command /start') |
| 65 | + await context.bot.send_message( |
| 66 | + chat_id=update.effective_chat.id, |
| 67 | + text=config.BOT_GREETING, |
| 68 | + parse_mode=ParseMode.HTML, |
| 69 | + ) |
| 70 | + |
| 71 | + async def command_help(self, update: Update, context: ContextTypes.DEFAULT_TYPE): |
| 72 | + self.trace('Received command /help') |
| 73 | + await context.bot.send_message( |
| 74 | + chat_id=update.effective_chat.id, |
| 75 | + text=( |
| 76 | + "Available commands:\n\n" |
| 77 | + "<code>/start</code> : start intereaction with the bot\n" |
| 78 | + "<code>/help</code> : Show commands\n" |
| 79 | + "<code>/status</code> : Show status and alive time\n" |
| 80 | + "<code>/zen</code> : Show the Zen of Python\n" |
| 81 | + ), |
| 82 | + parse_mode=ParseMode.HTML, |
| 83 | + ) |
| 84 | + |
| 85 | + async def command_zen(self, update: Update, context: ContextTypes.DEFAULT_TYPE): |
| 86 | + self.trace('Received command /zen') |
| 87 | + text = '\n'.join(config.THE_ZEN_OF_PYTHON) |
| 88 | + await context.bot.send_message( |
| 89 | + chat_id=update.effective_chat.id, |
| 90 | + text=text, |
| 91 | + parse_mode=ParseMode.HTML, |
| 92 | + ) |
| 93 | + |
| 94 | + async def welcome(self, update: Update, context): |
| 95 | + logger.info('Received new user event') |
| 96 | + new_member = update.message.new_chat_members[0] |
| 97 | + |
| 98 | + self.trace(f'Waiting {config.WELCOME_DELAY} seconds until user completes captcha...') |
| 99 | + time.sleep(config.WELCOME_DELAY) |
| 100 | + membership_info = await context.bot.get_chat_member(update.message.chat_id, new_member.id) |
| 101 | + if membership_info['status'] == 'left': |
| 102 | + self.trace(f'Skipping welcome message, user {new_member.name} is no longer in the chat') |
| 103 | + return |
| 104 | + |
| 105 | + self.trace(f'send welcome message for {new_member.name}') |
| 106 | + msg = None |
| 107 | + |
| 108 | + if new_member.is_bot: |
| 109 | + msg = f"{new_member.name} is a *bot*\\!\\! " \ |
| 110 | + "-> It could be kindly removed 🗑" |
63 | 111 | else: |
64 | | - msg = f"Welcome {new_member.name}!! " \ |
65 | | - "I am a friendly and polite *bot* 🤖" |
66 | | - if msg: |
67 | | - context.bot.send_message( |
68 | | - chat_id=update.message.chat_id, |
69 | | - text=msg, |
70 | | - parse_mode=telegram.ParseMode.MARKDOWN |
71 | | - ) |
72 | | - |
73 | | - |
74 | | -def reply(update, context): |
75 | | - if not config.bot_replies_enabled(): |
76 | | - return |
77 | | - |
78 | | - msg = update.message.text |
79 | | - reply_spec = utils.triggers_reply(msg) if msg else None |
80 | | - if reply_spec is not None: |
81 | | - logger.info(f'bot sends reply {reply_spec.reply}') |
82 | | - context.bot.send_message( |
83 | | - chat_id=update.message.chat_id, |
84 | | - text=reply_spec.reply |
85 | | - ) |
86 | | - |
87 | | - |
88 | | -def main(): |
89 | | - logging.basicConfig( |
90 | | - level=config.LOG_LEVEL, |
91 | | - format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', |
92 | | - ) |
93 | | - logger.info('Starting bot...') |
94 | | - config.log(logger.info) |
95 | | - updater = Updater(config.TELEGRAM_BOT_TOKEN) |
96 | | - dp = updater.dispatcher |
97 | | - |
98 | | - dp.add_handler(CommandHandler('start', command_start)) |
99 | | - dp.add_handler(CommandHandler('help', command_help)) |
100 | | - dp.add_handler(CommandHandler('status', command_status)) |
101 | | - dp.add_handler(MessageHandler(Filters.status_update.new_chat_members, |
102 | | - welcome, run_async=True)) |
103 | | - dp.add_handler(MessageHandler(Filters.chat_type.groups, reply)) |
104 | | - |
105 | | - logger.info('Bot is ready') |
106 | | - updater.start_polling(poll_interval=config.POLL_INTERVAL) |
107 | | - updater.idle() |
| 112 | + if utils.is_bot(new_member): |
| 113 | + await context.bot.delete_message(update.message.chat_id, |
| 114 | + update.message.message_id) |
| 115 | + if await context.bot.kick_chat_member(update.message.chat_id, new_member.id): |
| 116 | + msg = (f"*{new_member.username}* has been banned because I " |
| 117 | + "considered it was a bot. ") |
| 118 | + else: |
| 119 | + msg = f"Welcome {new_member.name}\\!\\! " \ |
| 120 | + "I am a friendly and polite *bot* 🤖" |
| 121 | + if msg: |
| 122 | + await update.message.reply_text(msg, parse_mode=telegram.constants.ParseMode('MarkdownV2')) |
| 123 | + |
| 124 | + async def reply(self, update: Update, context: ContextTypes.DEFAULT_TYPE): |
| 125 | + if config.bot_replies_enabled(): |
| 126 | + msg = update.message.text |
| 127 | + reply_spec = utils.triggers_reply(msg) if msg else None |
| 128 | + if reply_spec is not None: |
| 129 | + logger.info(f'bot sends reply {reply_spec.reply}') |
| 130 | + await update.message.reply_text(reply_spec.reply) |
| 131 | + context.bot.send_message( |
| 132 | + chat_id=update.message.chat_id, |
| 133 | + text=reply_spec.reply |
| 134 | + ) |
| 135 | + |
| 136 | + def run(self): |
| 137 | + self.trace('Starting bot...') |
| 138 | + application = ApplicationBuilder().token(config.TELEGRAM_BOT_TOKEN).build() |
| 139 | + start_handler = CommandHandler('start', self.command_start) |
| 140 | + application.add_handler(start_handler) |
| 141 | + help_handler = CommandHandler('help', self.command_help) |
| 142 | + application.add_handler(help_handler) |
| 143 | + status_handler = CommandHandler('status', self.command_status) |
| 144 | + application.add_handler(status_handler) |
| 145 | + |
| 146 | + # Zen Command |
| 147 | + application.add_handler(CommandHandler('zen', self.command_zen)) |
| 148 | + |
| 149 | + welcome_handler = MessageHandler( |
| 150 | + filters.StatusUpdate.NEW_CHAT_MEMBERS, |
| 151 | + self.welcome, |
| 152 | + ) |
| 153 | + application.add_handler(welcome_handler) |
| 154 | + reply_handler = MessageHandler( |
| 155 | + filters.TEXT & (~filters.COMMAND), |
| 156 | + self.reply, |
| 157 | + ) |
| 158 | + application.add_handler(reply_handler) |
| 159 | + self.trace('Bot is ready') |
| 160 | + application.run_polling(poll_interval=config.POLL_INTERVAL) |
108 | 161 |
|
109 | 162 |
|
110 | 163 | if __name__ == "__main__": |
111 | | - main() |
| 164 | + bot = DeckardBot() |
| 165 | + bot.run() |
0 commit comments