def accept_suggestion(bot, update, suggestion: Suggestion): user = User.from_telegram_object(update.effective_user) suggestion.apply() if suggestion.action == 'offline': suggestion_text = '{} went {}.'.format( suggestion.subject.str_no_md, 'offline' if suggestion.subject.offline else 'online') else: suggestion_text = str(suggestion) suggestion_text = suggestion_text[0].upper() + suggestion_text[1:] suggestion_text += '\nApproved by ' + user.markdown_short bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, suggestion_text, parse_mode='markdown', disable_web_page_preview=True) if user != suggestion.user.chat_id: submittant_notification = '*Thank you* {}, your suggestion has been accepted:' \ '\n\n{}'.format(util.escape_markdown(suggestion.user.first_name), str(suggestion)) bot.send_message(suggestion.user.chat_id, submittant_notification, parse_mode='markdown', disable_web_page_preview=True)
def add_keyword(bot, update, chat_data): user = User.from_telegram_object(update.effective_user) if check_suggestion_limit(bot, update, user): return kw = update.message.text bot_to_edit = chat_data.get('edit_bot') kw = helpers.format_keyword(kw) if len(kw) <= 1: update.message.reply_text('Keywords must be longer than 1 character.') return if len(kw) >= 20: update.message.reply_text( 'Keywords must not be longer than 20 characters.') # ignore duplicates try: Keyword.get((Keyword.name == kw) & (Keyword.entity == bot_to_edit)) return except Keyword.DoesNotExist: pass Suggestion.add_or_update(user=user, action='add_keyword', subject=bot_to_edit, value=kw) set_keywords(bot, update, chat_data, bot_to_edit) Statistic.of(update, 'added keyword to'.format(kw), bot_to_edit.username)
def set_text_property(bot, update, chat_data, property_name, to_edit=None): uid = util.uid_from_update(update) user = User.from_update(update) if check_suggestion_limit(bot, update, user): return if to_edit: text = (util.escape_markdown(getattr(to_edit, property_name)) + "\n\n" if getattr(to_edit, property_name) else '') text += mdformat.action_hint( messages.SET_BOTPROPERTY.format( property_name, util.escape_markdown(to_edit.username), CLEAR_QUERY)) if property_name == 'description': text += ', markdown enabled.' update.effective_message.reply_text( text, reply_markup=ForceReply(selective=True), parse_mode=ParseMode.MARKDOWN) chat_data['edit_bot'] = to_edit elif update.message: value = None text = update.message.text to_edit = chat_data.get('edit_bot', None) def too_long(n): bot.formatter.send_failure( uid, "Your {} text is too long, it must be shorter " "than {} characters. Please try again.".format( property_name, n)) util.wait(bot, update) return admin.edit_bot(bot, update, chat_data, to_edit) # Validation if property_name == 'description' and len(text) > 300: return too_long(300) if property_name == 'username': value = helpers.validate_username(text) if value: to_edit = chat_data.get('edit_bot', None) else: bot.formatter.send_failure( uid, "The username you entered is not valid. Please try again..." ) return admin.edit_bot(bot, update, chat_data, to_edit) if not value: value = text if to_edit: if _is_clear_query(text): Suggestion.add_or_update(user, property_name, to_edit, None) else: Suggestion.add_or_update(user, property_name, to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) else: bot.formatter.send_failure(uid, "An unexpected error occured.")
def change_category(bot, update, to_edit, category): uid = update.effective_user.id user = User.get(User.chat_id == uid) if uid in settings.MODERATORS and not uid == 918962: if check_suggestion_limit(bot, update, user): return Suggestion.add_or_update(user, 'category', to_edit, category.id) else: to_edit.category = category to_edit.save()
def remove_keyword(bot, update, chat_data, context): user = User.from_telegram_object(update.effective_user) if check_suggestion_limit(bot, update, user): return to_edit = context.get('to_edit') kw = context.get('keyword') Suggestion.add_or_update(user=user, action='remove_keyword', subject=to_edit, value=kw.name) return set_keywords(bot, update, chat_data, to_edit)
def set_country(bot, update, to_edit, country): user = User.from_update(update) if check_suggestion_limit(bot, update, user): return if isinstance(country, Country): value = country.id elif country is None or country == 'None': value = None else: raise AttributeError("Error setting country to {}.".format(country)) Suggestion.add_or_update(user, 'country', to_edit, value)
def change_category(bot, update, to_edit, category): uid = update.effective_user.id user = User.get(User.chat_id == uid) if uid == 918962: # Special for t3chno to_edit.category = category to_edit.save() else: if check_suggestion_limit(bot, update, user): return Suggestion.add_or_update(user, 'category', to_edit, category.id)
def ban_user(bot, update, user: User, ban_state: bool): if user.banned and ban_state is True: update.message.reply_text(mdformat.none_action( "User {} is already banned.".format(user)), parse_mode='markdown') return if not user.banned and ban_state is False: update.message.reply_text(mdformat.none_action( "User {} is not banned.".format(user)), parse_mode='markdown') return user.banned = ban_state if ban_state is True: with db.atomic(): users_bots = Bot.select().where((Bot.approved == False) & (Bot.submitted_by == user)) for b in users_bots: b.delete_instance() users_suggestions = Suggestion.select().where( (Suggestion.executed == False) & (Suggestion.user == user)) for s in users_suggestions: s.delete_instance() update.message.reply_text(mdformat.success( "User {} banned, all bot submissions and suggestions removed.". format(user)), parse_mode='markdown') Statistic.of(update, 'ban', user.markdown_short) else: update.message.reply_text(mdformat.success( "User {} unbanned.".format(user)), parse_mode='markdown') Statistic.of(update, 'unban', user.markdown_short) user.save()
def apply_all_changes(bot, update, chat_data, to_edit): user = User.from_update(update) user_suggestions = Suggestion.select_all_of_user(user) for suggestion in user_suggestions: suggestion.apply() refreshed_bot = Bot.get(id=to_edit.id) edit_bot(bot, update, chat_data, refreshed_bot) Statistic.of(update, 'apply', refreshed_bot.username)
def check_suggestion_limit(bot, update, user): cid = update.effective_chat.id if Suggestion.over_limit(user): bot.formatter.send_failure( cid, "You have reached the limit of {} suggestions. Please wait for " "the Moderators to approve of some of them.".format( settings.SUGGESTION_LIMIT)) Statistic.of(update, 'hit the suggestion limit') return True return False
def notify_bot_spam(bot, update, args=None): tg_user = update.message.from_user user = User.from_telegram_object(tg_user) if util.stop_banned(update, user): return reply_to = util.original_reply_id(update) if args: text = ' '.join(args) else: text = update.message.text command_no_args = len( re.findall(r'^/spam\s*$', text)) > 0 or text.lower().strip() == '/spam@botlistbot' if command_no_args: update.message.reply_text(util.action_hint( "Please use this command with an argument. For example:\n/spam @mybot" ), reply_to_message_id=reply_to) return # `#spam` is already checked by handler try: username = re.match(settings.REGEX_BOT_IN_TEXT, text).groups()[0] if username == '@' + settings.SELF_BOT_NAME: log.info("Ignoring {}".format(text)) return except AttributeError: if args: update.message.reply_text(util.failure( "Sorry, but you didn't send me a bot `@username`."), quote=True, parse_mode=ParseMode.MARKDOWN, reply_to_message_id=reply_to) else: log.info("Ignoring {}".format(text)) # no bot username, ignore update pass return try: spam_bot = Bot.get( fn.lower(Bot.username)**username.lower(), Bot.approved == True) try: Suggestion.get(action="spam", subject=spam_bot) except Suggestion.DoesNotExist: suggestion = Suggestion(user=user, action="spam", date=datetime.date.today(), subject=spam_bot) suggestion.save() update.message.reply_text(util.success( "Thank you! We will review your suggestion and mark the bot as spammy." ), reply_to_message_id=reply_to) except Bot.DoesNotExist: update.message.reply_text( util.action_hint("The bot you sent me is not in the @BotList."), reply_to_message_id=reply_to) return ConversationHandler.END
def create_suggested_trail(name, desc, lat, long, gps, length, ascent, descent, difficulty, location, url, user): """Create and return a new suggested trail.""" suggestion = Suggestion(name = name, desc = desc, long = long, lat = lat, gps = gps, length = length, ascent = ascent, descent = descent, difficulty = difficulty, location = location, url = url, user = user) db.session.add(suggestion) db.session.commit() return suggestion
def edit_bot(bot, update, chat_data, to_edit=None): uid = util.uid_from_update(update) message_id = util.mid_from_update(update) user = User.from_update(update) if not to_edit: if update.message: command = update.message.text if 'edit' in command: b_id = re.match(r'^/edit(\d+)$', command).groups()[0] elif 'approve' in command: b_id = re.match(r'^/approve(\d+)$', command).groups()[0] else: raise ValueError("No 'edit' or 'approve' in command.") try: to_edit = Bot.get(id=b_id) except Bot.DoesNotExist: update.message.reply_text( util.failure('No bot exists with this id.')) return else: bot.formatter.send_failure(uid, "An unexpected error occured.") return if not to_edit.approved: return approve_bots(bot, update, override_list=[to_edit]) pending_suggestions = Suggestion.pending_for_bot(to_edit, user) reply_markup = InlineKeyboardMarkup( _edit_bot_buttons(to_edit, pending_suggestions, uid in settings.MODERATORS)) pending_text = '\n\n{} Some changes are pending approval{}.'.format( captions.SUGGESTION_PENDING_EMOJI, '' if user.chat_id in settings.MODERATORS else ' by a moderator') if pending_suggestions else '' meta_text = '\n\nDate added: {}\nMember since revision {}\n' \ 'Submitted by {}\nApproved by {}'.format( to_edit.date_added, to_edit.revision, to_edit.submitted_by, to_edit.approved_by) bot.formatter.send_or_edit( uid, "🛃 Edit {}{}{}".format( to_edit.detail_text, meta_text if user.id in settings.MODERATORS else '', pending_text), to_edit=message_id, reply_markup=reply_markup)
def _admin_buttons(send_botlist_button=False, logs_button=False): n_unapproved = len(Bot.select().where(Bot.approved == False)) n_suggestions = len(Suggestion.select_all()) n_pending = len(Bot.select_pending_update()) second_row = list() if n_unapproved > 0: second_row.append( KeyboardButton( captions.APPROVE_BOTS + ' {}🆕'.format(mdformat.number_as_emoji(n_unapproved)))) if n_suggestions > 0: second_row.append( KeyboardButton( captions.APPROVE_SUGGESTIONS + ' {}⁉️'.format(mdformat.number_as_emoji(n_suggestions)))) buttons = [[ KeyboardButton(captions.EXIT), KeyboardButton(captions.REFRESH), ], [ KeyboardButton(captions.FIND_OFFLINE), KeyboardButton(captions.SEND_CONFIG_FILES) ]] update_row = list() if n_pending > 0: update_row.append( KeyboardButton(captions.PENDING_UPDATE + ' {}{}'.format(mdformat.number_as_emoji(n_pending), captions.SUGGESTION_PENDING_EMOJI))) if send_botlist_button: update_row.append(KeyboardButton(captions.SEND_BOTLIST)) if logs_button: update_row.append(KeyboardButton(captions.SEND_ACTIVITY_LOGS)) if len(update_row) > 0: buttons.insert(1, update_row) if len(second_row) > 0: buttons.insert(1, second_row) return buttons
def check_bot(bot: TelegramBot, bot_checker: BotChecker, to_check: BotModel): try: entity = bot_checker.get_bot_entity(to_check.username) except UsernameNotOccupiedError: bot.send_message( settings.BOTLIST_NOTIFICATIONS_ID, "{} deleted because the username does not exist (anymore).".format( to_check.username)) to_check.delete_instance() return time.sleep(2.5) # Check basic properties to_check.official = bool(entity.verified) to_check.inlinequeries = bool(entity.bot_inline_placeholder) to_check.username = '******' + str(entity.username) if entity in bot_checker.botbuilders: to_check.botbuilder = True # Check online state bot_offline = not bot_checker.ping_bot(entity, timeout=12) if to_check.offline != bot_offline: # to_check.offline = bot_offline # We get a lot of false negatives, therefore the bot may set bots online, but only makes # a suggestion to set them offline. # if bot_offline: Suggestion.add_or_update(UserModel.botlist_user_instance(), 'offline', to_check, bot_offline).save() # else: # to_check.offline = False # to_check.save() # bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, '{} went {}.'.format( # to_check.str_no_md, # 'online' # )) # Add entry to pings database now = datetime.datetime.now() ping, created = Ping.get_or_create(bot=to_check, defaults={'last_ping': now}) ping.last_response = ping.last_response if to_check.offline else now ping.save() # Download profile picture tmp_file = os.path.join(settings.BOT_THUMBNAIL_DIR, '_tmp.jpg') photo_file = to_check.thumbnail_file sticker_file = os.path.join(settings.BOT_THUMBNAIL_DIR, '_sticker_tmp.webp') time.sleep(1) downloaded = bot_checker.client.download_profile_photo(entity, tmp_file, download_big=True) if downloaded: try: similar = filecmp.cmp(tmp_file, photo_file, shallow=False) except FileNotFoundError: similar = False if not similar: shutil.copy(tmp_file, photo_file) if not created: # if this bot has been pinged before and its pp changed make_sticker(photo_file, sticker_file) bot.send_message(settings.BOTLIST_NOTIFICATIONS_ID, "New profile picture of {}:".format( to_check.username), timeout=360) bot.send_sticker(settings.BOTLIST_NOTIFICATIONS_ID, open(photo_file, 'rb'), timeout=360) to_check.save() bot_checker.schedule_conversation_deletion(entity, 8) # Sleep to give Userbot time to breathe time.sleep(4)
def approve_suggestions(bot, update, page=0): uid = util.uid_from_update(update) suggestions = Suggestion.select_all() if page * settings.PAGE_SIZE_SUGGESTIONS_LIST >= len(suggestions): # old item deleted, list now too small page = page - 1 if page > 0 else 0 start = page * settings.PAGE_SIZE_SUGGESTIONS_LIST end = start + settings.PAGE_SIZE_SUGGESTIONS_LIST has_prev_page = page > 0 has_next_page = (page + 1) * settings.PAGE_SIZE_SUGGESTIONS_LIST < len( suggestions) suggestions = suggestions[start:end] if len(suggestions) == 0: bot.formatter.send_or_edit(uid, "No more suggestions available.", to_edit=util.mid_from_update(update)) return buttons = [] count = 1 text = "Please choose suggestions to accept.\n" for x in suggestions: number = str(count) + '.' text += "\n{} {}".format(number, str(x)) row = [] # Should the suggestion be editable and is it too long? if x.action in Suggestion.TEXTUAL_ACTIONS: row.append( InlineKeyboardButton("{} {}📝".format( number, Emoji.WHITE_HEAVY_CHECK_MARK), callback_data=util.callback_for_action( CallbackActions.CHANGE_SUGGESTION, { 'id': x.id, 'page': page }))) else: row.append( InlineKeyboardButton("{} {}".format( number, Emoji.WHITE_HEAVY_CHECK_MARK), callback_data=util.callback_for_action( CallbackActions.ACCEPT_SUGGESTION, { 'id': x.id, 'page': page }))) row.append( InlineKeyboardButton("{} {}".format(number, Emoji.CROSS_MARK), callback_data=util.callback_for_action( CallbackActions.REJECT_SUGGESTION, { 'id': x.id, 'page': page }))) buttons.append(row) count += 1 page_arrows = list() if has_prev_page: page_arrows.append( InlineKeyboardButton(Emoji.LEFTWARDS_BLACK_ARROW, callback_data=util.callback_for_action( CallbackActions.SWITCH_SUGGESTIONS_PAGE, {'page': page - 1}))) if has_next_page: page_arrows.append( InlineKeyboardButton(Emoji.BLACK_RIGHTWARDS_ARROW, callback_data=util.callback_for_action( CallbackActions.SWITCH_SUGGESTIONS_PAGE, {'page': page + 1}))) buttons.append(page_arrows) reply_markup = InlineKeyboardMarkup(buttons) bot.formatter.send_or_edit(uid, util.action_hint(text), reply_markup=reply_markup, to_edit=util.mid_from_update(update), disable_web_page_preview=True) return CallbackStates.APPROVING_BOTS
def callback_router(bot, update, chat_data, user_data, job_queue): obj = json.loads(str(update.callback_query.data)) user = User.from_update(update) try: if 'a' in obj: action = obj['a'] # BOTLISTCHAT if action == CallbackActions.DELETE_CONVERSATION: botlistchat.delete_conversation(bot, update, chat_data) # HELP elif action == CallbackActions.HELP: help.help(bot, update) elif action == CallbackActions.CONTRIBUTING: help.contributing(bot, update) elif action == CallbackActions.EXAMPLES: help.examples(bot, update) # BASIC QUERYING elif action == CallbackActions.SELECT_CATEGORY: select_category(bot, update, chat_data) elif action == CallbackActions.SELECT_BOT_FROM_CATEGORY: category = Category.get(id=obj['id']) send_category(bot, update, chat_data, category) elif action == CallbackActions.SEND_BOT_DETAILS: item = Bot.get(id=obj['id']) send_bot_details(bot, update, chat_data, item) # FAVORITES elif action == CallbackActions.TOGGLE_FAVORITES_LAYOUT: value = obj['v'] favorites.toggle_favorites_layout(bot, update, value) elif action == CallbackActions.ADD_FAVORITE: favorites.add_favorite_handler(bot, update) elif action == CallbackActions.REMOVE_FAVORITE_MENU: favorites.remove_favorite_menu(bot, update) elif action == CallbackActions.REMOVE_FAVORITE: to_remove = Favorite.get(id=obj['id']) bot_details = to_remove.bot to_remove.delete_instance() if obj.get('details'): send_bot_details(bot, update, chat_data, bot_details) else: favorites.remove_favorite_menu(bot, update) elif action == CallbackActions.SEND_FAVORITES_LIST: favorites.send_favorites_list(bot, update) elif action == CallbackActions.ADD_ANYWAY: favorites.add_custom(bot, update, obj['u']) elif action == CallbackActions.ADD_TO_FAVORITES: details = obj.get('details') discreet = obj.get('discreet', False) or details item = Bot.get(id=obj['id']) favorites.add_favorite(bot, update, item, callback_alert=discreet) if details: send_bot_details(bot, update, chat_data, item) # ACCEPT/REJECT BOT SUBMISSIONS elif action == CallbackActions.APPROVE_REJECT_BOTS: custom_approve_list = [Bot.get(id=obj['id'])] admin.approve_bots(bot, update, override_list=custom_approve_list) elif action == CallbackActions.ACCEPT_BOT: to_accept = Bot.get(id=obj['id']) admin.edit_bot_category(bot, update, to_accept, CallbackActions.BOT_ACCEPTED) # Run in x minutes, giving the moderator enough time to edit bot details job_queue.run_once( lambda b, job: botlistchat. notify_group_submission_accepted(b, job, to_accept), settings.BOT_ACCEPTED_IDLE_TIME * 60) elif action == CallbackActions.RECOMMEND_MODERATOR: bot_in_question = Bot.get(id=obj['id']) admin.recommend_moderator(bot, update, bot_in_question, obj['page']) elif action == CallbackActions.SELECT_MODERATOR: bot_in_question = Bot.get(id=obj['bot_id']) moderator = User.get(id=obj['uid']) admin.share_with_moderator(bot, update, bot_in_question, moderator) admin.approve_bots(bot, update, obj['page']) elif action == CallbackActions.REJECT_BOT: to_reject = Bot.get(id=obj['id']) notification = obj.get('ntfc', True) admin.reject_bot_submission(bot, update, to_reject, verbose=False, notify_submittant=notification) admin.approve_bots(bot, update, obj['page']) elif action == CallbackActions.BOT_ACCEPTED: to_accept = Bot.get(id=obj['bid']) category = Category.get(id=obj['cid']) admin.accept_bot_submission(bot, update, to_accept, category) elif action == CallbackActions.COUNT_THANK_YOU: new_count = obj.get('count', 1) basic.count_thank_you(bot, update, new_count) # ADD BOT # elif action == CallbackActions.ADD_BOT_SELECT_CAT: # category = Category.get(id=obj['id']) # admin.add_bot(bot, update, chat_data, category) # EDIT BOT elif action == CallbackActions.EDIT_BOT: to_edit = Bot.get(id=obj['id']) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_SELECT_CAT: to_edit = Bot.get(id=obj['id']) admin.edit_bot_category(bot, update, to_edit) elif action == CallbackActions.EDIT_BOT_CAT_SELECTED: to_edit = Bot.get(id=obj['bid']) cat = Category.get(id=obj['cid']) botproperties.change_category(bot, update, to_edit, cat) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_COUNTRY: to_edit = Bot.get(id=obj['id']) botproperties.set_country_menu(bot, update, to_edit) elif action == CallbackActions.SET_COUNTRY: to_edit = Bot.get(id=obj['bid']) if obj['cid'] == 'None': country = None else: country = Country.get(id=obj['cid']) botproperties.set_country(bot, update, to_edit, country) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_DESCRIPTION: to_edit = Bot.get(id=obj['id']) botproperties.set_text_property(bot, update, chat_data, 'description', to_edit) elif action == CallbackActions.EDIT_BOT_EXTRA: to_edit = Bot.get(id=obj['id']) botproperties.set_text_property(bot, update, chat_data, 'extra', to_edit) elif action == CallbackActions.EDIT_BOT_NAME: to_edit = Bot.get(id=obj['id']) botproperties.set_text_property(bot, update, chat_data, 'name', to_edit) elif action == CallbackActions.EDIT_BOT_USERNAME: to_edit = Bot.get(id=obj['id']) botproperties.set_text_property(bot, update, chat_data, 'username', to_edit) # elif action == CallbackActions.EDIT_BOT_KEYWORDS: # to_edit = Bot.get(id=obj['id']) # botproperties.set_keywords_init(bot, update, chat_data, to_edit) elif action == CallbackActions.APPLY_ALL_CHANGES: to_edit = Bot.get(id=obj['id']) admin.apply_all_changes(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_INLINEQUERIES: to_edit = Bot.get(id=obj['id']) value = bool(obj['value']) botproperties.toggle_value(bot, update, 'inlinequeries', to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_OFFICIAL: to_edit = Bot.get(id=obj['id']) value = bool(obj['value']) botproperties.toggle_value(bot, update, 'official', to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_OFFLINE: to_edit = Bot.get(id=obj['id']) value = bool(obj['value']) botproperties.toggle_value(bot, update, 'offline', to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.EDIT_BOT_SPAM: to_edit = Bot.get(id=obj['id']) value = bool(obj['value']) botproperties.toggle_value(bot, update, 'spam', to_edit, value) admin.edit_bot(bot, update, chat_data, to_edit) elif action == CallbackActions.CONFIRM_DELETE_BOT: to_delete = Bot.get(id=obj['id']) botproperties.delete_bot_confirm(bot, update, to_delete) elif action == CallbackActions.DELETE_BOT: to_edit = Bot.get(id=obj['id']) botproperties.delete_bot(bot, update, to_edit) send_category(bot, update, to_edit.category) elif action == CallbackActions.ACCEPT_SUGGESTION: suggestion = Suggestion.get(id=obj['id']) components.botproperties.accept_suggestion( bot, update, suggestion) admin.approve_suggestions(bot, update, page=obj['page']) elif action == CallbackActions.REJECT_SUGGESTION: suggestion = Suggestion.get(id=obj['id']) suggestion.delete_instance() admin.approve_suggestions(bot, update, page=obj['page']) elif action == CallbackActions.CHANGE_SUGGESTION: suggestion = Suggestion.get(id=obj['id']) botproperties.change_suggestion(bot, update, suggestion, page_handover=obj['page']) elif action == CallbackActions.SWITCH_SUGGESTIONS_PAGE: page = obj['page'] admin.approve_suggestions(bot, update, page) elif action == CallbackActions.SWITCH_APPROVALS_PAGE: admin.approve_bots(bot, update, page=obj['page']) elif action == CallbackActions.SET_NOTIFICATIONS: set_notifications(bot, update, obj['value']) elif action == CallbackActions.NEW_BOTS_SELECTED: show_new_bots(bot, update, chat_data, back_button=True) elif action == CallbackActions.ABORT_SETTING_KEYWORDS: to_edit = Bot.get(id=obj['id']) admin.edit_bot(bot, update, chat_data, to_edit) # SENDING BOTLIST elif action == CallbackActions.SEND_BOTLIST: silent = obj.get('silent', False) re_send = obj.get('re', False) botlist.send_botlist(bot, update, resend=re_send, silent=silent) elif action == CallbackActions.RESEND_BOTLIST: botlist.send_botlist(bot, update, resend=True) # BROADCASTING elif action == 'send_broadcast': broadcasts.send_broadcast(bot, update, user_data) elif action == 'pin_message': broadcasts.pin_message(bot, update, obj['mid']) elif action == 'add_thank_you': basic.add_thank_you_button(bot, update, obj['cid'], obj['mid']) # EXPLORING elif action == CallbackActions.EXPLORE_NEXT: explore.explore(bot, update, chat_data) except Exception as e: traceback.print_exc() # get the callback action in plaintext actions = dict(CallbackActions.__dict__) a = next(k for k, v in actions.items() if v == obj.get('a')) util.send_md_message( bot, settings.ADMINS[0], "Exception in callback query for {}:\n{}\n\nWith CallbackAction {}\n\nWith data:\n{}" .format(user.markdown_short, util.escape_markdown(e), util.escape_markdown(a), util.escape_markdown(str(obj)))) finally: bot.answerCallbackQuery(update.callback_query.id) return ConversationHandler.END
# migrate( # migrator.add_column("bot", "userbot", BooleanField(default=False)) # # migrator.rename_column("transaction", "document", "document_id"), # # migrator.rename_column("document", "user", "user_id"), # ) # # print('Setting all bots to userbot=False.......') # for b in Bot.select(): # b.userbot = False # b.save() # try: # User.botlist_user_instance().delete_instance() # except: # pass Suggestion.delete().where(Suggestion.user == User.botlist_user_instance()).execute() migrate( # migrator.rename_column("bot", "manybot", "botbuilder"), # migrator.add_column("bot", "botbuilder", BooleanField(default=False)) # migrator.add_column("bot", "chat_id", IntegerField(null=True)) # migrator.rename_column("document", "user", "user_id"), ) # print('Setting all bots to botbuilder=False.......') # for b in Bot.select(): # b.botbuilder = False # b.save()
def update_suggestion(improve): if len(improve) > 0: session.add(Suggestion(content=improve)) session.commit()
def set_keywords(bot, update, chat_data, to_edit): chat_id = util.uid_from_update(update) keywords = Keyword.select().where(Keyword.entity == to_edit) chat_data['edit_bot'] = to_edit set_keywords_msgid = chat_data.get('set_keywords_msg') pending = Suggestion.select().where( Suggestion.executed == False, Suggestion.subject == to_edit, Suggestion.action << ['add_keyword', 'remove_keyword']) pending_removal = [y for y in pending if y.action == 'remove_keyword'] # Filter keywords by name to not include removal suggestions # We don't need to do this for add_keyword suggestions, because duplicates are not allowed. keywords = [ k for k in keywords if k.name not in [s.value for s in pending_removal] ] kw_remove_buttons = [ InlineCallbackButton('{} ✖️'.format(x), callback_action=CallbackActions.REMOVE_KEYWORD, params={ 'id': to_edit.id, 'kwid': x.id }) for x in keywords ] kw_remove_buttons.extend([ InlineKeyboardButton('#{} 👓✖️'.format(x.value), callback_data=util.callback_for_action( CallbackActions.DELETE_KEYWORD_SUGGESTION, { 'id': to_edit.id, 'suggid': x.id })) for x in [y for y in pending if y.action == 'add_keyword'] ]) kw_remove_buttons.extend([ InlineKeyboardButton('#{} 👓❌'.format(x.value), callback_data=util.callback_for_action( CallbackActions.DELETE_KEYWORD_SUGGESTION, { 'id': to_edit.id, 'suggid': x.id })) for x in pending_removal ]) buttons = util.build_menu( kw_remove_buttons, 2, header_buttons=[ InlineKeyboardButton(captions.DONE, callback_data=util.callback_for_action( CallbackActions.ABORT_SETTING_KEYWORDS, {'id': to_edit.id})) ]) reply_markup = InlineKeyboardMarkup(buttons) msg = util.send_or_edit_md_message( bot, chat_id, util.action_hint( 'Send me the keywords for {} one by one...\n\n{}'.format( util.escape_markdown(to_edit.username), messages.KEYWORD_BEST_PRACTICES)), to_edit=set_keywords_msgid, reply_markup=reply_markup) if msg: # message might not have been edited if the user adds an already-existing keyword # TODO: should the user be notified about this? chat_data['set_keywords_msg'] = msg.message_id return BotStates.SENDING_KEYWORDS
def toggle_value(bot, update, property_name, to_edit, value): user = User.from_update(update) if check_suggestion_limit(bot, update, user): return Suggestion.add_or_update(user, property_name, to_edit, bool(value))
def notify_bot_offline(bot, update, args=None): tg_user = update.message.from_user user = User.from_telegram_object(tg_user) if util.stop_banned(update, user): return reply_to = util.original_reply_id(update) if args: text = ' '.join(args) else: text = update.message.text command_no_args = len(re.findall( r'^/offline\s*$', text)) > 0 or text.lower().strip() == '/offline@botlistbot' if command_no_args: update.message.reply_text(util.action_hint( "Please use this command with an argument. For example:\n/offline @mybot" ), reply_to_message_id=reply_to) return # `#offline` is already checked by handler try: username = re.match(settings.REGEX_BOT_IN_TEXT, text).groups()[0] if username == '@' + settings.SELF_BOT_NAME: log.info("Ignoring {}".format(text)) return except AttributeError: if args: update.message.reply_text(util.failure( "Sorry, but you didn't send me a bot `@username`."), quote=True, parse_mode=ParseMode.MARKDOWN, reply_to_message_id=reply_to) else: log.info("Ignoring {}".format(text)) # no bot username, ignore update pass return def already_reported(): update.message.reply_text(mdformat.none_action( "Someone already reported this, thanks anyway 😊"), reply_to_message_id=reply_to) try: offline_bot = Bot.get( fn.lower(Bot.username)**username.lower(), Bot.approved == True) if offline_bot.offline: return already_reported() if offline_bot.official: update.message.reply_text(mdformat.none_action( "Official bots usually don't go offline for a long time. " "Just wait a couple hours and it will be back up ;)"), reply_to_message_id=reply_to) return try: Suggestion.get(action="offline", subject=offline_bot, executed=False) return already_reported() except Suggestion.DoesNotExist: suggestion = Suggestion(user=user, action="offline", value=True, date=datetime.date.today(), subject=offline_bot) suggestion.save() update.message.reply_text(util.success( "Thank you! We will review your suggestion and set the bot offline." ), reply_to_message_id=reply_to) except Bot.DoesNotExist: update.message.reply_text( util.action_hint("The bot you sent me is not in the @BotList."), reply_to_message_id=reply_to) return ConversationHandler.END
def register(dp: Dispatcher): keywords_handler = ConversationHandler( entry_points=[ InlineCallbackHandler( CallbackActions.EDIT_BOT_KEYWORDS, botproperties.set_keywords_init, serialize=lambda data: dict(to_edit=Bot.get(id=data['id'])), pass_chat_data=True) ], states={ BotStates.SENDING_KEYWORDS: [ MessageHandler(Filters.text, botproperties.add_keyword, pass_chat_data=True), InlineCallbackHandler( CallbackActions.REMOVE_KEYWORD, botproperties.remove_keyword, serialize=lambda data: dict(to_edit=Bot.get(id=data['id']), keyword=Keyword.get(id=data[ 'kwid'])), pass_chat_data=True), InlineCallbackHandler( CallbackActions.DELETE_KEYWORD_SUGGESTION, botproperties.delete_keyword_suggestion, serialize=lambda data: dict(to_edit=Bot.get(id=data['id']), suggestion=Suggestion.get( id=data['suggid'])), pass_chat_data=True) ], }, fallbacks=[ CallbackQueryHandler(callback_router, pass_chat_data=True, pass_user_data=True, pass_job_queue=True) ], per_user=True, allow_reentry=False) broadcasting_handler = ConversationHandler( entry_points=[ InlineCallbackHandler('broadcast', broadcasts.broadcast, pass_user_data=True), CommandHandler("broadcast", broadcasts.broadcast, pass_user_data=True), CommandHandler("bc", broadcasts.broadcast, pass_user_data=True) ], states={ BotStates.BROADCASTING: [ MessageHandler(Filters.text, broadcasts.broadcast_preview, pass_user_data=True), ], }, fallbacks=[], per_user=True, per_chat=False, allow_reentry=True) dp.add_handler(broadcasting_handler) dp.add_handler( CommandHandler(('cat', 'category', 'categories'), select_category, pass_chat_data=True)) dp.add_handler( CommandHandler(('s', 'search'), search_handler, pass_args=True, pass_chat_data=True)) dp.add_handler(MessageHandler(Filters.reply, reply_router, pass_chat_data=True), group=-1) dp.add_handler( MessageHandler(Filters.forwarded, forward_router, pass_chat_data=True)) dp.add_handler(CommandHandler("admin", admin.menu)) dp.add_handler(CommandHandler("a", admin.menu)) dp.add_handler( CommandHandler(('rej', 'reject'), admin.reject_bot_submission, pass_args=True)) dp.add_handler( CommandHandler(('rejsil', 'rejectsil', 'rejsilent', 'rejectsilent'), lambda bot, update: admin.reject_bot_submission( bot, update, None, notify_submittant=False))) # admin menu dp.add_handler( RegexHandler(captions.APPROVE_BOTS + '.*', admin.approve_bots)) dp.add_handler( RegexHandler(captions.APPROVE_SUGGESTIONS + '.*', admin.approve_suggestions)) dp.add_handler( RegexHandler(captions.PENDING_UPDATE + '.*', admin.pending_update)) dp.add_handler( RegexHandler(captions.SEND_BOTLIST, admin.prepare_transmission, pass_chat_data=True)) dp.add_handler(RegexHandler(captions.FIND_OFFLINE, admin.send_offline)) dp.add_handler( RegexHandler(captions.SEND_CONFIG_FILES, admin.send_runtime_files)) dp.add_handler( RegexHandler(captions.SEND_ACTIVITY_LOGS, admin.send_activity_logs)) # main menu dp.add_handler(RegexHandler(captions.ADMIN_MENU, admin.menu)) dp.add_handler(RegexHandler(captions.REFRESH, admin.menu)) dp.add_handler( RegexHandler(captions.CATEGORIES, select_category, pass_chat_data=True)) dp.add_handler( RegexHandler(captions.EXPLORE, explore.explore, pass_chat_data=True)) dp.add_handler( RegexHandler(captions.FAVORITES, favorites.send_favorites_list)) dp.add_handler( RegexHandler(captions.NEW_BOTS, show_new_bots, pass_chat_data=True)) dp.add_handler( RegexHandler(captions.SEARCH, search_handler, pass_chat_data=True)) dp.add_handler(RegexHandler(captions.CONTRIBUTING, help.contributing)) dp.add_handler(RegexHandler(captions.EXAMPLES, help.examples)) dp.add_handler(RegexHandler(captions.HELP, help.help)) dp.add_handler(RegexHandler("^/edit\d+$", admin.edit_bot, pass_chat_data=True), group=1) dp.add_handler(RegexHandler("^/approve\d+$", admin.edit_bot, pass_chat_data=True), group=1) dp.add_handler(CommandHandler('approve', admin.short_approve_list)) dp.add_handler(CommandHandler(('manybot', 'manybots'), admin.manybots)) dp.add_handler( CommandHandler('new', contributions.new_bot_submission, pass_args=True, pass_chat_data=True)) dp.add_handler(RegexHandler('.*#new.*', contributions.new_bot_submission, pass_chat_data=True), group=1) dp.add_handler( CommandHandler('offline', contributions.notify_bot_offline, pass_args=True)) dp.add_handler(RegexHandler('.*#offline.*', contributions.notify_bot_offline), group=1) dp.add_handler( CommandHandler('spam', contributions.notify_bot_spam, pass_args=True)) dp.add_handler(RegexHandler('.*#spam.*', contributions.notify_bot_spam), group=1) dp.add_handler( RegexHandler('^{}$'.format(settings.REGEX_BOT_ONLY), send_bot_details, pass_chat_data=True)) dp.add_handler(CommandHandler('help', help.help)) dp.add_handler( CommandHandler(("contribute", "contributing"), help.contributing)) dp.add_handler(CommandHandler("examples", help.examples)) dp.add_handler(CommandHandler("rules", help.rules)) dp.add_handler( CommandHandler(("addfav", "addfavorite"), favorites.add_favorite_handler, pass_args=True)) dp.add_handler( CommandHandler(("f", "fav", "favorites"), favorites.send_favorites_list)) dp.add_handler( CommandHandler(("e", "explore"), explore.explore, pass_chat_data=True)) dp.add_handler(CommandHandler("official", explore.show_official)) dp.add_handler( CommandHandler('ban', lambda bot, update, args: admin.ban_handler( bot, update, args, True), pass_args=True)) dp.add_handler( CommandHandler('unban', lambda bot, update, args: admin.ban_handler( bot, update, args, False), pass_args=True)) dp.add_handler(CommandHandler('t3chno', t3chnostats)) dp.add_handler(CommandHandler('random', eastereggs.send_random_bot)) dp.add_handler( CommandHandler('easteregg', eastereggs.send_next, pass_args=True)) dp.add_handler(CommandHandler("subscribe", manage_subscription)) dp.add_handler( CommandHandler("newbots", show_new_bots, pass_chat_data=True)) dp.add_handler(CommandHandler("accesstoken", access_token)) dp.add_handler( CommandHandler(('stat', 'stats', 'statistic', 'statistics'), admin.send_statistic)) dp.add_handler( CommandHandler(('log', 'logs'), admin.send_activity_logs, pass_args=True)) dp.add_handler( CommandHandler(('debug', 'analysis', 'ana', 'analyze'), lambda bot, update, args: admin.send_activity_logs( bot, update, args, Statistic.ANALYSIS), pass_args=True)) dp.add_handler( CommandHandler('info', lambda bot, update, args: admin.send_activity_logs( bot, update, args, Statistic.INFO), pass_args=True)) dp.add_handler( CommandHandler(('detail', 'detailed'), lambda bot, update, args: admin.send_activity_logs( bot, update, args, Statistic.DETAILED), pass_args=True)) dp.add_handler( CommandHandler(('warn', 'warning'), lambda bot, update, args: admin.send_activity_logs( bot, update, args, Statistic.WARN), pass_args=True)) dp.add_handler( CommandHandler('important', lambda bot, update, args: admin.send_activity_logs( bot, update, args, Statistic.IMPORTANT), pass_args=True)) dp.add_handler(MessageHandler( Filters.text, lambda bot, update: botlistchat.text_message_logger(bot, update, log)), group=99) for hashtag in HINTS.keys(): dp.add_handler(RegexHandler(r'{}.*'.format(hashtag), botlistchat.hint_handler), group=1) dp.add_handler( CommandHandler(('hint', 'hints'), botlistchat.show_available_hints)) dp.add_handler(keywords_handler) dp.add_handler( CallbackQueryHandler(callback_router, pass_chat_data=True, pass_user_data=True, pass_job_queue=True)) dp.add_handler( ChosenInlineResultHandler(inlinequeries.chosen_result, pass_chat_data=True)) dp.add_handler( InlineQueryHandler(inlinequeries.inlinequery_handler, pass_chat_data=True)) dp.add_handler(MessageHandler(Filters.all, all_handler, pass_chat_data=True), group=98)