예제 #1
0
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)
예제 #2
0
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
예제 #4
0
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}",
    )
예제 #5
0
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)
예제 #6
0
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
예제 #7
0
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
예제 #9
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
예제 #10
0
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
예제 #11
0
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)
예제 #12
0
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
예제 #13
0
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
예제 #15
0
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} 的更新。")
예제 #16
0
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)
예제 #17
0
파일: models.py 프로젝트: DahaWong/castpod
 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
예제 #18
0
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
예제 #19
0
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
예제 #21
0
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
예제 #23
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 == ([], {})
예제 #26
0
# 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
예제 #29
0
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)
예제 #30
0
    '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.