def _build_reply_markup(num, rating): buttons = [ InlineKeyboardButton("ЪЉј", callback_data=f"{num}+-1"), InlineKeyboardButton(f"{rating:+}", callback_data=f"{num}+1"), InlineKeyboardButton("ЪЉЇ", callback_data=f"{num}+1"), ] return InlineKeyboardMarkup.from_row(buttons)
def send_start(update: Update, context: CallbackContext): """Connect the user with admins group in case of private chat,\ else show the bot's description.""" if update.message.chat.type != update.message.chat.PRIVATE: update.message.reply_html(Message.START_GROUP) context.bot_data["lastUserId"] = Literal.ADMINS_GROUP_ID return buttons = [Button.BLOCK, Button.CONNECT] database = context.bot_data["database"] keyboard = InlineKeyboardMarkup.from_row(buttons) user = update.message.from_user user_id = user.id full_name = user.full_name membership = get_membership(user_id, context) username = f"@{user.username}" if user.username else None text = Message.USER_CONNECTED.format( FULL_NAME=full_name, USER_ID=user_id, USERNAME=username, MEMBERSHIP=membership, BLOCKED=False, ) update.message.reply_html( Message.START_PRIVATE.format(GROUP_NAME=Literal.GROUP_NAME)) message = context.bot.send_message( chat_id=Literal.ADMINS_GROUP_ID, text=text, reply_markup=keyboard, ) database.add_user_message(update.message.message_id, user_id, message.message_id)
def test_from_row(self): inline_keyboard_markup = InlineKeyboardMarkup.from_row([ InlineKeyboardButton(text='button1', callback_data='data1'), InlineKeyboardButton(text='button1', callback_data='data1'), ]).inline_keyboard assert len(inline_keyboard_markup) == 1 assert len(inline_keyboard_markup[0]) == 2
def say_potato_command(update: Update, context: CallbackContext) -> None: message = cast(Message, update.effective_message) who_banned = cast(User, message.from_user) chat = cast(Chat, update.effective_chat) # This check will fail if we add or remove admins at runtime but that is so rare that # we can just restart the bot in that case ... admins = cast(Dict, context.chat_data).setdefault("admins", chat.get_administrators()) if who_banned not in [admin.user for admin in admins]: message.reply_text( "This command is only available for admins. You are not an admin.") return message.delete() if not message.reply_to_message: return user = cast(User, message.reply_to_message.from_user) if context.args: try: time_limit = int(context.args[0]) except ValueError: time_limit = 60 else: time_limit = 60 correct, incorrect_1, incorrect_2 = random.sample(VEGETABLES, 3) message_text = ( f"You display behavior that is common for userbots, i.e. automated Telegram " f"accounts that usually produce spam. Please verify that you are not a userbot by " f"clicking the button that says »<code>{correct}</code>«.\nIf you don't press the button " f"within {time_limit} minutes, you will be banned from the PTB groups. If you miss the " f"time limit but are not a userbot and want to get unbanned, please contact " f"{who_banned.mention_html()}.") answers = random.sample([(correct, True), (incorrect_1, False), (incorrect_2, False)], 3) keyboard = InlineKeyboardMarkup.from_row([ InlineKeyboardButton(text=veg, callback_data=f"POTATO {user.id} {truth}") for veg, truth in answers ]) potato_message = message.reply_to_message.reply_text(message_text, reply_markup=keyboard) cast(JobQueue, context.job_queue).run_once( say_potato_job, time_limit * 60, context=( user.id, potato_message, message.from_user, ), name=f"POTATO {user.id}", )
def format_page(pool_id, title_type, page, page_count, titles): has_after = page < page_count has_before = page > 1 buttons = [] if has_before: buttons.append( InlineKeyboardButton("Previous page", callback_data='titles:list:prev')) if has_after: buttons.append( InlineKeyboardButton("Next page", callback_data='titles:list:next')) if titles: titles_str = '\n'.join( f'`{escape_markdown(str(t.id), version=2)}` {escape_markdown(t.text, version=2)}' for t in titles) else: titles_str = strings.NO_TITLES_FOUND if pool_id is DEFAULTS_POOL_ID: header = strings.TEMPLATE_TITLE_LIST_HEADER.format( title_type=title_type.value) else: header = strings.CHAT_TITLE_LIST_HEADER.format( title_type=title_type.value, chat_id=pool_id) message_lines = [header, '', titles_str] if page_count > 1: message_lines.extend(('', f'page: {page} / {page_count}')) message_text = '\n'.join(message_lines) reply_markup = InlineKeyboardMarkup.from_row(buttons) if buttons else None return dict(text=message_text, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN_V2)
def search_by_isbn(update: Update, context: CallbackContext): context.user_data["baseMessage"].edit_reply_markup() chat = update.effective_chat query = update.message.text chat.send_action(TYPING) res = get_book_by_isbn(query) query = query.replace(" ", "+") buttons = [InlineKeyboardButton(text=Label.BACK, callback_data="suggest")] if res: name = res[0] authors = res[1] genres = res[2] authors_str = " ,".join(authors) context.user_data["results"] = [(name, authors, genres)] book = Message.BOOK.format(BOOK_NAME=name, AUTHORS=authors_str) text = Message.CONFIRM_BOOK.format(BOOK=book) buttons.insert( 0, InlineKeyboardButton(text=Label.YES, callback_data="suggest_0")) else: text = Message.NO_RESULTS.format(QUERY=query) keyboard = InlineKeyboardMarkup.from_row(buttons) context.user_data["redirectUpdate"] = search_by_isbn base_msg = chat.send_message(text=text, reply_markup=keyboard, parse_mode=HTML, disable_web_page_preview=True) context.user_data["baseMessage"] = base_msg
def parse_raw(update: Update, context: CallbackContext): context.user_data["baseMessage"].edit_reply_markup() chat = update.effective_chat details = update.message.text lx = details.splitlines() buttons = [InlineKeyboardButton(text=Label.BACK, callback_data="suggest")] if len(lx) == 3: name = lx[0] authors = lx[1].split(",") genres = lx[2].split(",") authors_str = " ,".join(authors) context.user_data["results"] = [(name, authors, genres)] book = Message.BOOK.format(BOOK_NAME=name, AUTHORS=authors_str) text = Message.CONFIRM_BOOK.format(BOOK=book) buttons.insert( 0, InlineKeyboardButton(text=Label.YES, callback_data="suggest_0")) else: text = Message.INVALID_RAW_FORMAT keyboard = InlineKeyboardMarkup.from_row(buttons) context.user_data["redirectUpdate"] = parse_raw base_msg = chat.send_message(text=text, reply_markup=keyboard, parse_mode=HTML) context.user_data["baseMessage"] = base_msg
def test_clear_all(self, callback_data_cache, method): changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') reply_markup = InlineKeyboardMarkup.from_row( [changing_button_1, changing_button_2]) for i in range(100): out = callback_data_cache.process_keyboard(reply_markup) callback_query = CallbackQuery( str(i), from_user=None, chat_instance=None, data=out.inline_keyboard[0][1].callback_data, ) callback_data_cache.process_callback_query(callback_query) if method == 'callback_data': callback_data_cache.clear_callback_data() # callback_data was cleared, callback_queries weren't assert len(callback_data_cache.persistence_data[0]) == 0 assert len(callback_data_cache.persistence_data[1]) == 100 else: callback_data_cache.clear_callback_queries() # callback_queries were cleared, callback_data wasn't assert len(callback_data_cache.persistence_data[0]) == 100 assert len(callback_data_cache.persistence_data[1]) == 0
def create_inline_keyboard(match_id, response_format="default"): match_id = str(match_id) button_default = InlineKeyboardButton( "Scoreboard", callback_data=(f"match {match_id}") ) button_players = InlineKeyboardButton( "Players/Ranks", callback_data=(f"match {match_id} players") ) button_damage = InlineKeyboardButton( "Damage/Heal", callback_data=(f"match {match_id} damage") ) button_order = InlineKeyboardButton( "Picks/Bans", callback_data=(f"match {match_id} order") ) # Exclude the current view from the inline keyboard if response_format == "players": buttons = [button_default, button_damage, button_order] elif response_format == "damage": buttons = [button_default, button_players, button_order] elif response_format == "order": buttons = [button_default, button_players, button_damage] else: buttons = [button_players, button_damage, button_order] markup = InlineKeyboardMarkup.from_row(buttons) return markup
def show_buttons(update, context): proposal = context.user_data['proposal'] buttons = [] if proposal.finish: text = 'Create PFD' callback_data = CREATE_PDF elif proposal.info: proposal.info = False text = 'Add info' callback_data = ADD_INFO else: text = 'Choose engineer' callback_data = CHOOSE_ENGINEER btn1 = add_button('Edit info', CHOOSE_TITLE_TO_EDIT) btn2 = add_button(text, callback_data) buttons = append_btns(buttons, btn1, btn2) text = '<b>What`s next?</b>' keyboard = InlineKeyboardMarkup.from_row(buttons) # add this check to send_message(), # because there is a need to use this often if getattr(update, 'callback_query'): edit = True update.callback_query.answer() else: edit = False send_message(update, text, keyboard, edit=edit, parse='HTML') return SELECT_ACTION
def on_callback_coin_flip(update: Update, context: CallbackContext): message = update.effective_message query = update.callback_query query.answer() reply_markup = InlineKeyboardMarkup.from_row([ InlineKeyboardButton( '🔁 Повторить', callback_data=fill_string_pattern(PATTERN_COIN_FLIP)), InlineKeyboardButton( '❌ Убрать', callback_data=fill_string_pattern(PATTERN_HIDE_COIN_FLIP)), ]) value = random.choice(list(COIN_VARIANTS)) f = open(COIN_VARIANTS[value], 'rb') is_new = not message.photo if is_new: message.reply_photo(f, caption=f"🍀 Бросок: {value}", reply_markup=reply_markup, reply_to_message_id=message.message_id) else: message.edit_media(InputMediaPhoto(f, f'{message.caption}, {value}'), reply_markup=reply_markup)
def deny_confirm(update, context): update.callback_query.edit_message_text( text=f"如果没有找到您主持的播客,请联系我们", reply_markup=InlineKeyboardMarkup.from_row(([ InlineKeyboardButton('重新申请认证', callback_data='request_host'), InlineKeyboardButton('联系客服', url=f'https://t.me/{dev_name}') ]))) return -1
def start(update: Update, context: CallbackContext): base_message = context.user_data.get("baseMessage", None) database = context.bot_data["database"] chat = update.effective_chat sess_type = context.user_data["sessionType"] user_id = update.effective_user.id if sess_type == Constants.FICTION_SESSION: genre = Constants.FICTION_GENRE max_count = Constants.FICTION_COUNT elif sess_type == Constants.NONFICTION_SESSION: genre = Constants.NONFICTION_GENRE max_count = Constants.NONFICTION_COUNT if base_message: books_iter = context.user_data["books"] else: if sess_type == Constants.FICTION_SESSION: books_iter = database.get_fiction_books(user_id) elif sess_type == Constants.NONFICTION_SESSION: books_iter = database.get_nonfiction_books(user_id) books = [] books_str = [] count = 0 for book_name, authors in books_iter: authors_str = " ,".join(authors) books.append((book_name, authors)) books_str.append(Message.BOOK.format(BOOK_NAME=book_name, AUTHORS=authors_str)) count += 1 context.user_data["books"] = books books_txt = "\n".join(books_str) if count == 0: text = Message.EMPTY_SUGGESTIONS.format(GENRE=genre) buttons = InlineKeyboardMarkup.from_button(Button.SUGGEST) elif count < max_count: left = max_count - count s = "s" * (left != 1) text = Message.HALF_SUGGESTIONS.format( BOOKS=books_txt, GENRE=genre, LEFT=left, S=s ) buttons = InlineKeyboardMarkup.from_row([Button.SUGGEST, Button.REMOVE]) else: s = "s" * (max_count != 1) text = Message.FULL_SUGGESTIONS.format(BOOKS=books_txt, GENRE=genre, S=s) buttons = InlineKeyboardMarkup.from_button(Button.REMOVE, COUNT=count) if context.user_data.pop("newMessage", False): base_msg = chat.send_message(text=text, reply_markup=buttons, parse_mode=HTML) else: base_msg = base_message.edit_text( text=text, reply_markup=buttons, parse_mode=HTML ) context.user_data["baseMessage"] = base_msg
def test_build_inline_keyboard_existing_buttons(build_inline_keyboard, private): msg = build_dummy_message(private, private) msg.text = "__text__" markup = InlineKeyboardMarkup.from_row([ InlineKeyboardButton("__button_a__"), InlineKeyboardButton("__button_b__"), ]) keyboard = build_inline_keyboard(msg, "__template__", "__reactions__", markup) seq = keyboard_to_sequence(keyboard) assert "__button_a__" in seq assert "__button_b__" in seq assert "__text__" in seq assert "__template__" in seq assert "__reactions__" in seq
def unsubscribe_podcast(update, context): run_async = context.dispatcher.run_async query = update.callback_query podcast_id = re.match(r'unsubscribe_podcast_(.+)', query.data)[1] podcast_name = Podcast.objects(id=podcast_id).only('name').first().name run_async(query.message.edit_text, text=f"确认退订 {podcast_name} 吗?", reply_markup=InlineKeyboardMarkup.from_row([ InlineKeyboardButton( "返回", callback_data=f"back_to_actions_{podcast_id}"), InlineKeyboardButton( "退订", callback_data=f"confirm_unsubscribe_{podcast_id}") ])) run_async(query.answer, f"退订后,未来将不会收到 {podcast_name} 的更新。")
def make_credits_keyboard( from_name=None, from_username=None, forward_name=None, forward_username=None, forward_chat_name=None, forward_chat_username=None, forward_chat_message_id=None, ): if not from_name: return buttons = [] # user if from_username: from_user_button = InlineKeyboardButton( f'by {from_name}', url=f'https://t.me/{from_username}', ) else: from_user_button = InlineKeyboardButton( f"by {from_name}", callback_data=EMPTY_CB_DATA, ) buttons.append(from_user_button) # forward user if forward_name and from_username != forward_username: if forward_username: button = InlineKeyboardButton( text=f"from {forward_name}", url=f'https://t.me/{forward_username}', ) buttons.append(button) else: from_user_button.text += f', from {forward_name}' # forward_chat if forward_chat_username: button = InlineKeyboardButton( text=f"from {forward_chat_name}", url= f'https://t.me/{forward_chat_username}/{forward_chat_message_id}', ) buttons.append(button) return InlineKeyboardMarkup.from_row(buttons)
def check_update(self, context): last_updated_time = self.updated_time result = self.parse_feed() if not result: return # context.bot.send_message( # dev, f"{self.name}\n上次更新 {str(last_updated_time)}\n最近更新 {str(self.updated_time)}") if last_updated_time < self.updated_time: context.bot.send_message(dev, f'{self.name} 检测到更新,更新中…') self.update_feed(result, init=False) # else: # context.bot.send_message(dev, f'{self.name} 未检测到更新') for episode in self.episodes: if episode.is_downloaded: continue context.bot.send_message(dev, f'开始下载:{self.name} - {episode.title}') try: audio = download(episode, context) message = context.bot.send_audio( chat_id=f'@{podcast_vault}', audio=audio, caption=(f"{SPEAKER_MARK} *{self.name}*\n\n" f"#{self.id}"), reply_markup=InlineKeyboardMarkup.from_row([ InlineKeyboardButton( '订阅', url= f'https://t.me/{manifest.bot_id}?start=p{self.id}' ), InlineKeyboardButton('相关链接', url=episode.shownotes_url) ]), title=episode.title, performer=self.name, duration=episode.duration, thumb=episode.logo.path) episode.is_downloaded = True episode.message_id = message.message_id episode.file_id = message.audio.file_id episode.save() return message except TimedOut as e: context.bot.send_message(dev, '下载超时!') pass except Exception as e: context.bot.send_message(dev, f'{e}') continue
def verify_photo(update, context): user = update.effective_user context.bot.send_photo( chat_id=dev, photo=update.message.photo[0], caption=f"{user.first_name} 想要成为 XX 播客的认证主播", reply_markup=InlineKeyboardMarkup.from_row([ InlineKeyboardButton( '拒绝', callback_data=f"deny_host_{update.effective_user.id}"), InlineKeyboardButton( '通过', callback_data=f"pass_host_{update.effective_user.id}"), ])).pin() update.message.reply_text( text=f"图片上传成功,请耐心等待审核。\n\n审核通常会在一个工作日内完成,如果长时间没有收到回复,可直接联系我们", reply_markup=InlineKeyboardMarkup.from_button( InlineKeyboardButton('联系客服', url=f'https://t.me/{dev_name}'))) return -1
def handle_rss(update, context): podcast = None # try: # # 需要先处理 text 的格式,比如没带 https\大小写统一等问题 # podcast = Podcast.objects(feed=update.message.text).first() # except: # pass # 用 feedparser 处理 feed update.message.reply_text( text=(f"播客名称:" f"订阅地址:" f"联系方式:" f"请确认这是否是您主持的播客:"), reply_markup=InlineKeyboardMarkup.from_row([ InlineKeyboardButton('这不是我的播客', callback_data='deny_podcast'), InlineKeyboardButton('确认', callback_data=f'confirm_podcast_{podcast}') ])) return CONFIRM
def test_process_keyboard_full(self, bot): cdc = CallbackDataCache(bot, maxsize=1) changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') non_changing_button = InlineKeyboardButton('non-changing', url='https://ptb.org') reply_markup = InlineKeyboardMarkup.from_row( [non_changing_button, changing_button_1, changing_button_2]) out1 = cdc.process_keyboard(reply_markup) assert len(cdc.persistence_data[0]) == 1 out2 = cdc.process_keyboard(reply_markup) assert len(cdc.persistence_data[0]) == 1 keyboard_1, button_1 = cdc.extract_uuids( out1.inline_keyboard[0][1].callback_data) keyboard_2, button_2 = cdc.extract_uuids( out2.inline_keyboard[0][2].callback_data) assert cdc.persistence_data[0][0][0] != keyboard_1 assert cdc.persistence_data[0][0][0] == keyboard_2
def on_callback_coin_flip(update: Update, context: CallbackContext): message = update.effective_message query = update.callback_query query.answer() reply_markup = InlineKeyboardMarkup.from_row([ get_button_coin_flip(text_of.BTN_COIN_FLIP_REPEAT), get_button_delete_message(text_of.BTN_COIN_FLIP_HIDE), ]) value = random.choice(list(COIN_VARIANTS)) f = open(COIN_VARIANTS[value], 'rb') is_new = not message.photo if is_new: message.reply_photo(f, caption=f"{text_of.BTN_COIN_FLIP_RESULT}: {value}", reply_markup=reply_markup, quote=True) else: message.edit_media(InputMediaPhoto(f, f'{message.caption}, {value}'), reply_markup=reply_markup)
def test_drop_data(self, callback_data_cache): changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') reply_markup = InlineKeyboardMarkup.from_row( [changing_button_1, changing_button_2]) out = callback_data_cache.process_keyboard(reply_markup) callback_query = CallbackQuery( '1', from_user=None, chat_instance=None, data=out.inline_keyboard[0][1].callback_data, ) callback_data_cache.process_callback_query(callback_query) assert len(callback_data_cache.persistence_data[1]) == 1 assert len(callback_data_cache.persistence_data[0]) == 1 callback_data_cache.drop_data(callback_query) assert len(callback_data_cache.persistence_data[1]) == 0 assert len(callback_data_cache.persistence_data[0]) == 0
def block_user_cb(update: Update, context: CallbackContext): """Block the user for the incoming callback query.""" update.callback_query.answer() database = context.bot_data["database"] message = update.callback_query.message user_id, _ = database.get_user_message_id_from_users(message.message_id) msg_id = block_user(user_id, context) membership = get_membership(user_id, context) username, full_name, blocked = database.get_user(user_id) edit_text = Message.USER_CONNECTED.format( FULL_NAME=full_name, USER_ID=user_id, USERNAME=username, MEMBERSHIP=membership, BLOCKED=blocked, ) text = Message.BLOCKED_USER.format(USER_ID=user_id, FULL_NAME=full_name) markup = InlineKeyboardMarkup.from_row([Button.UNBLOCK, Button.CONNECT]) message.edit_text(text=edit_text, reply_markup=markup) message = message.reply_html(text) database.add_admin_message(0, user_id, msg_id) database.add_user_message(1, user_id, message.message_id) context.bot_data["lastUserId"] = Literal.ADMINS_GROUP_ID
def test_process_keyboard(self, callback_data_cache): changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') non_changing_button = InlineKeyboardButton('non-changing', url='https://ptb.org') reply_markup = InlineKeyboardMarkup.from_row( [non_changing_button, changing_button_1, changing_button_2]) out = callback_data_cache.process_keyboard(reply_markup) assert out.inline_keyboard[0][0] is non_changing_button assert out.inline_keyboard[0][1] != changing_button_1 assert out.inline_keyboard[0][2] != changing_button_2 keyboard_1, button_1 = callback_data_cache.extract_uuids( out.inline_keyboard[0][1].callback_data) keyboard_2, button_2 = callback_data_cache.extract_uuids( out.inline_keyboard[0][2].callback_data) assert keyboard_1 == keyboard_2 assert (callback_data_cache._keyboard_data[keyboard_1]. button_data[button_1] == 'some data 1') assert (callback_data_cache._keyboard_data[keyboard_2]. button_data[button_2] == 'some data 2')
def test_drop_data_missing_data(self, callback_data_cache): changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') reply_markup = InlineKeyboardMarkup.from_row( [changing_button_1, changing_button_2]) out = callback_data_cache.process_keyboard(reply_markup) callback_query = CallbackQuery( '1', from_user=None, chat_instance=None, data=out.inline_keyboard[0][1].callback_data, ) with pytest.raises(KeyError, match='CallbackQuery was not found in cache.'): callback_data_cache.drop_data(callback_query) callback_data_cache.process_callback_query(callback_query) callback_data_cache.clear_callback_data() callback_data_cache.drop_data(callback_query) assert callback_data_cache.persistence_data == ([], {})
# Keyboards DELETE = 'DELETE' """obj:`str`: Callback data for deleting a setting.""" YES = 'Ja' """obj:`str`: Callback data for "yes".""" NO = 'Nein' """obj:`str`: Callback data for "no".""" CORRECT = 'Richtig' """obj:`str`: Callback data for "correct".""" TG_PROFILE_PICTURE = 'TG_PROFILE_PICTURE' """obj:`str`: Callback data indicating that the profile picture of a user should be used as picture. """ BACK_OR_DELETE_KEYBOARD = InlineKeyboardMarkup.from_row( [ InlineKeyboardButton(text=BACK, callback_data=BACK), InlineKeyboardButton(text='Löschen', callback_data=DELETE), ] ) """:class:`telegram.InlineKeyboardMarkup`: Keyboard for either leaving the setting as is or deleting its current value.""" YES_NO_KEYBOARD = InlineKeyboardMarkup.from_row( [ InlineKeyboardButton(text=YES, callback_data=YES), InlineKeyboardButton(text=NO, callback_data=NO), ] ) """:class:`telegram.InlineKeyboardMarkup`: Keyboard for a yes or no choice.""" GENDER_KEYBOARD = InlineKeyboardMarkup( [ [ InlineKeyboardButton(text=Gender.MALE, callback_data=Gender.MALE),
def test_process_callback_query(self, callback_data_cache, data, message, invalid): """This also tests large parts of process_message""" changing_button_1 = InlineKeyboardButton('changing', callback_data='some data 1') changing_button_2 = InlineKeyboardButton('changing', callback_data='some data 2') non_changing_button = InlineKeyboardButton('non-changing', url='https://ptb.org') reply_markup = InlineKeyboardMarkup.from_row( [non_changing_button, changing_button_1, changing_button_2]) out = callback_data_cache.process_keyboard(reply_markup) if invalid: callback_data_cache.clear_callback_data() effective_message = Message(message_id=1, date=None, chat=None, reply_markup=out) effective_message.reply_to_message = deepcopy(effective_message) effective_message.pinned_message = deepcopy(effective_message) cq_id = uuid4().hex callback_query = CallbackQuery( cq_id, from_user=None, chat_instance=None, # not all CallbackQueries have callback_data data=out.inline_keyboard[0][1].callback_data if data else None, # CallbackQueries from inline messages don't have the message attached, so we test that message=effective_message if message else None, ) callback_data_cache.process_callback_query(callback_query) if not invalid: if data: assert callback_query.data == 'some data 1' # make sure that we stored the mapping CallbackQuery.id -> keyboard_uuid correctly assert len(callback_data_cache._keyboard_data) == 1 assert (callback_data_cache._callback_queries[cq_id] == list( callback_data_cache._keyboard_data.keys())[0]) else: assert callback_query.data is None if message: for msg in ( callback_query.message, callback_query.message.reply_to_message, callback_query.message.pinned_message, ): assert msg.reply_markup == reply_markup else: if data: assert isinstance(callback_query.data, InvalidCallbackData) else: assert callback_query.data is None if message: for msg in ( callback_query.message, callback_query.message.reply_to_message, callback_query.message.pinned_message, ): assert isinstance( msg.reply_markup.inline_keyboard[0][1].callback_data, InvalidCallbackData, ) assert isinstance( msg.reply_markup.inline_keyboard[0][2].callback_data, InvalidCallbackData, )
def on_get_quote_by_date(update: Update, context: CallbackContext) -> Optional[db.Quote]: """ Получение цитаты по её дате: - <день>.<месяц>.<год>, например 13.10.2006 """ query = update.callback_query message = update.effective_message default_page = 1 # Если функция вызвана из CallbackQueryHandler if query: query.answer() page = int(context.match.group(1)) date_str = context.match.group(2) else: page = default_page date_str = message.text date = DT.datetime.strptime(date_str, db.DATE_FORMAT_QUOTE).date() # Показываем по одной цитате items_per_page = 1 items = db.Quote.paginating_by_date( page= 1, # Всегда страница первая, т.к. значение items_per_page запредельное items_per_page= 999, # Просто очень большое число, чтобы получить все цитаты за дату date=date, ) if not items: nearest_date_before, nearest_date_after = db.Quote.get_nearest_dates( date) buttons = [] if nearest_date_before: date_before_str = nearest_date_before.strftime( db.DATE_FORMAT_QUOTE) buttons.append( InlineKeyboardButton(f'⬅️ {date_before_str}', callback_data=fill_string_pattern( PATTERN_PAGE_GET_BY_DATE, default_page, date_before_str))) if nearest_date_after: date_after_str = nearest_date_after.strftime(db.DATE_FORMAT_QUOTE) buttons.append( InlineKeyboardButton(f'➡️ {date_after_str}', callback_data=fill_string_pattern( PATTERN_PAGE_GET_BY_DATE, default_page, date_after_str))) text = f'Цитаты за <b>{date_str}</b> не существуют. Как насчет посмотреть за ближайшие даты?' reply_markup = InlineKeyboardMarkup.from_row(buttons) message.reply_html( text, reply_markup=reply_markup, quote=True, ) return quote_obj = items[page - 1] text = get_html_message(quote_obj) data_pattern = fill_string_pattern(PATTERN_PAGE_GET_BY_DATE, '{page}', date.strftime(db.DATE_FORMAT_QUOTE)) reply_text_or_edit_with_keyboard_paginator( message, query, text=text, page_count=len(items), items_per_page=items_per_page, current_page=page, data_pattern=data_pattern, parse_mode=ParseMode.HTML, disable_web_page_preview=True, quote=True, ) return quote_obj
def show_episodes(podcast, index): buttons = [ InlineKeyboardButton("订阅列表", switch_inline_query_current_chat=""), InlineKeyboardButton( "单集列表", switch_inline_query_current_chat=f"{podcast.name}#") ] if index: if re.match(r'^-?[0-9]*$', index): index = int(index) if abs(index) <= len(podcast.episodes): if index >= 0: index = -index episodes = podcast.episodes[max(index - 3, -len(podcast.episodes) ):min(index + 2, -1)] else: index = abs(index + 1) episodes = podcast.episodes[ max(index - 3, 0):min(index + 2, len(podcast.episodes))] else: yield InlineQueryResultArticle( id=0, title='超出检索范围', input_message_content=InputTextMessageContent(':('), # !!如果 podcast.episodes.count() == 1 description=f"请输入 1 ~ {len(podcast.episodes)} 之间的数字", ) return else: episodes = Episode.objects( Q(from_podcast=podcast) & Q(title__icontains=index) ).order_by('-published_time') or Episode.objects( Q(from_podcast=podcast) & Q(summary__icontains=index)).order_by('-published_time') if not episodes: yield InlineQueryResultArticle( id=0, title='没有找到相关的节目', input_message_content=InputTextMessageContent(':('), description=f"换个关键词试试", ) return else: episodes = podcast.episodes for index, episode in enumerate(episodes): if episode.file_id: yield InlineQueryResultCachedAudio( id=index, audio_file_id=episode.file_id, reply_markup=InlineKeyboardMarkup.from_row(buttons), input_message_content=InputTextMessageContent(( f"[{SPEAKER_MARK}]({podcast.logo.url}) *{podcast.name}* #{len(podcast.episodes)-index}" )), ) else: yield InlineQueryResultArticle( id=index, title=episode.title, input_message_content=InputTextMessageContent(( f"[{SPEAKER_MARK}]({podcast.logo.url}) *{podcast.name}* #{len(podcast.episodes)-index}" )), reply_markup=InlineKeyboardMarkup.from_row(buttons), description= f"{datetime.timedelta(seconds=episode.duration) or podcast.name}\n{episode.subtitle}", thumb_url=episode.logo.url, thumb_width=80, thumb_height=80)
'Felder.\n\nWenn Du fertig bist, klicke unten auf <i>Weiter</i>.', NUMBER_QUESTIONS: '<b>4/4 - Anzahl der Fragen</b>\n\n' 'Supidupi. Wie viele Fragen möchtest Du insgesamt erhalten?', } """Dict[:obj:`str`,:obj:`str`]: Texts for the different states.""" # Keyboards FREE_TEXT = 'Freitext' NUMBER_QUESTIONS_KEYBOARD = InlineKeyboardMarkup.from_column([ InlineKeyboardButton(text=i, callback_data=str(i)) for i in [10, 25, 50, 100] ]) """:class:`telegram.InlineKeyboardMarkup`: Keyboard for selection the number of questions.""" MULTIPLE_CHOICE_KEYBOARD = InlineKeyboardMarkup.from_row([ InlineKeyboardButton(text=MULTIPLE_CHOICE, callback_data=str(True)), InlineKeyboardButton(text=FREE_TEXT, callback_data=str(False)), ]) """:class:`telegram.InlineKeyboardMarkup`: Keyboard for selection the type of questions.""" # ----------------------------------------------------------------------------------------------- # @dataclass class GameSettings: """ A simple data class for storing the game settings made by a user. Attributes: hint_attributes (List[:obj:`str`]): Subset of the keys of :attr:`components.Orchestra.DICTS_TO_ATTRS`. These will be given as hints for the questions.