Open github-actions[bot] opened 3 years ago
availability of removing admins feature
https://github.com/bsimjoo/Telegram-RSS-Bot/blob/921facbf4da33c9eee711306aee93262ced76ca4/Handlers.py#L43
import html import json import logging import pickle import random import string import BugReporter from datetime import datetime, timedelta from dateutil.parser import parse from telegram import (Chat, ChatMember, InlineKeyboardButton, InlineKeyboardMarkup, InputMediaPhoto, ParseMode, ReplyKeyboardMarkup, ReplyKeyboardRemove, Update) from telegram.bot import Bot from telegram.error import BadRequest, NetworkError, Unauthorized from telegram.ext import (BaseFilter, CallbackContext, CallbackQueryHandler, ChatMemberHandler, CommandHandler, ConversationHandler, Filters, MessageHandler, Updater) from telegram.utils.helpers import DEFAULT_NONE from decorators import (CommandHandlerDecorator, ConversationDecorator, DispatcherDecorators, HandlerDecorator, auth, MessageHandlerDecorator) from main import BotHandler def add_owner_commands(server: BotHandler): dispatcher_decorators = DispatcherDecorators(server.dispatcher) @dispatcher_decorators.commandHandler @auth(server.ownerID, server.unknown) def gentoken(u: Update, c: CallbackContext): admin_token = ''.join( [random.choice(string.ascii_letters+string.digits) for x in range(32)]) server.admin_token.append(admin_token) u.message.reply_html(( 'one-time admin token:\n<pre>' f'{admin_token}' '</pre>\n<i>Send this token to anyone you want to promote as admin' )) # TODO:availability of removing admins feature # labels: enhancement def add_debuging_handlers(server: BotHandler): dispatcher_decorators = DispatcherDecorators(server.dispatcher) @dispatcher_decorators.messageHandler(filters=Filters.update, group=0) def log_update(u: Update, c: CallbackContext): message = ( 'Received a new update event from telegram\n' f'update = {json.dumps(u.to_dict(), indent = 2, ensure_ascii = False)}\n' f'user_data = {json.dumps(c.user_data, indent = 2, ensure_ascii = False)}\n' f'chat_data = {json.dumps(c.chat_data, indent = 2, ensure_ascii = False)}' ) logging.info(message) if server.debug: try: server.bot.send_message(server.ownerID, html.escape( message), parse_mode=ParseMode.HTML) except BaseException as e: server.log_bug(e, 'Exception while sending update log to owner', ownerID=server.ownerID, message=html.escape(message)) @dispatcher_decorators.commandHandler @auth(server.ownerID, server.unknown) def log_updates(u: Update, c: CallbackContext): server.debug = not server.debug if server.debug: u.message.reply_text( 'Debug enabled. now bot sends all updates for you') else: u.message.reply_text('Debug disabled.') def add_admin_commands(server: BotHandler): dispatcher_decorators = DispatcherDecorators(server.dispatcher) # TODO:Add unknown function to server # this function mist return `ConversatinHandler.END` admin_auth = auth(server.adminID, server.unknown) @dispatcher_decorators.commandHandler @admin_auth def my_level(u: Update, c: CallbackContext): if u.effective_user.id == server.ownerID: u.message.reply_text( 'Oh, my lord. I respect you.') elif u.effective_user.id in server.adminID: u.message.reply_text('Oh, my admin. Hi, How are you?') @dispatcher_decorators.commandHandler @admin_auth def state(u: Update, c: CallbackContext): members, chats = 0, 0 msg = u.message.reply_text('⏳ Please wait, counting members...') with server.env.begin(server.chats_db) as txn: chats = int(txn.stat()["entries"]) for key, value in txn.cursor(): v = pickle.loads(value) members += v['members-count'] msg.edit_text( f'👥chats:\t{chats}\n' + f'👤members:\t{members}\n' + f'🤵admins:\t{len(server.adminID)}' ) @dispatcher_decorators.commandHandler @admin_auth def listchats(u: Update, c: CallbackContext): res = '' with server.env.begin(server.chats_db) as txn: res = 'total: '+str(txn.stat()["entries"])+'\n' for key, value in txn.cursor(): chat = pickle.loads(value) if type(chat) is not type(dict()): res += html.escape( f'\n bad data type; type:{type(chat)}, value:{chat}\n') continue if 'username' in chat: chat['username'] = '@'+chat['username'] res += html.escape(json.dumps(chat, indent=2, ensure_ascii=False)) u.message.reply_html(res) @dispatcher_decorators.commandHandler @auth def send_feed_toall(u: Update, c: CallbackContext): server.send_feed( *server.read_feed(), server.get_string('last-feed'), server.iter_all_chats()) @dispatcher_decorators.commandHandler @auth def set_interval(u: Update, c: CallbackContext): if len(c.args) == 1: if c.args[0].isdigit(): server.interval = int(c.args[0]) server.set_data( 'interval', server.interval, server.data_db) u.message.reply_text( '✅ Interval changed to'+str(server.interval)) return u.message.reply_markdown_v2( '❌ Bad command, use `/set_interval {new interval in seconds}`') def add_keyboard(c: CallbackContext): 'A function that create keyboard that needed in send_all conversation' keys = ['❌Cancel'] if len(c.user_data['messages']): keys = ['✅Send', '👁Preview', '❌Cancel'] markdown = c.user_data['parser'] == ParseMode.HTML return ReplyKeyboardMarkup( [ [('✅ HTML Enabled' if markdown else '◻️ HTML Disabled')], keys ], resize_keyboard=True ) STATE_ADD, STATE_EDIT, STATE_DELETE, STATE_CONFIRM = range(4) @CommandHandlerDecorator @admin_auth def sendall(u: Update, c: CallbackContext): if u.effective_chat.type != Chat.PRIVATE: u.message.reply_text( '❌ ERROR\nthis command only is available in private') return ConversationHandler.END c.user_data['last-message'] = u.message.reply_text( 'You can send text or photo.', disable_notification=True) c.user_data['messages'] = [] c.user_data['parser'] = DEFAULT_NONE u.message.reply_text( 'OK, Send a message to forward it to all users', reply_markup=add_keyboard(c)) return STATE_ADD sendall_conv_handler = ConversationDecorator(sendall, per_user=True) @sendall_conv_handler.state(STATE_ADD) @MessageHandlerDecorator(Filters.regex("^✅Send$")) def confirm(u: Update, c: CallbackContext): c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message(u.effective_chat.id, 'Are you sure, you want to send message' + ('s' if len(c.user_data['messages']) > 1 else '') + 'to all users, groups and channels?', reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton( "👍Yes, that's OK!", callback_data='yes'), InlineKeyboardButton( "✋No, stop!", callback_data='no') ] ] )) return STATE_CONFIRM text_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton('✏️Edit', callback_data='edit'), InlineKeyboardButton('❌Delete', callback_data='delete') ] ]) photo_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton('✏️Edit', callback_data='edit'), InlineKeyboardButton('📝Edit caption', callback_data='edit-cap'), InlineKeyboardButton('❌Delete', callback_data='delete') ] ]) def cleanup_last_preview(chat_id, c: CallbackContext): if 'prev-dict' in c.user_data: for msg_id in c.user_data['prev-dict']: c.bot.edit_message_reply_markup( chat_id, msg_id, ) def cancel(state) -> callable: _cancel = None if state in (STATE_ADD, STATE_CONFIRM): def _cancel(u: Update, c: CallbackContext): for key in ('messages', 'prev-dict', 'had-error', 'edit-cap', 'editing-prev-id'): if key in c.user_data: del(c.user_data[key]) c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message(u.effective_chat.id, 'Canceled', reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END elif state == STATE_EDIT: def _cancel(u: Update, c: CallbackContext): for key in ('edit-cap', 'editing-prev-id'): if key in c.user_data: del(c.user_data[key]) return STATE_ADD elif state == STATE_DELETE: def _cancel(u: Update, c: CallbackContext): query = u.callback_query query.answer('❌ Canceled') query.edit_message_reply_markup( InlineKeyboardMarkup([ [InlineKeyboardButton('✏️Edit', callback_data='edit'), InlineKeyboardButton( '❌Delete', callback_data='delete')] ])) c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message( u.effective_chat.id, 'OK, now what? (send a message to add)', reply_markup=add_keyboard(c)) return STATE_ADD return _cancel @sendall_conv_handler.state(STATE_ADD) @MessageHandlerDecorator(Filters.regex("^👁Preview$")) def preview(u: Update, c: CallbackContext): cleanup_last_preview(u.effective_chat.id, c) c.user_data['prev-dict'] = dict() chat = u.effective_chat for msg in c.user_data['messages']: if msg['type'] == 'text': try: msg_id = chat.send_message( msg['text'], parse_mode=msg['parser'], reply_markup=text_markup ).message_id except BadRequest as ex: msg_id = chat.send_message( msg['text']+'\n\n⚠️ CAN NOT PARSE.\n'+ex.message, reply_markup=text_markup ).message_id c.user_data['had-error'] = True c.user_data['prev-dict'][msg_id] = msg elif msg['type'] == 'photo': try: msg_id = chat.send_photo( msg['photo'], msg['caption'], parse_mode=msg['parser'], reply_markup=photo_markup ).message_id except BadRequest as ex: msg_id = chat.send_photo( msg['photo'], caption=msg['caption'] + '\n\n⚠️ CAN NOT PARSE.\n'+ex.message, reply_markup=photo_markup ).message_id c.user_data['had-error'] = True c.user_data['prev-dict'][msg_id] = msg else: logging.error('UNKNOWN MSG TYPE FOUND\n'+str(msg)) c.bot.send_message( server.ownerID, 'UNKNOWN MSG TYPE FOUND\n'+str(msg)) BugReporter.bug('unknown type message in preview', 'UNKNOWN MSG TYPE FOUND\n'+str(msg)) if c.user_data.get('had-error'): c.user_data['last-message'] = u.message.reply_text( '🛑 there is a problem with your messages, please fix them.', reply_markup=add_keyboard(c)) else: c.user_data['last-message'] = u.message.reply_text('OK, now what? (send a message to add)', reply_markup=add_keyboard(c)) return STATE_ADD sendall_conv_handler.state(STATE_ADD)( MessageHandler(Filters.regex("^❌Cancel$"), cancel(STATE_ADD)) ) @sendall_conv_handler.state(STATE_ADD, STATE_EDIT) @MessageHandlerDecorator(Filters.regex("^✅ HTML Enabled$") | Filters.regex("^◻️ HTML Disabled$")) def toggle_markdown(u: Update, c: CallbackContext): if c.user_data['parser'] == ParseMode.HTML: c.user_data['parser'] = DEFAULT_NONE u.message.reply_text('◻️ HTML Disabled', reply_markup=add_keyboard(c)) else: c.user_data['parser'] = ParseMode.HTML u.message.reply_text( '✅ HTML Enabled', reply_markup=add_keyboard(c)) @sendall_conv_handler.state(STATE_ADD) @MessageHandlerDecorator(Filters.text) def add_text(u: Update, c: CallbackContext): text = u.message.text if c.user_data['parser'] == ParseMode.HTML: text = str(server.purge(text, False)) c.user_data['messages'].append( { 'type': 'text', 'text': text, 'parser': c.user_data['parser'] } ) c.user_data['last-message'].delete() c.user_data['last-message'] = u.message.reply_text('OK, I received your message now what? (send a message to add)', reply_markup=add_keyboard(c)) return STATE_ADD @sendall_conv_handler.state(STATE_ADD) @MessageHandlerDecorator(Filters.photo) def add_photo(u: Update, c: CallbackContext): text = u.message.caption if c.user_data['parser'] == ParseMode.HTML: text = str(server.purge(text, False)) c.user_data['messages'].append( { 'type': 'photo', 'photo': u.message.photo[-1], 'caption': text, 'parser': c.user_data['parser'] } ) c.user_data['last-message'].delete() c.user_data['last-message'] = u.message.reply_text( 'OK, I received photo%s now what? (send a message to add)' % ( 's' if len(u.message.photo) > 1 else ''), reply_markup=add_keyboard(c)) return STATE_ADD sendall_conv_handler.state(STATE_EDIT)( MessageHandler(Filters.regex("^❌Cancel$"), cancel(STATE_EDIT)) ) @sendall_conv_handler.fallback @HandlerDecorator(CallbackQueryHandler, pattern='^edit(-cap)?$') def edit(u: Update, c: CallbackContext): query = u.callback_query edit_cap = query.data == 'edit-cap' query.answer() c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message(u.effective_chat.id, '✏️ EDITING CAPTION\nSend new caption.' if edit_cap else '✏️ EDITING\nSend new edition.', reply_markup=ReplyKeyboardMarkup([['❌Cancel']], resize_keyboard=True)) c.user_data['editing-prev-id'] = query.message.message_id c.user_data['edit-cap'] = edit_cap return STATE_EDIT @sendall_conv_handler.state(STATE_EDIT) @MessageHandlerDecorator(Filters.text) def text_edited(u: Update, c: CallbackContext): if not u.message: return STATE_EDIT # id of the message that bot sent as preview preview_msg_id = c.user_data['editing-prev-id'] # get msg by searching preview message id in prev-dict msg = c.user_data['prev-dict'][preview_msg_id] edited_txt = u.message.text if c.user_data['parser'] == ParseMode.HTML: edited_txt = str(server.purge(edited_txt, False)) if msg.get('had-error'): del(msg['had-error']) if c.user_data.get('had-error'): del(c.user_data['had-error']) msg['parser'] = c.user_data['parser'] if msg['type'] == 'text': msg['text'] = edited_txt # change message text try: c.bot.edit_message_text( # edit preview message text edited_txt, u.effective_chat.id, preview_msg_id, parse_mode=msg['parser'], reply_markup=text_markup ) except BadRequest as ex: c.bot.edit_message_text( edited_txt+'\n\n⚠️ CAN NOT PARSE.\n'+ex.message, u.effective_chat.id, preview_msg_id, reply_markup=text_markup ) msg['had-error'] = True c.user_data['had-error'] = True elif msg['type'] == 'photo': if c.user_data['edit-cap']: msg['caption'] = u.message.text try: c.bot.edit_message_caption( u.effective_chat.id, preview_msg_id, caption=edited_txt, parse_mode=msg['parser'], reply_markup=photo_markup ) except BadRequest as ex: c.bot.edit_message_caption( u.effective_chat.id, preview_msg_id, caption=edited_txt+'\n\n⚠️ CAN NOT PARSE.\n'+ex.message, reply_markup=photo_markup ) msg['had-error'] = True c.user_data['had-error'] = True else: # change message type from photo to text msg['type'] = 'text' del(msg['photo'], msg['caption']) msg['text'] = edited_txt c.bot.edit_message_caption( caption='⚠️ This message type had been changed from photo to text. ' + 'You can request for a new preview to see this message.', chat_id=u.effective_chat.id, message_id=preview_msg_id ) else: # Log this bug logging.error('UNKNOWN MSG TYPE FOUND\n'+str(msg)) c.bot.send_message( server.ownerID, 'UNKNOWN MSG TYPE FOUND\n'+str(msg)) if c.user_data.get('had-error'): c.user_data['last-message'] = u.message.reply_text( '🛑 there is a problem with your messages, please fix them.', parse_mode=ParseMode.MARKDOWN_V2, reply_markup=add_keyboard(c)) else: c.user_data['last-message'] = u.message.reply_text('✅ Message edited; now you can add more messages or send it', reply_markup=add_keyboard(c)) return STATE_ADD @sendall_conv_handler.state(STATE_EDIT) @MessageHandlerDecorator(Filters.photo) def photo_edited(u: Update, c: CallbackContext): # id of the message that bot sent as preview preview_msg_id = c.user_data['editing-prev-id'] # get msg by searching preview message id in prev-dict msg = c.user_data['prev-dict'][preview_msg_id] if msg.get('had-error'): del(msg['had-error']) if c.user_data.get('had-error'): del(c.user_data['had-error']) msg['parser'] = c.user_data['parser'] msg['photo'] = u.message.photo[-1] msg['caption'] = u.message.caption if c.user_data['parser'] == ParseMode.HTML: msg['caption'] = str(server.purge(msg['caption'], False)) if c.user_data['parser'] == ParseMode.MARKDOWN_V2: msg['caption'] = u.message.caption_markdown_v2 if msg['type'] == 'photo': try: c.bot.edit_message_media( u.effective_chat.id, preview_msg_id, media=InputMediaPhoto( media=msg['photo'], caption=msg['caption'], parse_mode=msg['parser']) ) except BadRequest as ex: c.bot.edit_message_media( u.effective_chat.id, preview_msg_id, media=InputMediaPhoto( media=msg['photo'], caption=msg['caption']+'\n\n⚠️ CAN NOT PARSE.\n'+ex.message) ) msg['had-error'] = True c.user_data['had-error'] = True elif msg['type'] == 'text': # change message type to photo msg['type'] = 'photo' del(msg['text']) c.bot.edit_message_text( '⚠️ This message type had been changed from text to photo. ' + 'You can request for a new preview to see this message.', u.effective_chat.id, preview_msg_id, ) else: # report bug logging.error('UNKNOWN MSG TYPE FOUND\n'+str(msg)) c.bot.send_message( server.ownerID, 'UNKNOWN MSG TYPE FOUND\n'+str(msg)) if c.user_data.get('had-error'): c.user_data['last-message'] = u.message.reply_text( '🛑 there is a problem with your messages, please fix them.', parse_mode=ParseMode.MARKDOWN_V2, reply_markup=add_keyboard(c)) else: c.user_data['last-message'] = u.message.reply_text('✅ Message edited; now you can add more messages or send it', reply_markup=add_keyboard(c)) return STATE_ADD @sendall_conv_handler.fallback @HandlerDecorator(CallbackQueryHandler, pattern='^delete$') def deleting(u: Update, c: CallbackContext): query = u.callback_query query.answer() query.edit_message_reply_markup( InlineKeyboardMarkup([ [InlineKeyboardButton( '🛑 Are you sure?', callback_data='None')], [InlineKeyboardButton('🔴 Yes', callback_data='yes'), InlineKeyboardButton( '🟢 No', callback_data='no')] ]) ) c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message( u.effective_chat.id, '⏳ Deleting a message...', reply_markup=ReplyKeyboardRemove()) return STATE_DELETE sendall_conv_handler.state(STATE_DELETE)( CallbackQueryHandler(cancel(STATE_DELETE), pattern='^no$') ) @sendall_conv_handler.state(STATE_DELETE) @HandlerDecorator(CallbackQueryHandler, pattern='^yes$') def delete(u: Update, c: CallbackContext): query = u.callback_query query.answer('✅ Deleted') preview_msg_id = query.message.message_id msg = c.user_data['prev-dict'][preview_msg_id] c.user_data['messages'].remove(msg) del(c.user_data['prev-dict'][preview_msg_id]) query.edit_message_text('❌') c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message( u.effective_chat.id, 'OK, now you can send message to add', reply_markup=add_keyboard(c)) return STATE_ADD def send_message(chat_id, c: CallbackContext): chat = server.bot.get_chat(chat_id) for msg in c.user_data['messages']: # send message to admin for a debug! if msg['type'] == 'text': try: chat.send_message( msg['text'], parse_mode=msg['parser'] ).message_id except BadRequest as ex: chat.send_message( msg['text']+'\n\n⚠️ CAN NOT PARSE.\n'+ex.message, reply_markup=text_markup ) c.user_data['had-error'] = True msg['had-error'] = True return STATE_ADD elif msg['type'] == 'photo': try: chat.send_photo( msg['photo'], msg['caption'], parse_mode=msg['parser'] ).message_id except BadRequest as ex: chat.send_photo( msg['photo'], caption=msg['caption'] + '\n\n⚠️ CAN NOT PARSE.\n'+ex.message ).message_id c.user_data['had-error'] = True msg['had-error'] = True return STATE_ADD @sendall_conv_handler.state(STATE_CONFIRM) @HandlerDecorator(CallbackQueryHandler, pattern='^yes$') def send(u: Update, c: CallbackContext): query = u.callback_query if c.user_data.get('had-error'): query.answer() u.effective_chat.send_message( '🛑 there is a problem with your messages, please fix them.', parse_mode=ParseMode.MARKDOWN_V2, reply_markup=add_keyboard(c) ) return STATE_ADD query.answer( '✅ Done\nSending message to all users, groups and channels', show_alert=True) logging.info('Sending message to chats') c.user_data['last-message'].delete() c.user_data['last-message'] = server.bot.send_message(u.effective_chat.id, '✅ Done\nSending message to all users, groups and channels') res = send_message(u.effective_chat.id, c) if res: u.effective_chat.send_message( '🛑 there is a problem with your messages, please fix them.', parse_mode=ParseMode.MARKDOWN_V2, reply_markup=add_keyboard(c) ) return res remove_ids = [] for chat_id, chat_data in server.iter_all_chats(): if chat_id != u.effective_chat.id: try: send_message(chat_id, c) except Unauthorized as e: server.log_bug(e, 'handled an exception while trying to send message to a chat. removing chat', report=False, chat_id=chat_id, chat_data=chat_data) try: with server.env.begin(server.chats_db, write=True) as txn: txn.delete(str(chat_id).encode()) except Exception as e2: server.log_bug( e2, 'exception while trying to remove chat') remove_ids.append(chat_id) except Exception as e: server.log_bug( e, 'exception while trying to send message to a chat', chat_id=chat_id, chat_data=chat_data) for chat_id in remove_ids: with server.env.begin(server.chats_db, write=True) as txn: txn.delete(str(chat_id).encode()) cleanup_last_preview(u.effective_chat.id, c) for key in ('messages', 'prev-dict', 'had-error', 'edit-cap', 'editing-prev-id'): if key in c.user_data: del(c.user_data[key]) return ConversationHandler.END sendall_conv_handler.state(STATE_CONFIRM)( CallbackQueryHandler(cancel(STATE_CONFIRM), pattern='^no$') ) server.dispatcher.add_handler(sendall_conv_handler.get_handler()) def add_users_commands(server: BotHandler): dispatcher_decorators = DispatcherDecorators(server.dispatcher) @dispatcher_decorators.commandHandler def start(u: Update, c: CallbackContext): chat = u.effective_chat message = u.message user = u.effective_user data = chat.to_dict() data['members-count'] = chat.get_members_count()-1 if chat.type == Chat.PRIVATE: data.update(user.to_dict()) message.reply_markdown_v2(server.get_string('welcome')) if len(c.args) == 1: if c.args[0] == server.token: if user.id in server.adminID: message.reply_text( f'My dear {user.full_name}, I already know you as my lord!') else: message.reply_text( f'Hi my dear {user.full_name}\nFrom now on, I know you as my lord\nyour id is: "{user.id}"') server.adminID.append(user.id) server.set_data( 'adminID', server.adminID, DB=server.data_db) server.ownerID = user.id server.set_data( 'ownerID', server.ownerID, DB=server.data_db) elif c.args[0] in server.admin_token: if user.id in server.adminID: message.reply_text( f'My dear {user.full_name}, I already know you as my admin!') else: message.reply_text( 'Owner must accept your request.\n⏳ please wait...') server.admins_pendding[user.id] = c.args[0] server.bot.send_message( server.ownerID, 'Hi, A user wants to be admin:\n' + f'tel-id:\t{user.id}\n' + f'user-id:\t{user.username}\n' + f'name:\t{user.full_name}', reply_markup=InlineKeyboardMarkup( [[ InlineKeyboardButton( '✅ Accept', callback_data=f'accept-{user.id}'), InlineKeyboardButton( '❌ Decline', callback_data=f'decline-{user.id}') ]]) ) else: u.message.reply_markdown_v2( server.get_string('group-intro')) server.set_data(key=str(chat.id), value=data) @dispatcher_decorators.commandHandler def last_feed(u: Update, c: CallbackContext): if u.effective_user.id not in server.adminID and 'time' in c.user_data: if c.user_data['time'] > datetime.now(): u.message.reply_text(server.get_string('time-limit-error')) return server.send_feed(*server.read_feed(),msg_header = server.get_string('last-feed'),chats = [(u.effective_chat.id, c.chat_data)]) c.user_data['time'] = datetime.now() + timedelta(minutes = 2) #The next request is available 2 minutes later @dispatcher_decorators.commandHandler(command = 'help') def help_(u: Update, c: CallbackContext): if u.effective_chat.id == server.ownerID: u.message.reply_text(server.get_string('owner-help')) if u.effective_chat.id in server.adminID: u.message.reply_text(server.get_string('admin-help')) u.message.reply_text(server.get_string('help')) @dispatcher_decorators.messageHandler(Filters.update.edited_message) def handle_edited_msg(u: Update, c:CallbackContext): #TODO: Handle editing messages # Handle messages editing in /send_all could be usefull # labels: enhancement u.edited_message.reply_text(self.strings['edited-message'])
db880706fda58547eac90ebbbf6c6169cb020c61
availability of removing admins feature
https://github.com/bsimjoo/Telegram-RSS-Bot/blob/921facbf4da33c9eee711306aee93262ced76ca4/Handlers.py#L43
db880706fda58547eac90ebbbf6c6169cb020c61