示例#1
0
    def add_or_update(user, action, subject, value):
        from botlistbot.models import Statistic
        # value may be None
        already_exists = Suggestion.get_pending(action, subject, user, value)
        if already_exists:
            # Does the new suggestion reset the value?
            if action == 'remove_keyword':
                try:
                    kw = Keyword.get(entity=subject, name=value)
                    kw.delete_instance()
                except Keyword.DoesNotExist:
                    pass
            elif action == 'add_keyword':
                return  # TODO: is this right?
            elif value == getattr(already_exists.subject, action):
                already_exists.delete_instance()
                return None

            already_exists.value = value
            already_exists.save()

            Statistic.of(user, 'made changes to their suggestion: ', str(already_exists))

            return already_exists
        else:
            new_suggestion = Suggestion(user=user, action=action, date=datetime.date.today(),
                                        subject=subject, value=value)
            new_suggestion.save()
            Statistic.of(user, 'suggestion', new_suggestion._md_plaintext())
            return new_suggestion
示例#2
0
def add_favorite(bot, update, item: Bot, callback_alert=None):
    user = User.from_update(update)
    uid = util.uid_from_update(update)
    mid = util.mid_from_update(update)
    from botlistbot.components.basic import main_menu_buttons
    main_menu_markup = ReplyKeyboardMarkup(
        main_menu_buttons(uid in settings.MODERATORS))

    fav, created = Favorite.add(user=user, item=item)
    if created:
        Statistic.of(user, 'add-favorite', item.username)
        text = mdformat.love("{} added to your {}favorites.".format(
            fav.bot, '' if callback_alert else '/'))
        if callback_alert:
            update.callback_query.answer(text=text, show_alert=False)
        else:
            msg = util.send_md_message(bot,
                                       uid,
                                       text,
                                       to_edit=mid,
                                       reply_markup=main_menu_markup)
            mid = msg.message_id
            util.wait(bot, update)
            send_favorites_list(bot, update, to_edit=mid)
    else:
        text = mdformat.none_action(
            "{} is already a favorite of yours.{}".format(
                fav.bot, '' if callback_alert else ' /favorites'))
        if callback_alert:
            update.callback_query.answer(text=text, show_alert=False)
        else:
            util.send_md_message(bot, uid, text, reply_markup=main_menu_markup)
    return ConversationHandler.END
示例#3
0
def _input_failed(bot, update, chat_data, text):
    chat_id = util.uid_from_update(update)
    bot.formatter.send_failure(chat_id, text)
    Statistic.of(
        update,
        "error",
        "input failed in admin menu for {}".format(text),
        Statistic.ANALYSIS,
    )
    chat_data["add_bot_message"] = None
示例#4
0
def apply_all_changes(bot, update, chat_data, to_edit):
    user = User.from_update(update)

    user_suggestions = Suggestion.select_all_of_user(user)
    for suggestion in user_suggestions:
        suggestion.apply()

    refreshed_bot = Bot.get(id=to_edit.id)
    edit_bot(bot, update, chat_data, refreshed_bot)
    Statistic.of(update, "apply", refreshed_bot.username)
示例#5
0
def _too_many_favorites_handler(bot, update, user):
    uid = util.uid_from_update(update)
    any_removed = False
    while too_many_favorites(user):
        oldest = Favorite.get_oldest(user)
        oldest.delete_instance()
        any_removed = True
        Statistic.of(
            update, 'had to lose a favorite because HE HAD TOO F****N MANY 😬')
    if any_removed:
        txt = "You have too many favorites, _they do not fit into a single message_. That's why I removed your " \
              "oldest bot, *{}*, from your list of favorites.".format(oldest.bot if oldest.bot else oldest.custom_bot)
        util.send_md_message(bot, uid, txt)
示例#6
0
def set_notifications(bot, update, value: bool):
    cid = update.effective_chat.id
    try:
        notifications = Notifications.get(Notifications.chat_id == cid)
    except Notifications.DoesNotExist:
        notifications = Notifications(chat_id=cid)
    notifications.enabled = value
    notifications.save()

    Statistic.of(update, ('enabled' if value else 'disabled') +
                 ' notifications for their group {}'.format(cid))

    msg = util.success("Nice! Notifications enabled."
                       ) if value else "Ok, notifications disabled."
    msg += '\nYou can always adjust this setting with the /subscribe command.'
    bot.formatter.send_or_edit(cid, msg, to_edit=util.mid_from_update(update))
    return ConversationHandler.END
示例#7
0
def ban_user(_bot, update, user: User, ban_state: bool):
    if user.banned and ban_state is True:
        update.message.reply_text(
            mdformat.none_action("User {} is already banned.".format(user)),
            parse_mode="markdown",
        )
        raise DispatcherHandlerStop
    if not user.banned and ban_state is False:
        update.message.reply_text(
            mdformat.none_action("User {} is not banned.".format(user)),
            parse_mode="markdown",
        )
        raise DispatcherHandlerStop
    user.banned = ban_state
    if ban_state is True:
        with db.atomic():
            user_submissions = Bot.select().where(
                (Bot.approved == False)
                & (Bot.submitted_by == user)
                # TODO: does this need to include `Bot.deleted == True`?
            )
            for b in user_submissions:
                b.delete_instance()

            users_suggestions = Suggestion.select().where(
                (Suggestion.executed == False) & (Suggestion.user == user)
            )
            for s in users_suggestions:
                s.delete_instance()
        update.message.reply_text(
            mdformat.success(
                "User {} banned, all bot submissions and suggestions removed.".format(
                    user
                )
            ),
            parse_mode="markdown",
        )
        Statistic.of(update, "ban", user.markdown_short)
    else:
        update.message.reply_text(
            mdformat.success("User {} unbanned.".format(user)), parse_mode="markdown"
        )
        Statistic.of(update, "unban", user.markdown_short)
    user.save()
示例#8
0
def share_with_moderator(bot, update, bot_in_question, moderator):
    user = User.from_update(update)

    buttons = [
        [
            InlineKeyboardButton(
                "Yea, let me take this one!",
                callback_data=util.callback_for_action(
                    CallbackActions.APPROVE_REJECT_BOTS, {"id": bot_in_question.id}
                ),
            )
        ]
    ]
    reply_markup = InlineKeyboardMarkup(buttons)
    text = "{} thinks that you have the means to inspect this bot submission:\n▶️ {}".format(
        user.markdown_short, bot_in_question
    )
    try:
        util.send_md_message(
            bot,
            moderator.chat_id,
            text,
            reply_markup=reply_markup,
            disable_web_page_preview=True,
        )
        answer_text = mdformat.success(
            "I will ask {} to have a look at this submission.".format(
                moderator.plaintext
            )
        )
    except Exception as e:
        answer_text = mdformat.failure(f"Could not contact {moderator.plaintext}: {e}")

    if update.callback_query:
        update.callback_query.answer(text=answer_text)

    Statistic.of(
        update,
        "share",
        "submission {} with {}".format(bot_in_question.username, moderator.plaintext),
    )
示例#9
0
def send_botlist(bot, update, resend=False, silent=False):
    log.info("Re-sending BotList..." if resend else "Updating BotList...")

    channel = helpers.get_channel()
    revision = Revision.get_instance()
    revision.nr += 1
    revision.save()

    all_categories = Category.select_all()

    botlist = BotList(bot, update, channel, resend, silent)
    if resend:
        botlist.delete_full_botlist()
    botlist.update_intro()
    botlist.update_categories(all_categories)
    botlist.update_new_bots_list()
    botlist.update_category_list()
    botlist.send_footer()
    botlist.finish()
    channel.save()
    Statistic.of(update, 'send', 'botlist (resend: {})'.format(str(resend)),
                 Statistic.IMPORTANT)
示例#10
0
def send_activity_logs(bot, update, args=None, level=Statistic.INFO):
    num = 200
    if args:
        try:
            num = int(args[0])
            num = min(num, 500)
        except:
            pass
    uid = update.effective_user.id
    recent_statistic = Statistic.select().order_by(Statistic.date.desc()).limit(num)
    recent_statistic = list(reversed(recent_statistic))

    step_size = 30
    for i in range(0, len(recent_statistic), step_size):
        items = recent_statistic[i : i + step_size]
        text = "\n".join(x.md_str() for x in items)

        bot.formatter.send_message(uid, text)
示例#11
0
def send_statistic(bot, update):
    interesting_actions = [
        "explore",
        "menu",
        "command",
        "request",
        "made changes to their suggestion:",
        "issued deletion of conversation in BotListChat",
    ]
    stats = (
        Statistic.select(Statistic, fn.COUNT(Statistic.entity).alias("count"))
        .where(Statistic.action << interesting_actions)
        .group_by(Statistic.action, Statistic.entity)
    )
    maxlen = max(len(str(x.count)) for x in stats)
    text = "\n".join(
        "`{}▪️` {} {}".format(str(s.count).ljust(maxlen), s.action.title(), s.entity)
        for s in stats
    )
    bot.formatter.send_message(update.effective_chat.id, text, parse_mode="markdown")
示例#12
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)
示例#13
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
示例#14
0
def send_category(bot, update, chat_data, category):
    uid = util.uid_from_update(update)
    cid = update.effective_chat.id
    bots = Bot.of_category_without_new(category)[: settings.MAX_BOTS_PER_MESSAGE]
    bots_with_description = [b for b in bots if b.description is not None]
    detailed_buttons_enabled = len(
        bots_with_description
    ) > 0 and util.is_private_message(update)

    callback = CallbackActions.SEND_BOT_DETAILS

    if detailed_buttons_enabled:
        buttons = [
            InlineKeyboardButton(
                x.username,
                callback_data=util.callback_for_action(callback, {"id": x.id}),
            )
            for x in bots_with_description
        ]
    else:
        buttons = []
    menu = util.build_menu(buttons, 2)
    menu.insert(
        0,
        [
            InlineKeyboardButton(
                captions.BACK,
                callback_data=util.callback_for_action(CallbackActions.SELECT_CATEGORY),
            ),
            InlineKeyboardButton(
                "Show in BotList",
                url="http://t.me/botlist/{}".format(category.current_message_id),
            ),
            InlineKeyboardButton("Share", switch_inline_query=category.name),
        ],
    )
    txt = "There are *{}* bots in the category *{}*:\n\n".format(
        len(bots), str(category)
    )

    if uid in settings.MODERATORS and util.is_private_message(update):
        # append admin edit buttons
        txt += "\n".join(["{} — /edit{} 🛃".format(b, b.id) for b in bots])
    else:
        txt += "\n".join([str(b) for b in bots])

    if detailed_buttons_enabled:
        txt += "\n\n" + util.action_hint(
            "Press a button below to get a detailed description."
        )

    reply_markup = InlineKeyboardMarkup(menu)
    reply_markup, callback = botlistchat.append_restricted_delete_button(
        update, chat_data, reply_markup
    )
    msg = bot.formatter.send_or_edit(
        cid, txt, to_edit=util.mid_from_update(update), reply_markup=reply_markup
    )
    callback(msg)
    Statistic.of(
        update, "menu", "of category {}".format(str(category)), Statistic.ANALYSIS
    )
示例#15
0
def chosen_result(bot, update, chat_data):
    if update.chosen_inline_result.inline_message_id:
        chat_data[
            'sent_inlinequery'] = update.chosen_inline_result.inline_message_id
    Statistic.of(update, 'chosen-inlinequery-result', level=Statistic.ANALYSIS)