Exemple #1
0
def lookup_entity(query, exact=True):
    """
    Searches for a Bot or User contained in the query
    """
    if exact:
        try:
            return Bot.by_username(query, include_disabled=True)
        except Bot.DoesNotExist:
            pass

        try:
            return Bot.get(chat_id=int(query))
        except ValueError:
            pass
        except Bot.DoesNotExist:
            pass

        try:
            return User.by_username(query)
        except User.DoesNotExist:
            pass

        try:
            return User.get(chat_id=query)
        except User.DoesNotExist:
            pass
        return None
Exemple #2
0
def search_bots(query):
    query = query.lower().strip()
    split = query.split(' ')

    # easter egg
    if query in ('awesome bot', 'great bot', 'superb bot', 'best bot',
                 'best bot ever'):
        return [Bot.by_username('@botlistbot')]

    # exact results
    where_query = ((fn.lower(Bot.username).contains(query)
                    | fn.lower(Bot.name) << split | fn.lower(Bot.extra)**query)
                   & (Bot.revision <= Revision.get_instance().nr & Bot.approved
                      == True & Bot.disabled == False))
    results = set(Bot.select().distinct().where(where_query))

    # keyword results
    keyword_results = Bot.select(Bot).join(
        Keyword).where((fn.lower(Keyword.name) << split)
                       & (Bot.revision <= Revision.get_instance().nr)
                       & (Bot.approved == True & Bot.disabled == False))
    results.update(keyword_results)

    # many @usernames
    usernames = re.findall(settings.REGEX_BOT_ONLY, query)
    if usernames:
        try:
            bots = Bot.many_by_usernames(usernames)
            print([b.username for b in bots])
            results.update(bots)
        except Bot.DoesNotExist:
            pass

    return list(results)
Exemple #3
0
def add_favorite_handler(bot, update, args=None):
    uid = util.uid_from_update(update)
    from botlistbot.components.basic import main_menu_buttons
    main_menu_markup = ReplyKeyboardMarkup(
        main_menu_buttons(uid in settings.MODERATORS))

    if args:
        query = ' '.join(args) if isinstance(args, list) else args
        try:
            # TODO: add multiple
            username = re.match(settings.REGEX_BOT_IN_TEXT, query).groups()[0]
            try:
                # TODO: get exact database matches for input without `@`
                item = Bot.by_username(username, include_disabled=True)

                return add_favorite(bot, update, item)
            except Bot.DoesNotExist:
                buttons = [
                    InlineKeyboardButton(
                        "Yai!",
                        callback_data=util.callback_for_action(
                            CallbackActions.ADD_ANYWAY, {'u': username})),
                    InlineKeyboardButton(
                        "Nay...",
                        callback_data=util.callback_for_action(
                            CallbackActions.ADD_FAVORITE))
                ]
                reply_markup = InlineKeyboardMarkup([buttons])
                util.send_md_message(
                    bot,
                    uid,
                    "{} is not in the @BotList. Do you want to add it to your {} anyway?"
                    .format(username, captions.FAVORITES),
                    reply_markup=reply_markup)
        except AttributeError:
            # invalid bot username
            # TODO when does this happen?
            update.message.reply_text(
                util.failure(
                    "Sorry, but that is not a valid username. Please try again. /addfav"
                ))
    else:
        buttons = [
            InlineKeyboardButton("Search inline",
                                 switch_inline_query_current_chat='')
        ]
        reply_markup = InlineKeyboardMarkup([buttons])

        bot.sendMessage(uid,
                        messages.ADD_FAVORITE,
                        reply_markup=ForceReply(selective=True))
    return ConversationHandler.END
Exemple #4
0
def thumbnail(username):
    if username[0] != '@':
        username = '******' + username
    try:
        item = Bot.by_username(username)
    except Bot.DoesNotExist:
        item = None
    if not item:
        return _error(
            "There is no bot in the BotList with the username {}.".format(
                username))
    if not os.path.exists(item.thumbnail_file):
        return _error("Sorry, we don't have a thumbnail for this bot.")

    return send_file(item.thumbnail_file, mimetype='image/jpeg')
Exemple #5
0
def reject_bot_submission(
    bot,
    update,
    args=None,
    to_reject=None,
    verbose=True,
    notify_submittant=True,
    reason=None,
):
    uid = util.uid_from_update(update)
    user = User.from_update(update)

    if to_reject is None:
        if not update.message.reply_to_message:
            bot.send_message(
                update.effective_user.id,
                util.failure("You must reply to a message of mine."),
            )
            return

        text = update.message.reply_to_message.text
        reason = reason if reason else (" ".join(args) if args else None)

        try:
            update.message.delete()
        except:
            pass

        username = helpers.find_bots_in_text(text, first=True)
        if not username:
            bot.send_message(
                update.effective_user.id,
                util.failure("No username in the message that you replied to."),
            )
            return

        try:
            to_reject = Bot.by_username(username)
        except Bot.DoesNotExist:
            bot.send_message(
                update.effective_user.id,
                util.failure(
                    "Rejection failed: {} is not present in the "
                    "database.".format(username)
                ),
            )
            return

        if to_reject.approved is True:
            msg = "{} has already been accepted, so it cannot be rejected anymore.".format(
                username
            )
            bot.sendMessage(uid, util.failure(msg))
            return

    Statistic.of(update, "reject", to_reject.username)
    text = notify_submittant_rejected(bot, user, notify_submittant, reason, to_reject)
    to_reject.delete_instance()

    if verbose:
        bot.sendMessage(uid, text)

    if update.callback_query:
        update.callback_query.answer(text=text)
Exemple #6
0
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
Exemple #7
0
def new_channel_post(bot, update, photo=None):
    post = update.channel_post
    if post.chat.username != settings.SELF_CHANNEL_USERNAME:
        return
    text = post.text

    channel, created = Channel.get_or_create(chat_id=post.chat_id,
                                             username=post.chat.username)
    if created:
        channel.save()

    category_list = '•Share your bots to the @BotListChat using the hashtag #new' in text
    intro = 'Hi! Welcome' in text
    category = text[0] == '•' and not category_list
    new_bots_list = 'NEW→' in text

    # TODO: is this a document?
    if photo:
        pass
    elif category:
        try:
            # get the category meta data
            meta = re.match(r'•(.*?)([A-Z].*):(?:\n(.*):)?', text).groups()
            if len(meta) < 2:
                raise ValueError("Category could not get parsed.")

            emojis = str.strip(meta[0])
            name = str.strip(meta[1])
            extra = str.strip(meta[2]) if meta[2] else None
            try:
                cat = Category.get(name=name)
            except Category.DoesNotExist:
                cat = Category(name=name)
            cat.emojis = emojis
            cat.extra = extra
            cat.save()

            # get the bots in that category
            bots = re.findall(r'^(🆕)?.*(@\w+)( .+)?$', text, re.MULTILINE)
            languages = Country.select().execute()
            for b in bots:
                username = b[1]
                try:
                    new_bot = Bot.by_username(username)
                except Bot.DoesNotExist:
                    new_bot = Bot(username=username)

                new_bot.category = cat

                new_bot.inlinequeries = "🔎" in b[2]
                new_bot.official = "🔹" in b[2]

                extra = re.findall(r'(\[.*\])', b[2])
                if extra:
                    new_bot.extra = extra[0]

                # find language
                for lang in languages:
                    if lang.emoji in b[2]:
                        new_bot.country = lang

                if b[0]:
                    new_bot.date_added = datetime.date.today()
                else:
                    new_bot.date_added = datetime.date.today(
                    ) - datetime.timedelta(days=31)

                new_bot.save()
        except AttributeError:
            log.error("Error parsing the following text:\n" + text)
Exemple #8
0
def new_bot_submission(bot, update, chat_data, args=None, bot_checker=None):
    tg_user = update.message.from_user
    user = User.from_telegram_object(tg_user)
    if util.stop_banned(update, user):
        return
    reply_to = util.original_reply_id(update)

    if args:
        text = " ".join(args)
    else:
        text = update.message.text
        command_no_args = (
            len(re.findall(r"^/new\s*$", text)) > 0
            or text.lower().strip() == "/new@botlistbot"
        )
        if command_no_args:
            update.message.reply_text(
                util.action_hint(
                    "Please use this command with an argument. For example:\n/new @mybot 🔎"
                ),
                reply_to_message_id=reply_to,
            )
            return

    # `#new` is already checked by handler
    try:
        username = re.match(settings.REGEX_BOT_IN_TEXT, text).groups()[0]
        if username.lower() == "@" + settings.SELF_BOT_NAME.lower():
            log.info("Ignoring {}".format(text))
            return
    except AttributeError:
        if args:
            update.message.reply_text(
                util.failure("Sorry, but you didn't send me a bot `@username`."),
                quote=True,
                parse_mode=ParseMode.MARKDOWN,
                reply_to_message_id=reply_to,
            )
        log.info("Ignoring {}".format(text))
        # no bot username, ignore update
        return

    try:
        new_bot = Bot.by_username(username, include_disabled=True)
        if new_bot.disabled:
            update.message.reply_text(
                util.failure(
                    "{} is banned from the @BotList.".format(new_bot.username)
                ),
                reply_to_message_id=reply_to,
            )
        elif new_bot.approved:
            update.message.reply_text(
                util.action_hint(
                    "Sorry fool, but {} is already in the @BotList 😉".format(
                        new_bot.username
                    )
                ),
                reply_to_message_id=reply_to,
            )
        else:
            update.message.reply_text(
                util.action_hint(
                    "{} has already been submitted. Please have patience...".format(
                        new_bot.username
                    )
                ),
                reply_to_message_id=reply_to,
            )
        return
    except Bot.DoesNotExist:
        new_bot = Bot(
            revision=Revision.get_instance().next,
            approved=False,
            username=username,
            submitted_by=user,
        )

    new_bot.inlinequeries = "🔎" in text
    new_bot.official = "🔹" in text

    # find language
    languages = Country.select().execute()
    for lang in languages:
        if lang.emoji in text:
            new_bot.country = lang

    new_bot.date_added = datetime.date.today()

    description_reg = re.match(settings.REGEX_BOT_IN_TEXT + " -\s?(.*)", text)
    description_notify = ""
    if description_reg:
        description = description_reg.group(2)
        new_bot.description = description
        description_notify = " Your description was included."

    new_bot.save()

    if (
        util.is_private_message(update)
        and util.uid_from_update(update) in settings.MODERATORS
    ):
        from botlistbot.components.explore import send_bot_details

        send_bot_details(bot, update, chat_data, new_bot)
    else:
        update.message.reply_text(
            util.success(
                "You submitted {} for approval.{}".format(new_bot, description_notify)
            ),
            parse_mode=ParseMode.MARKDOWN,
            reply_to_message_id=reply_to,
        )

        # Ask the user to fill in the bot details
        util.send_md_message(
            bot,
            update.effective_user.id,
            "Congratulations, you just submitted a bot to the @BotList. Please help us fill in the details below:",
        )
        edit_bot(bot, update, chat_data, to_edit=new_bot)

    try:
        check_submission(bot, bot_checker, new_bot)
    except Exception as e:
        log.exception(e)

    return ConversationHandler.END