def get_hints(query): results = {} hashtag, _, query = query.partition(' ') for k, v in HINTS.items(): if k.startswith(hashtag): reply_markup = InlineKeyboardMarkup(util.build_menu([InlineKeyboardButton( **{k: v.format(query=query) for k, v in b.items()} ) for b in v['buttons']], 1)) if 'buttons' in v else None msg = v['message'].format(query=query if query else v.get('default', '')) results[k] = Hint(help=v.get('help', ''), msg=msg, reply_markup=reply_markup) return results
def get_hint_message_and_markup(text): for k, v in HINTS.items(): if k not in text: continue text = text.replace(k, '') query = text.strip() reply_markup = None if v.get('buttons'): # Replace 'query' placeholder and expand kwargs buttons = [ InlineKeyboardButton( **{k: v.format(query=query) for k, v in b.items()}) for b in v.get('buttons') ] reply_markup = InlineKeyboardMarkup(util.build_menu(buttons, 1)) msg = v['message'].format( query=query if query else v['default'] if v.get('default') else '') return msg, reply_markup, k return None, None, None
def show_event(chat_id, i, msg_id=None): chats[chat_id]['event_selected'] = i button_list = [ InlineKeyboardButton(text="Edit Event", callback_data="/edit"), InlineKeyboardButton(text="Delete Event", callback_data="/delete"), InlineKeyboardButton(text="Add Note", callback_data="/add_note"), InlineKeyboardButton(text="« Back to List", callback_data="/all") ] reply_markup = InlineKeyboardMarkup( inline_keyboard=util.build_menu(button_list, n_cols=2)) msg = planner.show(chat_id, i) if msg_id: bot.editMessageText((chat_id, msg_id), msg, parse_mode=telegram.ParseMode.MARKDOWN, reply_markup=reply_markup) else: bot.sendMessage(chat_id, msg, parse_mode=telegram.ParseMode.MARKDOWN, reply_markup=reply_markup, disable_notification=True)
def perform_actions(self, actions: List[ChatAction]): """ Executes a sequence of `ChatActions` planned by the `DialogManager`. This includes sending messages, showing "typing" notifications, waiting when there are delays planned, and adding ReplyKeyboard buttons. """ for i, action in enumerate(actions): if action.show_typing: self.bot.send_chat_action(action.peer.telegram_id, TelegramChatAction.TYPING, timeout=20) if action.delay: time.sleep(action.delay.value if isinstance( action.delay, ChatAction.Delay) else action.delay) markup = None if action.action_type == ChatAction.Type.ASKING_QUESTION: if action.choices: buttons = [KeyboardButton(x) for x in action.choices] markup = ReplyKeyboardMarkup(util.build_menu(buttons, 3), resize_keyboard=True, one_time_keyboard=True, selective=True) else: if i < len(actions) - 1: markup = ReplyKeyboardRemove() else: markup = ForceReply() elif action.action_type == ChatAction.Type.SENDING_MEDIA: self.send_media(action.peer, action.media_id, action.render()) continue if markup is None and settings.ALWAYS_REMOVE_MARKUP: markup = ReplyKeyboardRemove() text = action.render() self.send_message(peer=action.peer, text=text, markup=markup)
def _edit_bot_buttons(to_edit: Bot, pending_suggestions: Dict, is_moderator): bid = {'id': to_edit.id} def is_pending(action): if isinstance(action, str): return action in pending_suggestions else: return any(a in pending_suggestions for a in action) def pending_or_caption(action, caption): return format_pending(str(pending_suggestions[action])) if is_pending( action) else str(caption) buttons = [ InlineKeyboardButton(pending_or_caption('name', to_edit.name or "Set Name"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_NAME, bid)), InlineKeyboardButton(pending_or_caption('username', to_edit.username), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_USERNAME, bid)), InlineKeyboardButton( # remove bulletin from category pending_or_caption( 'category', str(pending_suggestions.get('category') or to_edit.category)[1:]), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_SELECT_CAT, bid)), InlineKeyboardButton(pending_or_caption( 'description', "Change description" if to_edit.description else "Write a description"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_DESCRIPTION, bid)), InlineKeyboardButton(pending_or_caption( 'country', to_edit.country.emojized if to_edit.country else "Set country/language"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_COUNTRY, bid)), InlineKeyboardButton(pending_or_caption( 'extra', "Change extra text" if to_edit.extra else "Add an extra text"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_EXTRA, bid)), InlineKeyboardButton(format_pending("Set keywords") if is_pending( ['add_keyword', 'remove_keyword']) else 'Set keywords', callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_KEYWORDS, bid)), ] toggleable_properties = [ ('inlinequeries', '🔎', CallbackActions.EDIT_BOT_INLINEQUERIES), ('official', '🔹', CallbackActions.EDIT_BOT_OFFICIAL), ('offline', '💤', CallbackActions.EDIT_BOT_OFFLINE), ('spam', '🚮', CallbackActions.EDIT_BOT_SPAM), ] def toggle_button(property_name, emoji, callback_action): is_pending = property_name in pending_suggestions.keys() pending_emoji = captions.SUGGESTION_PENDING_EMOJI + ' ' if is_pending else '' active = bool( pending_suggestions[property_name]) if is_pending else bool( getattr(to_edit, property_name)) active_emoji = '✔️' if active else Emoji.HEAVY_MULTIPLICATION_X caption = '{}{} {}'.format(pending_emoji, emoji, active_emoji) return InlineKeyboardButton(caption, callback_data=util.callback_for_action( callback_action, { 'id': to_edit.id, 'value': not active })) for toggle in toggleable_properties: buttons.append(toggle_button(*toggle)) if is_moderator: buttons.append( InlineKeyboardButton("Delete", callback_data=util.callback_for_action( CallbackActions.CONFIRM_DELETE_BOT, bid))) header = [ InlineKeyboardButton(captions.BACK_TO_CATEGORY, callback_data=util.callback_for_action( CallbackActions.SELECT_BOT_FROM_CATEGORY, {'id': to_edit.category.id})), InlineKeyboardButton(captions.REFRESH, callback_data=util.callback_for_action( CallbackActions.EDIT_BOT, {'id': to_edit.id})) ] footer = list() if is_moderator and len(pending_suggestions) > 0: footer.append( InlineKeyboardButton("🛃 Apply all changes", callback_data=util.callback_for_action( CallbackActions.APPLY_ALL_CHANGES, {'id': to_edit.id}))) return util.build_menu(buttons, n_cols=2, header_buttons=header, footer_buttons=footer)
def cards(update: Update, context: CallbackContext): match = re.findall(r'\[\[(.*?)\]\]', update.message.text) asyncio.set_event_loop(asyncio.new_event_loop()) is_flipcard = False photos = [] button_list = [] footer_list = [] header_list = [] for index, name in enumerate(match): if index > max_cards: break try: card = scrython.cards.Named(fuzzy=name) except scrython.ScryfallError: auto = scrython.cards.Autocomplete(q=name, query=name) if len(auto.data()) > 0: text = "" for index, item in zip(range(5), auto.data()): text += '`{}`\n'.format(item) context.bot.send_message( chat_id=update.message.chat_id, text=strings.Card.card_autocorrect.format(text), parse_mode=telegram.ParseMode.MARKDOWN) continue else: context.bot.send_message( chat_id=update.message.chat_id, text=strings.Card.card_not_found.format(name), parse_mode=telegram.ParseMode.MARKDOWN) continue del card.legalities()["penny"] del card.legalities()["oldschool"] del card.legalities()["future"] del card.legalities()["duel"] banned_in = [ k for k, v in card.legalities().items() if v == "banned" or v == "not_legal" ] legal_in = [k for k, v in card.legalities().items() if v == "legal"] legal_text = "" if len(banned_in) == 0: legal_text = strings.Card.card_legal else: footer_list.append( InlineKeyboardButton("Legalities", callback_data=card.name())) for v in legal_in: legal_text += ':white_check_mark: {}\n'.format(v) for v in banned_in: legal_text += ':no_entry: {}\n'.format(v) cacheable.CACHED_LEGALITIES.update({card.name(): legal_text}) eur = '{}€'.format(card.prices(mode="eur")) if card.prices( mode="eur") is not None else "CardMarket" usd = '{}€'.format(card.prices(mode="usd")) if card.prices( mode="usd") is not None else "TCGPlayer" usd_link = card.purchase_uris().get("tcgplayer") eur_link = card.purchase_uris().get("cardmarket") img_caption = emojize(":moneybag: [" + eur + "]" + "(" + eur_link + ")" + " | " + "[" + usd + "]" + "(" + usd_link + ")" + "\n" + legal_text, use_aliases=True) try: card.card_faces() is_flipcard = True except KeyError: is_flipcard = False pass if len(match) > 1 or is_flipcard: if is_flipcard: photos.append( InputMediaPhoto( media=card.card_faces()[0]['image_uris']['normal'], caption=img_caption, parse_mode=telegram.ParseMode.MARKDOWN)) photos.append( InputMediaPhoto( media=card.card_faces()[1]['image_uris']['normal'], caption=img_caption, parse_mode=telegram.ParseMode.MARKDOWN)) else: photos.append( InputMediaPhoto(media=card.image_uris(0, image_type="normal"), caption=img_caption, parse_mode=telegram.ParseMode.MARKDOWN)) time.sleep(0.04) continue else: if card.related_uris().get("edhrec") is not None: button_list.append( InlineKeyboardButton( "Edhrec", url=card.related_uris().get("edhrec"))) if card.related_uris().get("mtgtop8") is not None: button_list.append( InlineKeyboardButton( "Top8", url=card.related_uris().get("mtgtop8"))) button_list.append( InlineKeyboardButton("Scryfall", url=card.scryfall_uri())) if card.prices(mode="usd") is not None: header_list.append( InlineKeyboardButton( '{}$'.format(card.prices(mode="usd")), url=card.purchase_uris().get("tcgplayer"))) else: header_list.append( InlineKeyboardButton("TCGPlayer", url=usd_link)) if card.prices(mode="eur") is not None: header_list.append( InlineKeyboardButton( '{}€'.format(card.prices(mode="eur")), url=card.purchase_uris().get("cardmarket"))) else: header_list.append(InlineKeyboardButton("MKM", url=eur_link)) reply_markup = InlineKeyboardMarkup( util.build_menu(button_list, header_buttons=header_list, footer_buttons=footer_list, n_cols=3)) context.bot.send_photo( chat_id=update.message.chat_id, photo=card.image_uris(0, image_type="normal"), parse_mode=telegram.ParseMode.MARKDOWN, reply_markup=reply_markup, reply_to_message_id=update.message.message_id) return if len(match) > 1 or is_flipcard: context.bot.send_media_group( chat_id=update.message.chat_id, media=photos, reply_to_message_id=update.message.message_id, disable_notification=True)
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 display_info(update, context): img_name = context.user_data[PHOTO] lang = context.user_data[LANG] speech = context.user_data[AUDIO] # Detect landmark on image try: landmarks = detect_landmarks(img_name) context.user_data[LANDMARK] = landmarks[0]['description'] context.user_data[LAT] = landmarks[0]["locations"][0]["lat_lng"][ "latitude"] context.user_data[LNG] = landmarks[0]["locations"][0]["lat_lng"][ "longitude"] ###### # p_name = Process(target=display_name, args=(update, context)) # p_name.start() display_name(update, context) ###### # Get URL try: url = google_fast_search(query=context.user_data[LANDMARK]) except: url = google_search(query=context.user_data[LANDMARK], num_res=1)[0] logger.info(f'[URL] {url}') ###### # p_image = Process(target=display_image, args=(update, context, landmarks)) # p_image.start() display_image(update, context, landmarks) ###### # Get informative text info_text = get_entry_text(url) if len(info_text) < 500: info_text = get_text_maxChars(url, maxChars=5000) # logger.info('[INFO TEXT SCRAPPED]') # Translate text sleep(0.2) trans_text = my_translate(update, context, info_text, lang) # print(trans_text) # translate(info_text, source_language='en', dest_language=lang) # logger.info('[TRADUCCION DONE]') ###### # p_text = Process(target=display_text, args=(update, context, trans_text)) # p_text.start() text_promise = display_text(update, context, trans_text) ###### # Generate audio if speech: ###### # p_audio = Process(target=display_audio, args=(update, context, trans_text)) # p_audio.start() audio_promise = generate_audio(update, context, trans_text) text_promise.result() display_audio(update, context, audio_promise) ###### else: text_promise.result() except AttributeError: update.message.reply_text( text=texts.NO_LANDMARK[context.user_data[LANG]] + u' \U0001F625') except: update.message.reply_text(text=texts.NO_INFO[context.user_data[LANG]] + u' \U0001F625') # ###### # p_name.join() # p_image.join() # p_text.join() # p_audio.join() # ###### # Ask to continue button_list = [ InlineKeyboardButton('{} {}'.format( texts.YES_NO[context.user_data[LANG]]['yes'], u'\U0001F44D'), callback_data='yes'), InlineKeyboardButton('{} {}'.format( texts.YES_NO[context.user_data[LANG]]['no'], u'\U0001F44E'), callback_data='no'), ] langs_markup = InlineKeyboardMarkup(util.build_menu(button_list, n_cols=2)) update.message.reply_text( text=texts.CONTINUE_QUESTION[context.user_data[LANG]], reply_markup=langs_markup, resize_keyboard=True, ) return DISPLAY_INFO
import logging logger = logging.getLogger(__name__) # State definitions for Telegram Bot (SELECTING_LANG, SELECTING_AUDIO, SELECTING_PICT, DISPLAY_INFO) = map(chr, range(4)) # Shortcut for ConversationHandler.END END = ConversationHandler.END # Different constants for this example (START_OVER, LANG, AUDIO, PHOTO, LANDMARK, LAT, LNG) = map(chr, range(10, 17)) # Keyboard buttons button_list = ['/start', '/settings', '/help', '/exit'] keyboard = ReplyKeyboardMarkup(util.build_menu(button_list, n_cols=1)) PHOTO_DIR = None def start(update, context): """Displays welcome message.""" # choose_lang = True # If we're starting over we don't need do send a new message if not context.user_data.get(START_OVER): user = update.message.from_user try: context.user_data[LANG] = user.language_code logger.info( f'User language: {texts.LANGUAGE[context.user_data[LANG]]["name"]}'
def send_bot_details(bot, update, chat_data, item=None): is_group = util.is_group_message(update) cid = update.effective_chat.id user = User.from_update(update) if item is None: if is_group: return try: text = update.message.text bot_in_text = re.findall(settings.REGEX_BOT_IN_TEXT, text)[0] item = Bot.by_username(bot_in_text, include_disabled=True) except Bot.DoesNotExist: update.message.reply_text( util.failure( "This bot is not in the @BotList. If you think this is a " "mistake, see the /examples for /contributing.")) return header_buttons = [] buttons = [] if item.disabled: txt = '{} {} and thus removed from the @BotList.'.format( item, Bot.DisabledReason.to_str(item.disabled_reason)) elif item.approved: # bot is already in the botlist => show information txt = item.detail_text if item.description is None and not Keyword.select().where( Keyword.entity == item).exists(): txt += ' is in the @BotList.' btn = InlineCallbackButton(captions.BACK_TO_CATEGORY, CallbackActions.SELECT_BOT_FROM_CATEGORY, {'id': item.category.id}) header_buttons.insert(0, btn) header_buttons.append( InlineKeyboardButton(captions.SHARE, switch_inline_query=item.username)) # if cid in settings.MODERATORS: header_buttons.append( InlineKeyboardButton("📝 Edit", callback_data=util.callback_for_action( CallbackActions.EDIT_BOT, {'id': item.id}))) # Add favorite button favorite_found = Favorite.search_by_bot(user, item) if favorite_found: buttons.append( InlineKeyboardButton(captions.REMOVE_FAVORITE_VERBOSE, callback_data=util.callback_for_action( CallbackActions.REMOVE_FAVORITE, { 'id': favorite_found.id, 'details': True }))) else: buttons.append( InlineKeyboardButton(captions.ADD_TO_FAVORITES, callback_data=util.callback_for_action( CallbackActions.ADD_TO_FAVORITES, { 'id': item.id, 'details': True }))) else: txt = '{} is currently pending to be accepted for the @BotList.'.format( item) if cid in settings.MODERATORS: header_buttons.append( InlineKeyboardButton("🛃 Accept / Reject", callback_data=util.callback_for_action( CallbackActions.APPROVE_REJECT_BOTS, {'id': item.id}))) if buttons or header_buttons: reply_markup = InlineKeyboardMarkup( util.build_menu(buttons, n_cols=3, header_buttons=header_buttons)) else: reply_markup = None reply_markup, callback = botlistchat.append_delete_button( update, chat_data, reply_markup) # Should we ever decide to show thumbnails *shrug* # if os.path.exists(item.thumbnail_file): # preview = True # photo = '[\xad]({})'.format('{}/thumbnail/{}.jpeg'.format( # settings.API_URL, # item.username[1:] # )) # log.info(photo) # txt = photo + txt # else: # preview = False msg = bot.formatter.send_or_edit(cid, txt, to_edit=util.mid_from_update(update), reply_markup=reply_markup) callback(msg) Statistic.of(update, 'view-details', item.username, Statistic.ANALYSIS) return CallbackStates.SHOWING_BOT_DETAILS
def configure(bot, update, edit=False): if update.message.from_user.id in config.admin_id or edit or bot.get_chat_member( update.message.chat_id, update.message.from_user.id).status in [ "creator", "administrator" ]: btns = [] db = MySQLdb.connect(config.database['server'], config.database['user'], config.database['password'], config.database['name']) db.autocommit(True) cur = db.cursor() cur.execute("SELECT * FROM Groups WHERE Chat_ID = '" + str(update.message.chat_id) + "'") row = cur.fetchone() btns.append( InlineKeyboardButton((strings.CONF_ANTISPAM_WORDS % ("On" if row[5] == 1 else "Off")), callback_data='conf_spam_words')) btns.append( InlineKeyboardButton((strings.CONF_ANTISPAM_NON_WEST % ("On" if row[11] == 1 else "Off")), callback_data='conf_spam_non_west')) btns.append( InlineKeyboardButton((strings.CONF_ANTISPAM_USERNAME % ("On" if row[6] == 1 else "Off")), callback_data='conf_spam_username')) btns.append( InlineKeyboardButton((strings.CONF_ANTISPAM_USER % ("On" if row[7] == 1 else "Off")), callback_data='conf_spam_user')) btns.append( InlineKeyboardButton( (strings.CONF_ANTISCAM % ("On" if row[8] == 1 else "Off")), callback_data='conf_scam')) btns.append( InlineKeyboardButton( (strings.CONF_BLACKLIST % ("On" if row[9] == 1 else "Off")), callback_data='conf_blacklist')) btns.append( InlineKeyboardButton( (strings.CONF_HAMMER % ("Open" if row[10] == 1 else "Close")), callback_data='conf_hammer')) if update.message.from_user.id in config.super_admin_id: btns.append( InlineKeyboardButton(strings.CONF_LEAVE, callback_data='conf_leave')) btns.append( InlineKeyboardButton(strings.CONF_CLOSE_MENU, callback_data='conf_close_menu')) reply_markup = InlineKeyboardMarkup(util.build_menu(btns, n_cols=1)) if edit: aid = re.search('{{(.*)}}', update.message.text).group(1) bot.edit_message_text((strings.CONF_MENU_HEADER % aid), reply_markup=reply_markup, parse_mode=ParseMode.HTML, chat_id=update.message.chat_id, message_id=update.message.message_id) else: bot.send_message( update.message.chat_id, (strings.CONF_MENU_HEADER % str(update.message.from_user.id)), reply_markup=reply_markup, parse_mode=ParseMode.HTML) cur.close() db.close()
def _edit_bot_buttons(to_edit: Bot, pending_suggestions: Dict, is_moderator): bid = {"id": to_edit.id} def is_pending(action): if isinstance(action, str): return action in pending_suggestions else: return any(a in pending_suggestions for a in action) def pending_or_caption(action, caption): return (format_pending(str(pending_suggestions[action])) if is_pending(action) else str(caption)) buttons = [ InlineKeyboardButton( pending_or_caption("name", to_edit.name or "Set Name"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_NAME, bid), ), InlineKeyboardButton( pending_or_caption("username", to_edit.username), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_USERNAME, bid), ), InlineKeyboardButton( # remove bulletin from category pending_or_caption( "category", str(pending_suggestions.get("category") or to_edit.category)[1:] if to_edit.category else "Choose a category", ), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_SELECT_CAT, bid), ), InlineKeyboardButton( pending_or_caption( "description", "Change description" if to_edit.description else "Write a description", ), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_DESCRIPTION, bid), ), InlineKeyboardButton( pending_or_caption( "country", to_edit.country.emojized if to_edit.country else "Set country/language", ), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_COUNTRY, bid), ), InlineKeyboardButton( pending_or_caption( "extra", "Change extra text" if to_edit.extra else "Add an extra text"), callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_EXTRA, bid), ), InlineKeyboardButton( format_pending("Set keywords") if is_pending( ["add_keyword", "remove_keyword"]) else "Set keywords", callback_data=util.callback_for_action( CallbackActions.EDIT_BOT_KEYWORDS, bid), ), ] toggleable_properties = [ ("inlinequeries", "🔎", CallbackActions.EDIT_BOT_INLINEQUERIES), ("official", "🔹", CallbackActions.EDIT_BOT_OFFICIAL), # ('offline', '💤', CallbackActions.EDIT_BOT_OFFLINE), ("spam", "🚮", CallbackActions.EDIT_BOT_SPAM), ] def toggle_button(property_name, emoji, callback_action): is_pending = property_name in pending_suggestions.keys() pending_emoji = captions.SUGGESTION_PENDING_EMOJI + " " if is_pending else "" active = (bool(pending_suggestions[property_name]) if is_pending else bool(getattr(to_edit, property_name))) active_emoji = "✔️" if active else Emoji.HEAVY_MULTIPLICATION_X caption = "{}{} {}".format(pending_emoji, emoji, active_emoji) return InlineKeyboardButton( caption, callback_data=util.callback_for_action(callback_action, { "id": to_edit.id, "value": not active }), ) for toggle in toggleable_properties: buttons.append(toggle_button(*toggle)) if is_moderator: buttons.append( InlineKeyboardButton( "Delete", callback_data=util.callback_for_action( CallbackActions.CONFIRM_DELETE_BOT, bid), )) header = [] if to_edit.category: header.append( InlineKeyboardButton( captions.BACK_TO_CATEGORY, callback_data=util.callback_for_action( CallbackActions.SELECT_BOT_FROM_CATEGORY, {"id": to_edit.category.id}, ), )) header.append( InlineKeyboardButton( captions.REFRESH, callback_data=util.callback_for_action(CallbackActions.EDIT_BOT, {"id": to_edit.id}), )) footer = list() if is_moderator and len(pending_suggestions) > 0: footer.append( InlineKeyboardButton( "🛃 Apply all changes", callback_data=util.callback_for_action( CallbackActions.APPLY_ALL_CHANGES, {"id": to_edit.id}), )) return util.build_menu(buttons, n_cols=2, header_buttons=header, footer_buttons=footer)