예제 #1
0
async def get_user_info(_, message):
    if len(message.command) != 2:
        return await wrapper.send_message(
            message.chat.id,
            plate("invalid_syntax", correct="/getuser id/[@]username"))

    if message.command[1].isdigit():
        name = None
        user = get_user(message.command[1])
    else:
        name = message.command[1].lstrip("@").lower()
        user = get_user_by_name(name)

    if user:
        logging.warning(
            f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /getuser {message.command[1]}"
        )
        result = user
        text = format_user(result)
        await wrapper.send_message(message.chat.id, text)
    else:
        if name:
            await wrapper.send_message(
                message.chat.id,
                plate("error") + ":" +
                plate("name_missing", tg_uname=message.command[1]),
            )
        else:
            await wrapper.send_message(
                message.chat.id,
                plate("error") + ":" +
                plate("id_missing", tg_id=message.command[1]),
            )
예제 #2
0
async def bot_disclaimer_handler(_, query):
    cb_wrapper = MethodWrapper(query)
    await cb_wrapper.edit_message_text(
        text=plate("bot_disclaimer_text"),
        disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(
            [[InlineKeyboardButton(plate("back_button"), "back_start")]]
        ),
    )
    await cb_wrapper.answer()
예제 #3
0
def format_user(user):
    (tg_id, tg_uname, date, banned) = user
    return plate(
        "user_info",
        tg_id=tg_id,
        tg_uname="@" + tg_uname if tg_uname else "N/A",
        date=date,
        status=plate("yes") if banned else plate("no"),
        admin=plate("yes") if tg_id in ADMINS else plate("no"),
    )
예제 #4
0
async def count_users(_, message):
    if len(message.command) > 1:
        await wrapper.send_message(message.chat.id,
                                   plate("no_parameters", command="/count"))
    else:
        logging.warning(
            f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /count"
        )
        users_count = len(get_users())
        await wrapper.send_message(
            message.chat.id, plate("users_count", users_count=users_count))
예제 #5
0
async def queue(_, message):
    if len(message.command) > 1:
        return await wrapper.send_message(
            message.chat.id, plate("no_parameters", command="/queue"))

    logging.warning(
        f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /queue")
    text = ""
    for user in CACHE:
        if CACHE[user][0] == "AWAITING_ADMIN":
            text += f"- 👤 [User]({NAME.format(user)})\n"
    await wrapper.send_message(message.chat.id, plate("queue_list",
                                                      queue=text))
예제 #6
0
async def bot_about_handler(_, query):
    cb_wrapper = MethodWrapper(query)
    await cb_wrapper.edit_message_text(
        text=plate(
            "credits",
            python_version=PY_VERSION,
            botbase_version=BOTBASE_VERSION,
            bot_version=BOT_VERSION,
        ),
        disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(
            [[InlineKeyboardButton(plate("back_button"), "back_start")]]
        ),
    )
    await cb_wrapper.answer()
예제 #7
0
async def chats(_, message):
    if len(message.command) > 1:
        return await wrapper.send_message(
            message.chat.id, plate("no_parameters", command="/chats"))

    logging.warning(
        f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /chats")
    text = ""
    for user in CACHE:
        if CACHE[user][0] == "IN_CHAT" and user not in ADMINS:
            admin_id = CACHE[user][1]
            admin_name = ADMINS[admin_id]
            text += f"- 👤 [User]({NAME.format(user)}) -> 👨‍💻 [{admin_name}]({NAME.format(admin_id)})\n"
    await wrapper.send_message(message.chat.id, plate("chats_list",
                                                      chats=text))
예제 #8
0
async def busy(_, message):
    if len(message.command) > 1:
        return await wrapper.send_message(
            message.chat.id, plate("no_parameters", command="/busy"))

    logging.warning(
        f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /busy")
    if (CACHE[message.from_user.id][0] == "IN_CHAT"
            and CACHE[message.from_user.id][1] != 1234567):
        await wrapper.send_message(message.from_user.id,
                                   plate("leave_current_chat"))
    elif CACHE[message.from_user.id][0] == "none":
        await wrapper.send_message(message.chat.id, plate("marked_busy"))
        CACHE[message.from_user.id] = ["IN_CHAT", 1234567]
    else:
        if message.from_user.id in CACHE:
            del CACHE[message.from_user.id]
        await wrapper.send_message(message.chat.id, plate("unmarked_busy"))
예제 #9
0
async def services_status_history_handler(_, query):
    cb_wrapper = MethodWrapper(query)
    await cb_wrapper.edit_message_text(
        text=plate(
            "services_status_history_text",
            website_30d_avg=await get_30d_website_history_ratio(),
            website_30d_avg_symbol="✅"
            if await get_30d_website_history_label()
            else "⚠️",
            qr_code_api_30d_avg=await get_30d_qr_api_history_ratio(),
            qr_code_api_30d_avg_symbol="✅"
            if await get_30d_qr_api_history_ratio()
            else "⚠️",
            api_30d_avg=await get_30d_api_history_ratio(),
            api_30d_avg_symbol="✅" if await get_30d_api_history_label() else "⚠️",
            docs_30d_avg=await get_30d_api_docs_history_ratio(),
            docs_30d_avg_symbol="✅" if await get_30d_api_docs_history_label() else "⚠️",
            internal_api_30d_avg=await get_30d_internal_api_history_ratio(),
            internal_api_30d_avg_symbol="✅"
            if await get_30d_internal_api_history_label()
            else "⚠️",
            website_90d_avg=await get_90d_website_history_ratio(),
            website_90d_avg_symbol="✅"
            if await get_90d_website_history_label()
            else "⚠️",
            qr_code_api_90d_avg=await get_90d_qr_api_history_ratio(),
            qr_code_api_90d_avg_symbol="✅"
            if await get_90d_qr_api_history_ratio()
            else "⚠️",
            api_90d_avg=await get_90d_api_history_ratio(),
            api_90d_avg_symbol="✅" if await get_90d_api_history_label() else "⚠️",
            docs_90d_avg=await get_90d_api_docs_history_ratio(),
            docs_90d_avg_symbol="✅" if await get_90d_api_docs_history_label() else "⚠️",
            internal_api_90d_avg=await get_90d_internal_api_history_ratio(),
            internal_api_90d_avg_symbol="✅"
            if await get_90d_internal_api_history_label()
            else "⚠️",
        ),
        disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(
            [[InlineKeyboardButton(plate("back_button"), "back_start")]]
        ),
    )
    await cb_wrapper.answer()
예제 #10
0
async def get_random_user(_, message):
    logging.warning(
        f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /getranduser"
    )
    if len(message.command) > 1:
        await wrapper.send_message(
            message.chat.id, plate("no_parameters", command="/getranduser"))
    else:
        user = random.choice(get_users())
        result = get_user(*user)
        text = format_user(result)
        await wrapper.send_message(message.chat.id, text)
예제 #11
0
async def clear_flood(_, message):
    if len(message.command) == 1:
        global MESSAGES  # Ew...
        MESSAGES = defaultdict(list)
        for user in BANNED_USERS.copy():
            BANNED_USERS.remove(user)
        await wrapper.send_message(message.chat.id, plate("flood_cleared"))
    else:
        for user in message.command[1:]:
            if not user.isdigit():
                return await wrapper.send_message(
                    message.chat.id, plate("error") + ":" + plate("non_numeric_id")
                )
            BANNED_USERS.discard(int(user))
            # noinspection PyUnboundLocalVariable
            MESSAGES.pop(int(user), None)
        await wrapper.send_message(
            message.chat.id,
            plate(
                "flood_user_cleared",
                user="******".join((f"{usr}" for usr in message.command[1:])),
            ),
        )
예제 #12
0
async def whisper(_, message):
    if len(message.command) < 2:
        return await wrapper.send_message(
            message.chat.id,
            plate("invalid_syntax", correct="/whisper ID") +
            "\n<b>HTML and Markdown styling supported</b>",
        )

    if not message.command[1].isdigit():
        return await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" + plate("non_numeric_id"))

    logging.warning(
        f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent {message.text.html}"
    )

    tg_id = int(message.command[1])
    msg = message.text.html[9:]
    msg = msg[re.search(message.command[1], msg).end():]

    if tg_id not in itertools.chain(*get_users()):
        return await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" + plate("id_missing", tg_id=tg_id))

    result = await wrapper.send_message(
        tg_id,
        plate(
            "whisper_from",
            admin=
            f"[{ADMINS[message.from_user.id]}]({NAME.format(message.from_user.id)})",
            msg=msg,
        ),
    )

    if isinstance(result, Exception):
        logging.error(
            f"Could not whisper to {tg_id} because of {type(result).__name__}: {result}"
        )
        await wrapper.send_message(
            message.chat.id,
            plate("error") + f": {type(result).__name__} -> {result}")
    else:
        await wrapper.send_message(message.chat.id,
                                   plate("whisper_successful"))
예제 #13
0
async def global_message(_, message):
    if len(message.command) > 1:
        msg = message.text.html[7:]
        logging.warning(
            f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent the following global message: {msg}"
        )

        missed = 0
        attempts = 0

        for tg_id in itertools.chain(*get_users()):
            attempts += 1
            result = await wrapper.send_message(tg_id, msg)

            if isinstance(result, Exception):
                logging.error(
                    f"Could not deliver the global message to {tg_id} because of {type(result).__name__}: {result}"
                )
                missed += 1

        logging.warning(
            f"{attempts - missed}/{attempts} global messages were successfully delivered"
        )
        await wrapper.send_message(
            message.chat.id,
            plate("global_message_stats",
                  attempts=attempts,
                  success=(attempts - missed),
                  msg=msg),
        )
    else:
        await wrapper.send_message(
            message.chat.id,
            plate("invalid_syntax", correct="/global message") +
            "\n<b>HTML and Markdown styling supported</b>",
        )
예제 #14
0
async def update(_, message):
    if len(message.command) != 2:
        return await wrapper.send_message(
            message.chat.id, plate("invalid_syntax", correct="/update ID"))

    if not message.command[1].isdigit():
        return await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" + plate("non_numeric_id"))

    user = get_user(message.command[1])
    if user:
        logging.warning(
            f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /update {message.command[1]}"
        )

        tg_id, tg_uname = user[:2]
        new = await wrapper.get_users(tg_id)

        if isinstance(new, Exception):
            logging.error(
                f"An error has occurred when calling get_users({tg_id}), {type(new).__name__}: {new}"
            )
            await wrapper.send_message(
                message.chat.id,
                plate("error") + f": {type(new).__name__} -> {new}")
        else:
            if new.username is None:
                new.username = "******"
            if new.username != tg_uname:
                update_name(tg_id, new.username)
                await wrapper.send_message(message.chat.id,
                                           plate("user_info_updated"))
            else:
                await wrapper.send_message(message.chat.id,
                                           plate("user_info_unchanged"))
    else:
        await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" +
            plate("id_missing", tg_id=message.command[1]),
        )
예제 #15
0
async def anti_flood(_, update):
    """Anti flood module"""

    user_id = update.from_user.id
    chat = update.chat.id
    date = update.date
    message_id = update.message_id
    if isinstance(MESSAGES[user_id], tuple):
        chat, date = MESSAGES[user_id]
        if time.time() - date >= BAN_TIME:
            logging.warning(
                f"{user_id} has waited at least {BAN_TIME} seconds in {chat} and can now text again"
            )
            BANNED_USERS.remove(user_id)
            del MESSAGES[user_id]
    elif (
        len(MESSAGES[user_id]) >= MAX_UPDATE_THRESHOLD - 1
    ):  # -1 to avoid acting on the next update
        MESSAGES[user_id].append({chat: (date, message_id)})
        logging.info(
            f"MAX_UPDATE_THRESHOLD ({MAX_UPDATE_THRESHOLD}) Reached for {user_id}"
        )
        user_data = MESSAGES.pop(user_id)
        timestamps = [list(*d.values())[0] for d in user_data]
        updates = [list(*d.values())[1] for d in user_data]
        if is_flood(timestamps):
            logging.warning(f"Flood detected from {user_id} in chat {chat}")
            if user_id in CACHE:
                del CACHE[user_id]
            BANNED_USERS.add(user_id)
            # noinspection PyTypeChecker
            MESSAGES[user_id] = chat, time.time()
            if FLOOD_NOTICE:
                await wrapper.send_message(
                    user_id, plate("flood_notice", time=f"{BAN_TIME / 60:.1f}")
                )
            if DELETE_MESSAGES:
                await wrapper.delete_messages(chat, updates)
        else:
            if user_id in MESSAGES:
                del MESSAGES[user_id]
    else:
        MESSAGES[user_id].append({chat: (date, message_id)})
예제 #16
0
async def start_handler(_, update):
    """Simply handles the /start command sending a pre-defined greeting
    and saving new users to the database"""
    update_wrapper = MethodWrapper(update)

    if update.from_user.first_name:
        name = update.from_user.first_name
    elif update.from_user.username:
        name = update.from_user.username
    else:
        name = "Anonymous"
    if update.from_user.id not in itertools.chain(*get_users()):
        logging.warning(
            f"New user detected ({update.from_user.id}), adding to database"
        )
        set_user(
            update.from_user.id,
            update.from_user.username.lower() if update.from_user.username else None,
        )
    if GREET:
        if isinstance(update, Message):
            await update_wrapper.reply(
                text=plate(
                    "greet",
                    mention=f"[{name}](tg://user?id={update.from_user.id})",
                    id=update.from_user.id,
                    username=update.from_user.username,
                    website_status="Online"
                    if await get_website_status()
                    else "Offline",
                    qr_code_api_status="Online"
                    if await get_qr_api_status()
                    else "Offline",
                    api_status="Online" if await get_api_status() else "Offline",
                    api_docs_status="Online"
                    if await get_api_docs_status()
                    else "Offline",
                    internal_api_status="Online"
                    if await get_internal_api_status()
                    else "Offline",
                ),
                reply_markup=BUTTONS,
            )
        elif isinstance(update, CallbackQuery):
            if CACHE[update.from_user.id][0] == "AWAITING_ADMIN":
                data = CACHE[update.from_user.id][-1]

                if isinstance(data, list):
                    for chatid, message_ids in data:
                        await wrapper.delete_messages(chatid, message_ids)

                for admin in ADMINS:
                    await wrapper.send_message(
                        chat_id=admin,
                        text=plate(
                            "user_left_queue",
                            user=f"[{name}]({NAME.format(update.from_user.id)})",
                        ),
                    ),

            await update_wrapper.edit_message_text(
                text=plate(
                    "greet",
                    mention=f"[{name}](tg://user?id={update.from_user.id})",
                    id=update.from_user.id,
                    username=update.from_user.username,
                    website_status="Online"
                    if await get_website_status()
                    else "Offline",
                    qr_code_api_status="Online"
                    if await get_qr_api_status()
                    else "Offline",
                    api_status="Online" if await get_api_status() else "Offline",
                    api_docs_status="Online"
                    if await get_api_docs_status()
                    else "Offline",
                    internal_api_status="Online"
                    if await get_internal_api_status()
                    else "Offline",
                ),
                reply_markup=BUTTONS,
            )

            del CACHE[update.from_user.id]
            await update_wrapper.answer()
예제 #17
0
async def ban(_, message):
    cmd = message.command[0]
    condition = {"ban": False, "unban": True}.get(cmd)

    if len(message.command) != 2:
        return await wrapper.send_message(
            message.chat.id, plate("invalid_syntax", correct=f"/{cmd} ID"))

    if not message.command[1].isdigit():
        return await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" + plate("non_numeric_id"))

    if int(message.command[1]) in ADMINS:
        return await wrapper.send_message(message.chat.id,
                                          plate("cannot_ban_admin"))

    user = get_user(message.command[1])
    if user:
        if bool(user[3]) is condition:
            logging.warning(
                f"{ADMINS[message.from_user.id]} [{message.from_user.id}] sent /{cmd} {message.command[1]}"
            )

            tg_id = user[0]
            if condition:
                res = unban_user(tg_id)
            else:
                res = ban_user(tg_id)

            if isinstance(res, Exception):
                logging.error(
                    f"An error has occurred when calling {cmd}_user({tg_id}), {type(res).__name__}: {res}"
                )
                await wrapper.send_message(
                    message.chat.id,
                    plate("error") + f": {type(res).__name__} -> {res}")
            else:
                if condition and tg_id in BANNED_USERS:
                    BANNED_USERS.remove(tg_id)
                else:
                    BANNED_USERS.add(tg_id)

                await wrapper.send_message(
                    message.chat.id,
                    plate("user_unbanned")
                    if condition else plate("user_banned"),
                )
                await wrapper.send_message(
                    tg_id,
                    plate("you_are_unbanned")
                    if condition else plate("you_are_banned"),
                )
        else:
            await wrapper.send_message(
                message.chat.id,
                plate("user_not_banned")
                if condition else plate("user_already_banned"),
            )
    else:
        await wrapper.send_message(
            message.chat.id,
            plate("error") + ":" +
            plate("id_missing", tg_id=message.command[1]),
        )