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 ""
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
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
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 ""
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
def wrapper(*args, **kwargs): return thread(func, args, kwargs, daemon)
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 ""
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
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