Exemple #1
0
def undo_user(client: Client, message: Message, aid: int, uid: int,
              action_type: str) -> str:
    try:
        # Basic
        gid = message.chat.id
        mid = message.message_id

        # Init user data
        if not init_user_id(uid):
            return ""

        # Check the user's lock
        if gid in glovar.user_ids[uid]["lock"]:
            return lang("answer_proceeded")

        # Proceed
        glovar.user_ids[uid]["lock"].add(gid)
        try:
            if action_type == "ban":
                text = unban_user(client, message, uid, aid)
            else:
                text = unwarn_user(client, message, uid, aid)

            thread(edit_message_text, (client, gid, mid, text))
        finally:
            glovar.user_ids[uid]["lock"].discard(gid)

        # Save data
        save("user_ids")
    except Exception as e:
        logger.warning(f"Undo user error: {e}", exc_info=True)

    return ""
Exemple #2
0
def reset_data(client: Client) -> bool:
    # Reset data every month
    try:
        glovar.bad_ids = {"users": set()}
        save("bad_ids")

        glovar.left_group_ids = set()
        save("left_group_ids")

        glovar.user_ids = {}
        save("user_ids")

        glovar.watch_ids = {"ban": {}, "delete": {}}
        save("watch_ids")

        glovar.reports = {}
        save("reports")

        # Send debug message
        text = (
            f"{lang('project')}{lang('colon')}{general_link(glovar.project_name, glovar.project_link)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('reset'))}\n")
        thread(send_message, (client, glovar.debug_channel_id, text))

        return True
    except Exception as e:
        logger.warning(f"Reset data error: {e}", exc_info=True)

    return False
Exemple #3
0
def receive_leave_approve(client: Client, data: dict) -> bool:
    # Receive leave approve
    result = False

    try:
        # Basic data
        admin_id = data["admin_id"]
        the_id = data["group_id"]
        force = data["force"]
        reason = data["reason"]

        if reason in {"permissions", "user"}:
            reason = lang(f"reason_{reason}")

        if not glovar.admin_ids.get(the_id) and not force:
            return True

        text = get_debug_text(client, the_id)
        text += (
            f"{lang('admin_project')}{lang('colon')}{mention_id(admin_id)}\n"
            f"{lang('status')}{lang('colon')}{code(lang('leave_approve'))}\n")

        if reason:
            text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"

        leave_group(client, the_id)
        thread(send_message, (client, glovar.debug_channel_id, text))

        result = True
    except Exception as e:
        logger.warning(f"Receive leave approve error: {e}", exc_info=True)

    return result
Exemple #4
0
def mention_answer(client: Client, message: Message, aid: int, uid: int,
                   action_type: str) -> str:
    # Mention abuse
    try:
        # Basic data
        gid = message.chat.id
        mid = message.message_id

        # Abuse
        if action_type == "abuse":
            message.reply_to_message = message
            message.reply_to_message.from_user.id = uid
            message.reply_to_message.from_user.is_self = lang("abuse_mention")
            text, markup = warn_user(client, message, uid, aid)
            text += f"{lang('reason')}{lang('colon')}{code(lang('reason_abuse'))}\n"

            # Edit the report message
            thread(edit_message_text, (client, gid, mid, text, markup))
            delay(180, delete_message, [client, gid, mid])

        # Delete
        elif action_type == "delete":
            glovar.message_ids[gid] = (0, 0)
            save("message_ids")
            delete_message(client, gid, mid)
    except Exception as e:
        logger.warning(f"Mention answer error: {e}", exc_info=True)

    return ""
Exemple #5
0
def receive_file_data(client: Client,
                      message: Message,
                      decrypt: bool = True) -> Any:
    # Receive file's data from exchange channel
    data = None
    try:
        if not message.document:
            return None

        file_id = message.document.file_id
        path = get_downloaded_path(client, file_id)

        if not path:
            return None

        if decrypt:
            # Decrypt the file, save to the tmp directory
            path_decrypted = get_new_path()
            crypt_file("decrypt", path, path_decrypted)
            path_final = path_decrypted
        else:
            # Read the file directly
            path_decrypted = ""
            path_final = path

        with open(path_final, "rb") as f:
            data = pickle.load(f)

        for f in {path, path_decrypted}:
            thread(delete_file, (f, ))
    except Exception as e:
        logger.warning(f"Receive file error: {e}", exc_info=True)

    return data
Exemple #6
0
def send_debug(client: Client,
               message: Message,
               action: str,
               uid: int,
               aid: int,
               em: Message = None,
               reason: str = None) -> bool:
    # Send the debug message
    try:
        text = get_debug_text(client, message.chat)
        text += (f"{lang('user_id')}{lang('colon')}{code(uid)}\n"
                 f"{lang('action')}{lang('colon')}{code(action)}\n"
                 f"{lang('admin_group')}{lang('colon')}{code(aid)}\n")

        if em:
            text += f"{lang('stored_message')}{lang('colon')}{general_link(em.message_id, message_link(em))}\n"

        # If the message is a report callback message
        if reason:
            text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"
        elif message.from_user.is_self and action not in {
                lang("action_unban"),
                lang("action_unwarns")
        }:
            text += f"{lang('reason')}{lang('colon')}{code(lang('by_button'))}\n"
        else:
            reason = get_command_type(message)
            if reason:
                text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"

        thread(send_message, (client, glovar.debug_channel_id, text))
    except Exception as e:
        logger.warning(f"Send debug error: {e}", exc_info=True)

    return False
Exemple #7
0
def receive_rollback(client: Client, message: Message, data: dict) -> bool:
    # Receive rollback data
    try:
        # Basic data
        aid = data["admin_id"]
        the_type = data["type"]
        the_data = receive_file_data(client, message)

        if not the_data:
            return True

        exec(f"glovar.{the_type} = the_data")
        save(the_type)

        # Send debug message
        text = (
            f"{lang('project')}{lang('colon')}{general_link(glovar.project_name, glovar.project_link)}\n"
            f"{lang('admin_project')}{lang('colon')}{mention_id(aid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('rollback'))}\n"
            f"{lang('more')}{lang('colon')}{code(the_type)}\n")
        thread(send_message, (client, glovar.debug_channel_id, text))
    except Exception as e:
        logger.warning(f"Receive rollback error: {e}", exc_info=True)

    return False
Exemple #8
0
def kick_user(client: Client, gid: int, uid: Union[int, str]) -> bool:
    # Kick a user
    try:
        thread(kick_user_thread, (client, gid, uid))

        return True
    except Exception as e:
        logger.warning(f"Kick user error: {e}", exc_info=True)

    return False
Exemple #9
0
def save(file: str) -> bool:
    # Save a global variable to a file
    try:
        thread(save_thread, (file, ))

        return True
    except Exception as e:
        logger.warning(f"Save error: {e}", exc_info=True)

    return False
Exemple #10
0
def undo(client: Client, message: Message) -> bool:
    # Undo operations

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        aid = message.from_user.id
        r_message = message.reply_to_message

        # Text prefix
        text = (
            f"{lang('admin')}{lang('colon')}{code(aid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('action_undo'))}\n")

        # Check usage
        if not r_message:
            text += (
                f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                f"{lang('reason')}{lang('colon')}{code(lang('command_usage'))}\n"
            )
            thread(send_report_message, (15, client, gid, text))
            return True

        # Check message
        callback_data_list = get_callback_data(r_message)
        if not (r_message.from_user.is_self and callback_data_list
                and callback_data_list[0]["a"] == "undo"):
            text += (
                f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                f"{lang('reason')}{lang('colon')}{code(lang('command_reply'))}\n"
            )
            thread(send_report_message, (15, client, gid, text))
            return True

        # Proceed
        action_type = callback_data_list[0]["t"]
        uid = callback_data_list[0]["d"]
        undo_user(client, r_message, aid, uid, action_type)

        return True
    except Exception as e:
        logger.warning(f"Undo error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #11
0
def delete_message(client: Client, gid: int, mid: int) -> bool:
    # Delete a single message
    try:
        if not gid or not mid:
            return True

        mids = [mid]
        thread(delete_messages, (client, gid, mids))

        return True
    except Exception as e:
        logger.warning(f"Delete message error: {e}", exc_info=True)

    return False
Exemple #12
0
def receive_clear_data(client: Client, data_type: str, data: dict) -> bool:
    # Receive clear data command
    glovar.locks["message"].acquire()
    try:
        # Basic data
        aid = data["admin_id"]
        the_type = data["type"]

        # Clear bad data
        if data_type == "bad":
            if the_type == "channels":
                glovar.bad_ids["channels"] = set()
            elif the_type == "users":
                glovar.bad_ids["users"] = set()

            save("bad_ids")

        # Clear user data
        if data_type == "user":
            if the_type == "all":
                glovar.user_ids = {}

            save("user_ids")

        # Clear watch data
        if data_type == "watch":
            if the_type == "all":
                glovar.watch_ids = {"ban": {}, "delete": {}}
            elif the_type == "ban":
                glovar.watch_ids["ban"] = {}
            elif the_type == "delete":
                glovar.watch_ids["delete"] = {}

            save("watch_ids")

        # Send debug message
        text = (
            f"{lang('project')}{lang('colon')}{general_link(glovar.project_name, glovar.project_link)}\n"
            f"{lang('admin_project')}{lang('colon')}{mention_id(aid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('clear'))}\n"
            f"{lang('more')}{lang('colon')}{code(f'{data_type} {the_type}')}\n"
        )
        thread(send_message, (client, glovar.debug_channel_id, text))
    except Exception as e:
        logger.warning(f"Receive clear data: {e}", exc_info=True)
    finally:
        glovar.locks["message"].release()

    return False
Exemple #13
0
def share_data(client: Client,
               receivers: List[str],
               action: str,
               action_type: str,
               data: Union[bool, dict, int, str] = None,
               file: str = None,
               encrypt: bool = True) -> bool:
    # Use this function to share data in the channel
    try:
        thread(target=share_data_thread,
               args=(client, receivers, action, action_type, data, file,
                     encrypt))

        return True
    except Exception as e:
        logger.warning(f"Share data error: {e}", exc_info=True)

    return False
Exemple #14
0
def warn(client: Client, message: Message) -> bool:
    # Warn users

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        aid = message.from_user.id

        # Get user id
        uid, r_mid = get_class_d_id(message)

        # Check user status
        if not uid or uid in glovar.admin_ids[gid]:
            return True

        # Warn the user
        reason = get_command_type(message)
        text, markup = warn_user(client, message, uid, aid, reason)

        if markup:
            secs = 180
        else:
            secs = 15

        # Send the report message
        r_mid and delete_message(client, gid, r_mid)
        thread(send_report_message, (secs, client, gid, text, None, markup))

        return True
    except Exception as e:
        logger.warning(f"Warn error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #15
0
def forgive(client: Client, message: Message) -> bool:
    # Forgive users

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        # Get user id
        uid, _ = get_class_d_id(message)

        # Check user status
        if not uid or uid in glovar.admin_ids[gid]:
            return True

        # Forgive the user
        reason = get_command_type(message)
        text, success = forgive_user(client, message, uid, reason)
        glovar.user_ids[uid]["lock"].discard(gid)
        save("user_ids")

        if success:
            secs = 180
        else:
            secs = 15

        # Send the report message
        thread(send_report_message, (secs, client, gid, text, None))

        return True
    except Exception as e:
        logger.warning(f"Forgive error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #16
0
def receive_refresh(client: Client, data: int) -> bool:
    # Receive refresh
    try:
        # Basic data
        aid = data

        # Update admins
        update_admins(client)

        # Send debug message
        text = (
            f"{lang('project')}{lang('colon')}{general_link(glovar.project_name, glovar.project_link)}\n"
            f"{lang('admin_project')}{lang('colon')}{mention_id(aid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('refresh'))}\n")
        thread(send_message, (client, glovar.debug_channel_id, text))

        return True
    except Exception as e:
        logger.warning(f"Receive refresh error: {e}", exc_info=True)

    return False
Exemple #17
0
def leave_group(client: Client, gid: int) -> bool:
    # Leave a group, clear it's data
    try:
        glovar.left_group_ids.add(gid)
        save("left_group_ids")
        thread(leave_chat, (client, gid))

        glovar.admin_ids.pop(gid, None)
        save("admin_ids")

        glovar.message_ids.pop(gid, (0, 0))
        save("message_ids")

        glovar.configs.pop(gid, None)
        save("configs")

        return True
    except Exception as e:
        logger.warning(f"Leave group error: {e}", exc_info=True)

    return False
Exemple #18
0
def receive_config_reply(client: Client, data: dict) -> bool:
    # Receive config reply
    try:
        # Basic data
        gid = data["group_id"]
        uid = data["user_id"]
        link = data["config_link"]

        text = (
            f"{lang('admin')}{lang('colon')}{code(uid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('config_change'))}\n"
            f"{lang('description')}{lang('colon')}{code(lang('config_button'))}\n"
        )
        markup = InlineKeyboardMarkup(
            [[InlineKeyboardButton(text=lang("config_go"), url=link)]])
        thread(send_report_message, (180, client, gid, text, None, markup))

        return True
    except Exception as e:
        logger.warning(f"Receive config reply error: {e}", exc_info=True)

    return False
Exemple #19
0
def exchange_to_hide(client: Client) -> bool:
    # Let other bots exchange data in the hide channel instead
    try:
        glovar.should_hide = True
        share_data(client=client,
                   receivers=["EMERGENCY"],
                   action="backup",
                   action_type="hide",
                   data=True)

        # Send debug message
        text = (
            f"{lang('project')}{lang('colon')}{code(glovar.sender)}\n"
            f"{lang('issue')}{lang('colon')}{code(lang('exchange_invalid'))}\n"
            f"{lang('auto_fix')}{lang('colon')}{code(lang('protocol_1'))}\n")
        thread(send_message, (client, glovar.critical_channel_id, text))

        return True
    except Exception as e:
        logger.warning(f"Exchange to hide error: {e}", exc_info=True)

    return False
Exemple #20
0
def unban(client: Client, message: Message) -> bool:
    # Unban a user

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        aid = message.from_user.id
        command_type, command_context = get_command_context(message)

        # Text prefix
        text = (
            f"{lang('admin')}{lang('colon')}{code(aid)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('action_unban'))}\n")

        # Check command format
        if not command_type:
            text += (
                f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                f"{lang('reason')}{lang('colon')}{code(lang('command_usage'))}\n"
            )
            thread(send_report_message, (15, client, gid, text))
            return True

        # Get user id
        uid = get_int(command_context)
        if not uid:
            peer_type, peer_id = resolve_username(client, command_type)
            if peer_type == "user" and peer_id:
                uid = peer_id

        # Proceed
        if not uid:
            text += (
                f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                f"{lang('reason')}{lang('colon')}{code(lang('command_para'))}\n"
            )
            thread(send_report_message, (15, client, gid, text))
            return True

        # Proceed
        text = unban_user(client, message, uid, aid)
        thread(send_report_message, (30, client, gid, text))

        return True
    except Exception as e:
        logger.warning(f"Unban error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #21
0
def answer(client: Client, callback_query: CallbackQuery) -> bool:
    # Answer the callback query
    try:
        # Basic data
        gid = callback_query.message.chat.id
        aid = callback_query.from_user.id
        mid = callback_query.message.message_id
        callback_data = loads(callback_query.data)
        action = callback_data["a"]
        action_type = callback_data["t"]
        data = callback_data["d"]

        # Undo
        if action == "undo":
            uid = data
            text = undo_user(client, callback_query.message, aid, uid, action_type)

        # Mention abuse
        elif action == "mention":
            uid = data
            text = mention_answer(client, callback_query.message, aid, uid, action_type)

        # Answer report
        elif action == "report":
            key = data
            text = report_answer(client, callback_query.message, gid, aid, mid, action_type, key)

        else:
            text = ""

        thread(answer_callback, (client, callback_query.id, text))

        return True
    except Exception as e:
        logger.warning(f"Answer callback error: {e}", exc_info=True)

    return False
Exemple #22
0
def share_data_thread(client: Client,
                      receivers: List[str],
                      action: str,
                      action_type: str,
                      data: Union[bool, dict, int, str] = None,
                      file: str = None,
                      encrypt: bool = True) -> bool:
    # Share data thread
    try:
        if glovar.sender in receivers:
            receivers.remove(glovar.sender)

        if not receivers:
            return True

        if glovar.should_hide:
            channel_id = glovar.hide_channel_id
        else:
            channel_id = glovar.exchange_channel_id

        if file:
            text = format_data(sender=glovar.sender,
                               receivers=receivers,
                               action=action,
                               action_type=action_type,
                               data=data)

            if encrypt:
                # Encrypt the file, save to the tmp directory
                file_path = get_new_path()
                crypt_file("encrypt", file, file_path)
            else:
                # Send directly
                file_path = file

            result = send_document(client, channel_id, file_path, text)

            # Delete the tmp file
            if result:
                for f in {file, file_path}:
                    f.startswith("tmp/") and thread(delete_file, (f, ))
        else:
            text = format_data(sender=glovar.sender,
                               receivers=receivers,
                               action=action,
                               action_type=action_type,
                               data=data)
            result = send_message(client, channel_id, text)

        # Sending failed due to channel issue
        if result is False and not glovar.should_hide:
            # Use hide channel instead
            exchange_to_hide(client)
            thread(
                share_data,
                (client, receivers, action, action_type, data, file, encrypt))

        return True
    except Exception as e:
        logger.warning(f"Share data thread error: {e}", exc_info=True)

    return False
Exemple #23
0
def ban_user(client: Client,
             message: Message,
             uid: int,
             aid: int,
             result: int = 0,
             reason: str = None) -> (str, InlineKeyboardMarkup):
    # Ban a user
    text = ""
    markup = None
    try:
        # Basic data
        gid = message.chat.id

        # Check admin
        if is_limited_admin(gid, aid):
            return "", None

        # Init user data
        if not init_user_id(uid):
            return "", None

        # Check users' locks
        if gid in glovar.user_ids[uid]["lock"]:
            return "", None

        # Proceed
        glovar.user_ids[uid]["lock"].add(gid)
        try:
            if gid in glovar.user_ids[uid]["ban"]:
                text += (
                    f"{lang('user_id')}{lang('colon')}{mention_id(uid)}\n"
                    f"{lang('action')}{lang('colon')}{code(lang('action_ban'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('reason_banned'))}\n"
                    f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"
                )
                return text, None

            if not result:
                result = forward_evidence(client=client,
                                          message=message.reply_to_message,
                                          level=lang("action_ban"))

            if not result:
                text += (
                    f"{lang('user_id')}{lang('colon')}{mention_id(uid)}\n"
                    f"{lang('action')}{lang('colon')}{code(lang('action_ban'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('reason_deleted'))}\n"
                    f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"
                )
                return text, None

            # Count admin operation
            glovar.counts[gid][aid] += 1

            # Ban the user
            thread(kick_chat_member, (client, gid, uid))
            glovar.user_ids[uid]["ban"].add(gid)
            glovar.user_ids[uid]["warn"].pop(gid, 0)
            update_score(client, uid)

            # Generate report text
            stored_link = general_link(result.message_id, message_link(result))
            text += (
                f"{lang('user_banned')}{lang('colon')}{mention_id(uid)}\n"
                f"{lang('stored_message')}{lang('colon')}{stored_link}\n"
                f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"
            )

            if reason:
                text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"

            # Generate report markup
            data = button_data("undo", "ban", uid)
            markup = InlineKeyboardMarkup([[
                InlineKeyboardButton(text=lang("unban"), callback_data=data)
            ]])

            # Share
            ask_for_help(client, "delete", gid, uid)
            send_debug(client=client,
                       message=message,
                       action=lang("action_ban"),
                       uid=uid,
                       aid=aid,
                       em=result,
                       reason=reason)
        finally:
            glovar.user_ids[uid]["lock"].discard(gid)
    except Exception as e:
        logger.warning(f"Ban user error: {e}", exc_info=True)

    return text, markup
Exemple #24
0
def admin(client: Client, message: Message) -> bool:
    # Mention admins

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if is_class_c(None, None, message):
            return True

        # Check config
        if not glovar.configs[gid].get("mention"):
            return True

        uid = message.from_user.id

        # Init user data
        if not init_user_id(uid):
            return True

        # Warned user and the user having report status can't mention admins
        if (gid in glovar.user_ids[uid]["waiting"]
                or gid in glovar.user_ids[uid]["ban"]
                or glovar.user_ids[uid]["warn"].get(gid)):
            return True

        # Generate report text
        text = (
            f"{lang('from_user')}{lang('colon')}{mention_id(uid)}\n"
            f"{lang('mention_admins')}{lang('colon')}{get_admin_text(gid)}\n")
        reason = get_command_type(message)

        if reason:
            text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"

        # Generate report markup
        button_abuse = button_data("mention", "abuse", uid)
        button_delete = button_data("mention", "delete", uid)
        markup = InlineKeyboardMarkup([[
            InlineKeyboardButton(text=lang("abuse"),
                                 callback_data=button_abuse),
            InlineKeyboardButton(text=lang("del"), callback_data=button_delete)
        ]])

        # Send the report message
        if message.reply_to_message:
            rid = message.reply_to_message.message_id
        else:
            rid = None

        result = send_message(client, gid, text, rid, markup)

        if not result:
            return True

        old_mid, _ = glovar.message_ids.get(gid, (0, 0))
        old_mid and thread(delete_message, (client, gid, old_mid))
        sent_mid = result.message_id
        glovar.message_ids[gid] = (sent_mid, get_now())
        save("message_ids")

        return True
    except Exception as e:
        logger.warning(f"Admin error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #25
0
def report(client: Client, message: Message) -> bool:
    # Report spam messages

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Normal user
        if not is_class_c(None, None, message):
            # Check config
            if not glovar.configs[gid]["report"]["manual"]:
                return True

            rid = message.from_user.id
            now = message.date or get_now()

            # Init user data
            if not init_user_id(rid):
                return True

            # Get user id
            uid, r_mid = get_class_d_id(message)

            # Init user data
            if not uid or not init_user_id(uid):
                return True

            # Check user status
            bad_user = (gid in glovar.user_ids[rid]["lock"]
                        or gid in glovar.user_ids[uid]["lock"]
                        or gid in glovar.user_ids[rid]["waiting"]
                        or gid in glovar.user_ids[uid]["waiting"]
                        or gid in glovar.user_ids[uid]["ban"]
                        or is_watch_user(message.from_user, "ban", now)
                        or is_watch_user(message.from_user, "delete", now)
                        or is_high_score_user(message.from_user))
            good_user = (is_class_e_user(message.from_user)
                         and uid not in glovar.admin_ids[gid])

            # Users can not self-report
            if uid == rid or (bad_user and not good_user):
                return True

            # Reporter cannot report someone by replying WARN's report
            r_message = message.reply_to_message

            if r_message.from_user.is_self:
                return True

            # Proceed
            if r_message.service:
                name = get_full_name(r_message.from_user)
            else:
                name = None

            reason = get_command_type(message)

            text, markup, key = report_user(gid, r_message.from_user, rid,
                                            r_mid, name, reason)
            result = send_message(client, gid, text, r_mid, markup)

            if result:
                glovar.reports[key]["report_id"] = result.message_id
            else:
                glovar.reports.pop(key, {})

            save("reports")

        # Admin
        else:
            aid = message.from_user.id
            action_type, reason = get_command_context(message)

            # Text prefix
            text = (
                f"{lang('admin')}{lang('colon')}{code(aid)}\n"
                f"{lang('action')}{lang('colon')}{code(lang('action_answer'))}\n"
            )

            # Check command format
            if action_type not in {"warn", "ban", "cancel", "abuse"
                                   } or not message.reply_to_message:
                text += (
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('command_usage'))}\n"
                )
                thread(send_report_message, (15, client, gid, text))
                return True

            # Check the evidence message
            r_message = get_message(client, gid,
                                    message.reply_to_message.message_id)
            if not r_message or not r_message.reply_to_message:
                text += (
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('reason_deleted'))}\n"
                )
                thread(send_report_message, (15, client, gid, text))
                return True

            # Check the report message
            callback_data_list = get_callback_data(r_message)
            if not callback_data_list or callback_data_list[0]["a"] != "report":
                text += (
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('command_reply'))}\n"
                )
                thread(send_report_message, (15, client, gid, text))
                return True

            # Proceed
            key = callback_data_list[0]["d"]
            report_answer(client=client,
                          message=r_message,
                          gid=gid,
                          aid=aid,
                          mid=r_message.message_id,
                          action_type=action_type,
                          key=key,
                          reason=reason)

        return True
    except Exception as e:
        logger.warning(f"Report error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #26
0
def config_directly(client: Client, message: Message) -> bool:
    # Config the bot directly

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        aid = message.from_user.id
        success = True
        reason = lang("config_updated")
        new_config = deepcopy(glovar.configs[gid])
        text = f"{lang('admin_group')}{lang('colon')}{code(aid)}\n"

        # Check command format
        command_type, command_context = get_command_context(message)
        if command_type:
            if command_type == "show":
                text += f"{lang('action')}{lang('colon')}{code(lang('config_show'))}\n"
                text += get_config_text(new_config)
                thread(send_report_message, (30, client, gid, text))
                return True

            now = get_now()
            if now - new_config["lock"] > 310:
                if command_type == "default":
                    new_config = deepcopy(glovar.default_config)
                else:
                    if command_context:
                        if command_type in {"delete", "mention"}:
                            if command_context == "off":
                                new_config[command_type] = False
                            elif command_context == "on":
                                new_config[command_type] = True
                            else:
                                success = False
                                reason = lang("command_para")
                        elif command_type == "limit":
                            limit = get_int(command_context)
                            if 2 <= limit <= 5:
                                new_config["limit"] = limit
                            else:
                                success = False
                                reason = lang("command_para")
                        elif command_type == "report":
                            if not new_config.get("report"):
                                new_config["report"] = {}

                            if command_context == "off":
                                new_config["report"]["auto"] = False
                                new_config["report"]["manual"] = False
                            elif command_context == "auto":
                                new_config["report"]["auto"] = True
                                new_config["report"]["manual"] = False
                            elif command_context == "manual":
                                new_config["report"]["auto"] = False
                                new_config["report"]["manual"] = True
                            elif command_context == "both":
                                new_config["report"]["auto"] = True
                                new_config["report"]["manual"] = True
                            else:
                                success = False
                                reason = lang("command_para")
                        else:
                            success = False
                            reason = lang("command_type")
                    else:
                        success = False
                        reason = lang("command_lack")

                    if success:
                        new_config["default"] = False
            else:
                success = False
                reason = lang("config_locked")
        else:
            success = False
            reason = lang("command_usage")

        if success and new_config != glovar.configs[gid]:
            # Save new config
            glovar.configs[gid] = new_config
            save("configs")

            # Send debug message
            debug_text = get_debug_text(client, message.chat)
            debug_text += (
                f"{lang('admin_group')}{lang('colon')}{code(message.from_user.id)}\n"
                f"{lang('action')}{lang('colon')}{code(lang('config_change'))}\n"
                f"{lang('more')}{lang('colon')}{code(f'{command_type} {command_context}')}\n"
            )
            thread(send_message, (client, glovar.debug_channel_id, debug_text))

        text += (
            f"{lang('action')}{lang('colon')}{code(lang('config_change'))}\n"
            f"{lang('status')}{lang('colon')}{code(reason)}\n")
        thread(send_report_message,
               ((lambda x: 10 if x else 5)(success), client, gid, text))

        return True
    except Exception as e:
        logger.warning(f"Config directly error: {e}", exc_info=True)
    finally:
        delete_message(client, gid, mid)

    return False
Exemple #27
0
 def wrapper(*args, **kwargs):
     return thread(func, args, kwargs, daemon)
Exemple #28
0
def report_answer(client: Client,
                  message: Message,
                  gid: int,
                  aid: int,
                  mid: int,
                  action_type: str,
                  key: str,
                  reason: str = None) -> str:
    # Answer the user's report
    try:
        report_record = glovar.reports.get(key)

        if not report_record:
            message_text = get_text(message)
            uid = get_int(message_text.split("\n")[0].split(lang("colon"))[1])
            text = (
                f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"
                f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                f"{lang('reason')}{lang('colon')}{code(lang('expired'))}\n")
            thread(edit_message_text, (client, gid, mid, text))
            delay(15, delete_message, [client, gid, mid])
            glovar.user_ids[uid]["waiting"].discard(gid)
            save("user_ids")
            return ""

        if not report_record["time"]:
            return ""

        rid = report_record["reporter_id"]
        uid = report_record["user_id"]
        r_mid = report_record["message_id"]
        record_reason = report_record["reason"]

        if not reason:
            reason = record_reason

        if not (init_user_id(rid) and init_user_id(uid)):
            return ""

        # Check users' locks
        if gid in glovar.user_ids[uid]["lock"] or gid in glovar.user_ids[rid][
                "lock"]:
            return lang("answer_proceeded")

        # Lock the report status
        glovar.reports[key]["time"] = 0
        try:
            if action_type == "ban":
                text, markup = ban_user(client, message, uid, aid, 0, reason)
                thread(delete_message, (client, gid, r_mid))
            elif action_type == "warn":
                text, markup = warn_user(client, message, uid, aid, reason)
                thread(delete_message, (client, gid, r_mid))
            elif action_type == "abuse":
                if not rid:
                    return ""

                message.reply_to_message.from_user.id = rid
                message.reply_to_message.from_user.is_self = lang(
                    "abuse_report")
                text, markup = warn_user(client, message, rid, aid)
                text += f"{lang('reason')}{lang('colon')}{code(lang('reason_abuse'))}\n"
            else:
                reported_link = general_link(
                    r_mid, f'{get_channel_link(message)}/{r_mid}')

                if rid:
                    reporter_text = code(rid)
                else:
                    reporter_text = code(lang("auto_triggered"))

                text = (
                    f"{lang('reported_user')}{lang('colon')}{mention_id(uid)}\n"
                    f"{lang('reported_message')}{lang('colon')}{reported_link}\n"
                    f"{lang('reporter')}{lang('colon')}{reporter_text}\n"
                    f"{lang('action')}{lang('colon')}{code(lang('action_cancel'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_succeeded'))}\n"
                    f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"
                )
                markup = None

            if markup:
                secs = 180
            else:
                secs = 15

            thread(edit_message_text, (client, gid, mid, text, markup))
            delay(secs, delete_message, [client, gid, mid])
        finally:
            glovar.user_ids[uid]["lock"].discard(gid)
            glovar.user_ids[rid]["lock"].discard(gid)
            glovar.user_ids[uid]["waiting"].discard(gid)
            glovar.user_ids[rid]["waiting"].discard(gid)
            save("user_ids")
    except Exception as e:
        logger.warning(f"Report answer error: {e}", exc_info=True)

    return ""
Exemple #29
0
def config(client: Client, message: Message) -> bool:
    # Request CONFIG session

    if not message or not message.chat:
        return True

    # Basic data
    gid = message.chat.id
    mid = message.message_id

    try:
        # Check permission
        if not is_class_c(None, None, message):
            return True

        # Check command format
        command_type = get_command_type(message)
        if not command_type or not re.search(f"^{glovar.sender}$",
                                             command_type, re.I):
            return True

        now = get_now()

        # Check the config lock
        if now - glovar.configs[gid]["lock"] < 310:
            return True

        # Set lock
        glovar.configs[gid]["lock"] = now
        save("configs")

        # Ask CONFIG generate a config session
        group_name, group_link = get_group_info(client, message.chat)
        share_data(client=client,
                   receivers=["CONFIG"],
                   action="config",
                   action_type="ask",
                   data={
                       "project_name": glovar.project_name,
                       "project_link": glovar.project_link,
                       "group_id": gid,
                       "group_name": group_name,
                       "group_link": group_link,
                       "user_id": message.from_user.id,
                       "config": glovar.configs[gid],
                       "default": glovar.default_config
                   })

        # Send debug message
        text = get_debug_text(client, message.chat)
        text += (
            f"{lang('admin_group')}{lang('colon')}{code(message.from_user.id)}\n"
            f"{lang('action')}{lang('colon')}{code(lang('config_create'))}\n")
        thread(send_message, (client, glovar.debug_channel_id, text))

        return True
    except Exception as e:
        logger.warning(f"Config error: {e}", exc_info=True)
    finally:
        if is_class_c(None, None, message):
            delay(3, delete_message, [client, gid, mid])
        else:
            delete_message(client, gid, mid)

    return False
Exemple #30
0
def forgive_user(client: Client,
                 message: Message,
                 uid: int,
                 reason: str = None) -> (str, bool):
    # Forgive user
    text = ""
    success = False
    try:
        # Basic data
        gid = message.chat.id
        aid = message.from_user.id

        # Init user data
        if not init_user_id(uid):
            return "", False

        # Check users' locks
        if gid in glovar.user_ids[uid]["lock"]:
            return "", False

        # Proceed
        glovar.user_ids[uid]["lock"].add(gid)
        try:
            # Text prefix
            text += f"{lang('user_id')}{lang('colon')}{mention_id(uid)}\n"

            if gid in glovar.user_ids[uid]["ban"]:
                glovar.user_ids[uid]["ban"].discard(gid)
                thread(unban_chat_member, (client, gid, uid))
                text += (
                    f"{lang('action')}{lang('colon')}{code(lang('action_unban'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_succeeded'))}\n"
                )
                success = True
            elif glovar.user_ids[uid]["warn"].get(gid, 0):
                glovar.user_ids[uid]["warn"].pop(gid, 0)
                text += (
                    f"{lang('action')}{lang('colon')}{code(lang('action_unwarns'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_succeeded'))}\n"
                )
                success = True
            elif gid in glovar.user_ids[uid]["waiting"]:
                glovar.user_ids[uid]["waiting"].discard(gid)
                text += (
                    f"{lang('action')}{lang('colon')}{code(lang('action_unwait'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_succeeded'))}\n"
                )
                success = True
            else:
                text += (
                    f"{lang('action')}{lang('colon')}{code(lang('action_forgive'))}\n"
                    f"{lang('status')}{lang('colon')}{code(lang('status_failed'))}\n"
                    f"{lang('reason')}{lang('colon')}{code(lang('reason_none'))}\n"
                )
                success = False

            text += f"{lang('description')}{lang('colon')}{code(lang('description_by_admin'))}\n"

            if not success:
                return text, success

            save("user_ids")

            if reason:
                text += f"{lang('reason')}{lang('colon')}{code(reason)}\n"

            update_score(client, uid)
            send_debug(client=client,
                       message=message,
                       action=lang("action_forgive"),
                       uid=uid,
                       aid=aid,
                       reason=reason)
        finally:
            glovar.user_ids[uid]["lock"].discard(gid)
    except Exception as e:
        logger.warning(f"Forgive user error: {e}")

    return text, success