Beispiel #1
0
def reroute_private_chat(bot, update, quote, action, message, redirect_message=None, reply_markup=None):
    cid = update.effective_chat.id
    mid = util.mid_from_update(update)
    if redirect_message is None:
        redirect_message = messages.REROUTE_PRIVATE_CHAT

    if util.is_group_message(update):
        update.message.reply_text(
            redirect_message,
            quote=quote,
            parse_mode=ParseMode.MARKDOWN,
            reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton(
                    captions.SWITCH_PRIVATE,
                    url="https://t.me/{}?start={}".format(
                        settings.SELF_BOT_NAME,
                        action)),
                    InlineKeyboardButton('🔎 Switch to inline', switch_inline_query=action)
                ]]
            ))
    else:
        if mid:
            bot.formatter.send_or_edit(cid, message, mid, reply_markup=reply_markup)
        else:
            update.message.reply_text(message, quote=quote, parse_mode=ParseMode.MARKDOWN, reply_markup=reply_markup)
def search_handler(bot, update, chat_data, args=None):
    if args:
        search_query(bot, update, chat_data, " ".join(args))
    else:
        # no search term
        if util.is_group_message(update):
            action = const.DeepLinkingActions.SEARCH
            sent_msg = update.message.reply_text(
                "Please use the search command with arguments, inlinequeries or continue in private. "
                "Example: `/search awesome bot`",
                quote=True,
                parse_mode=ParseMode.MARKDOWN,
                reply_markup=InlineKeyboardMarkup(
                    [
                        [
                            InlineKeyboardButton(
                                "🔎 Search inline", switch_inline_query_current_chat=""
                            ),
                            InlineKeyboardButton(
                                captions.SWITCH_PRIVATE,
                                url="https://t.me/{}?start={}".format(
                                    settings.SELF_BOT_NAME, action
                                ),
                            ),
                        ]
                    ]
                ),
            )
            try_delete_after(appglobals.job_queue, [sent_msg, update.effective_message], delay=10)
        else:
            update.message.reply_text(
                messages.SEARCH_MESSAGE, reply_markup=ForceReply(selective=True)
            )
    return ConversationHandler.END
Beispiel #3
0
def manage_subscription(bot, update):
    chat_id = update.effective_chat.id
    user_id = update.effective_user.id

    if util.is_group_message(update):
        admins = bot.get_chat_administrators(chat_id)
        if user_id not in admins:
            bot.formatter.send_failure(
                chat_id,
                "Sorry, but only Administrators of this group are allowed "
                "to manage subscriptions.")
            return

    text = "Would you like to be notified when new bots arrive at the @BotList?"
    buttons = [[
        InlineKeyboardButton(util.success("Yes"),
                             callback_data=util.callback_for_action(
                                 CallbackActions.SET_NOTIFICATIONS,
                                 {'value': True})),
        InlineKeyboardButton("No",
                             callback_data=util.callback_for_action(
                                 CallbackActions.SET_NOTIFICATIONS,
                                 {'value': False}))
    ]]
    reply_markup = InlineKeyboardMarkup(buttons)
    msg = util.send_md_message(bot, chat_id, text, reply_markup=reply_markup)
    return ConversationHandler.END
Beispiel #4
0
def append_restricted_delete_button(
        update, chat_data, reply_markup
) -> Tuple[Optional[ReplyMarkup], Callable[[Message], None]]:
    uid = update.effective_user.id
    command_mid = update.effective_message.message_id

    if not util.is_group_message(update) or not isinstance(
            reply_markup, InlineKeyboardMarkup):
        return reply_markup, lambda _: None

    def append_callback(message):
        if message is None:  # No message was saved
            return
        if isinstance(message, Message):
            mid = message.message_id
        else:
            mid = message
        deletions_pending = chat_data.get("deletions_pending", dict())
        if not deletions_pending.get(mid):
            deletions_pending[mid] = dict(user_id=uid, command_id=command_mid)
            chat_data["deletions_pending"] = deletions_pending

    buttons = reply_markup.inline_keyboard
    buttons.append([
        InlineKeyboardButton(
            captions.random_done_delete(),
            callback_data=util.callback_for_action(
                CallbackActions.DELETE_CONVERSATION),
        )
    ])
    reply_markup.inline_keyboard = buttons
    return reply_markup, append_callback
Beispiel #5
0
def append_free_delete_button(update, reply_markup) -> Optional[ReplyMarkup]:
    if not util.is_group_message(update) or not isinstance(
            reply_markup, InlineKeyboardMarkup):
        return reply_markup

    buttons = reply_markup.inline_keyboard
    buttons.append([
        InlineKeyboardButton(
            captions.random_done_delete(),
            callback_data=util.callback_for_action(
                CallbackActions.DELETE_CONVERSATION),
        )
    ])

    reply_markup.inline_keyboard = buttons
    return reply_markup
Beispiel #6
0
def hint_handler(bot, update, job_queue: JobQueue):
    chat_id = update.message.chat_id
    if not util.is_group_message(update):
        return
    text = update.message.text
    reply_to = update.message.reply_to_message
    user = User.from_update(update)
    msg, reply_markup, hashtag = get_hint_data(text)

    def _send_hint(hint_text):
        if hint_text is None:
            return
        if reply_to:
            hint_text = f"{user.markdown_short} hints: {hint_text}"

        bot.formatter.send_message(
            chat_id,
            hint_text,
            reply_markup=reply_markup,
            reply_to_message_id=reply_to.message_id if reply_to else None,
        )
        update.effective_message.delete()

    should_reply: bool = HINTS.get(hashtag)["should_reply"]
    if should_reply and not reply_to:
        del_markup = append_free_delete_button(update,
                                               InlineKeyboardMarkup([[]]))
        _send_hint(msg)
        ntfc_msg = update.effective_message.reply_text(
            f"Hey {user.markdown_short}, next time reply to someone 🙃",
            parse_mode=ParseMode.MARKDOWN,
            reply_markup=del_markup,
            quote=False,
            disable_web_page_preview=True,
        )
        job_queue.run_once(lambda *_: ntfc_msg.delete(),
                           7,
                           name="delete notification")
    else:
        _send_hint(msg)
def send_next(bot, update, job_queue: JobQueue, args=None):
    uid = util.uid_from_update(update)
    num_rows = None
    if args:
        try:
            num_rows = int(args[0])
        except:
            num_rows = None

    reply_markup = ReplyKeyboardMarkup(_crapPy_Tr0ll_kbmarkup(num_rows),
                                       one_time_keyboard=False,
                                       per_user=True)
    text = "ɹoʇɐɹǝuǝb ǝɯɐuɹǝsn ɯɐɹbǝןǝʇ"
    util.send_md_message(bot, uid, text, reply_markup=reply_markup)

    if util.is_group_message(update):
        del_msg = bot.formatter.send_message(
            update.effective_chat.id, "Have fun in private ;)\n/easteregg")
        update.effective_message.delete()
        job_queue.run_once(lambda *_: del_msg.delete(safe=True),
                           4,
                           name="delete easteregg hint")
Beispiel #8
0
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)
    first_row = list()

    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)

        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

    if 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})
        first_row.insert(0, btn)
        first_row.append(
            InlineKeyboardButton(captions.SHARE,
                                 switch_inline_query=item.username))

        # if cid in settings.MODERATORS:
        first_row.append(
            InlineKeyboardButton("📝 Edit",
                                 callback_data=util.callback_for_action(
                                     CallbackActions.EDIT_BOT,
                                     {'id': item.id})))
    else:
        txt = '{} is currently pending to be accepted for the @BotList.'.format(
            item)
        if cid in settings.MODERATORS:
            first_row.append(
                InlineKeyboardButton("🛃 Accept / Reject",
                                     callback_data=util.callback_for_action(
                                         CallbackActions.APPROVE_REJECT_BOTS,
                                         {'id': item.id})))

    if is_group:
        reply_markup = InlineKeyboardMarkup([])
    else:
        buttons = [first_row]
        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
                                         }))
            ])
        reply_markup = InlineKeyboardMarkup(buttons)
    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 search_query(bot, update: Update, chat_data, query, send_errors=True):
    cid: int = update.effective_chat.id
    user: User = User.from_update(update)
    is_admin: bool = cid in settings.MODERATORS
    replied_to_message_id: Optional[int] = util.original_reply_id(update)

    results = search.search_bots(query)

    reply_markup = (
        ReplyKeyboardMarkup(basic.main_menu_buttons(is_admin), resize_keyboard=True)
        if util.is_private_message(update)
        else None
    )
    if results:
        if len(results) == 1:
            update.effective_message.delete()
            header = f"{user.markdown_short} found the following bot for you:"
            return send_bot_details(bot, update, chat_data, results[0], header_msg=header)
        too_many_results = len(results) > settings.MAX_SEARCH_RESULTS

        bots_list = ""
        if cid in settings.MODERATORS:  # private chat with moderator
            # append edit buttons
            bots_list += "\n".join(
                ["{} — /edit{} 🛃".format(b, b.id) for b in list(results)[:100]]
            )
        else:
            bots_list += "\n".join(
                [str(b) for b in list(results)[: settings.MAX_SEARCH_RESULTS]]
            )
        bots_list += "\n…" if too_many_results else ""
        bots_list = messages.SEARCH_RESULTS.format(
            bots=bots_list,
            num_results=len(results),
            plural="s" if len(results) > 1 else "",
            query=query,
        )

        if util.is_group_message(update) and not update.message.reply_to_message:
            try:
                bot.formatter.send_message(
                    update.effective_user.id,
                    bots_list,
                    reply_markup=reply_markup,
                    disable_web_page_preview=True,
                )
                reply_markup, callback = botlistchat.append_restricted_delete_button(
                    update, chat_data, InlineKeyboardMarkup([[]])
                )
                msg = bot.formatter.send_message(
                    update.effective_chat.id,
                    f"Hey {user.plaintext}, let's not annoy the others. I sent you the search results "
                    f"[in private chat](https://t.me/{settings.SELF_BOT_NAME}).",
                    disable_web_page_preview=True,
                    reply_markup=reply_markup,
                )
                callback(msg)
                update.effective_message.delete()
            except TelegramError:
                hint_msg, hint_reply_markup, _ = get_hint_data("#private")
                bot.formatter.send_message(
                    update.effective_chat.id,
                    hint_msg,
                    reply_markup=hint_reply_markup,
                    reply_to_message_id=update.effective_message.id,
                    disable_web_page_preview=True,
                )
            return ConversationHandler.END

        if replied_to_message_id:
            bots_list = f"{user.markdown_short} suggests to search and {bots_list}"

        bot.formatter.send_message(
            update.effective_chat.id,
            bots_list,
            parse_mode=ParseMode.MARKDOWN,
            reply_markup=reply_markup,
            disable_web_page_preview=True,
            reply_to_message_id=replied_to_message_id,
        )
        update.effective_message.delete()
    else:
        if send_errors:
            callback = None
            if util.is_group_message(update):
                reply_markup, callback = botlistchat.append_restricted_delete_button(
                    update, chat_data, InlineKeyboardMarkup([[]])
                )
            msg = update.message.reply_text(
                util.failure(
                    "Sorry, I couldn't find anything related "
                    "to *{}* in the @BotList. /search".format(
                        util.escape_markdown(query)
                    )
                ),
                parse_mode=ParseMode.MARKDOWN,
                reply_markup=reply_markup,
            )
            if callback:
                callback(msg)

    return ConversationHandler.END
def send_bot_details(bot,
                     update,
                     chat_data,
                     item=None,
                     header_msg: Optional[str] = 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 = f"{header_msg}\n\n{item.detail_text}" if header_msg else item.detail_text

        if (item.description is None and
                not Keyword.select().where(Keyword.entity == item).exists()):
            txt += " is in the @BotList, but has no description or keywords yet."
        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_restricted_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