From 76d7d7f4c6147664277bae4cf6639f256f0a33e6 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Sun, 13 Nov 2022 13:40:49 +0100 Subject: [PATCH 1/4] /warn and /warnings commands --- locale/uk.json | 14 +++--- main.py | 110 +++++++++++++++++++++++++++++++++++++---------- modules/utils.py | 9 ++-- 3 files changed, 98 insertions(+), 35 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index 0678d1e..5e3b8b8 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -1,12 +1,4 @@ { - "commands": { - "start": "Почати користуватись ботом", - "rules": "Правила пропонування фото" - }, - "commands_admin": { - "forwards": "Переглянути репости", - "reboot": "Перезапустити бота" - }, "message": { "start": "Привіт і ласкаво просимо!\n\nЦей бот створено для прийому заявок на вступ до нашої спільноти. Для продовження нас цікавить відповідь на одне питання:\n\nЧи хочеш ти доєднатися до українського ком'юніті фанатів Хололайв?", "goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.", @@ -55,6 +47,12 @@ "reapply_in_progress": "❌ **Дія неможлива**\nТи прямо зараз вже заповнюєш анкету. Якщо в ній є помилка - після заповнення просто натисни **{0}** та почни знову.", "birthday": "У користувача **{0}** (@{1}) сьогодні день народження! Виповнилось {2} років", "application_invalid_syntax": "Неправильний синтаксис!\nТреба: `/application ID/NAME/USERNAME`", + "warned": "Попереджено користувача **{0}** (`{1}`) про порушення правил", + "warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження", + "warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень", + "no_warnings": "Користувач **{0}** (`{1}`) не має попереджень", + "no_user_warnings": "Не знайдено користувачів за запитом **{0}**", + "syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`", "question_titles": { "question1": "Ім'я/звертання:", "question2": "День народження:", diff --git a/main.py b/main.py index 6c3afcb..1a0d059 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,7 @@ from pyrogram.errors.exceptions import bad_request_400 pid = getpid() -for entry in [f"{configGet('data', 'locations')}{sep}applications.json"]: +for entry in [f"{configGet('data', 'locations')}{sep}applications.json", f"{configGet('data', 'locations')}{sep}warnings.json"]: mode = 'r' if path.exists(entry) else 'w' with open(entry, mode) as f: try: @@ -50,10 +50,10 @@ async def cmd_start(app, msg): # Shutdown command ============================================================================================================= -@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["", "/"])) +@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) async def cmd_kill(app, msg): - if await isAnAdmin(msg.from_user.id): + if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id): logWrite(f"Shutting down bot with pid {pid}") await msg.reply_text(f"Вимкнення бота з підом `{pid}`") killProc(pid) @@ -61,28 +61,82 @@ async def cmd_kill(app, msg): # Rules command ============================================================================================================= -@app.on_message(~ filters.scheduled & filters.private & filters.command(["rules"], prefixes=["", "/"])) +@app.on_message(~ filters.scheduled & filters.private & filters.command(["rules"], prefixes=["/"])) async def cmd_rules(app, msg): for rule_msg in locale("rules"): await msg.reply_text(rule_msg) # ============================================================================================================================== +# Warn command ============================================================================================================= +@app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"])) +async def cmd_warn(app, msg): + + if msg.chat.id == configGet("destination_group"): + if msg.reply_to_message_id != None: + if isAnAdmin(msg.from_user.id): + warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json") + if str(msg.reply_to_message.from_user.id) not in warnings: + warnings[str(msg.reply_to_message.from_user.id)] = 1 + else: + warnings[str(msg.reply_to_message.from_user.id)] += 1 + jsonSave(warnings, f"{configGet('data', 'locations')}{sep}warnings.json") + await msg.reply_text(locale("warned", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id)) # type: ignore +# ============================================================================================================================== + + +# Warnings command ============================================================================================================= +@app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"])) +async def cmd_warnings(app, msg): + + if msg.chat.id == configGet("admin_group") or await isAnAdmin(msg.from_user.id): + + warnings = jsonLoad(f"{configGet('data', 'locations')}{sep}warnings.json") + + if len(msg.command) <= 1: + await msg.reply_text(locale("syntax_warnings", "message")) + + if path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json"): + target_id = str(int(msg.command[1])) + target_name = "N/A" + else: + list_of_users = [] + async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): + list_of_users.append(m) + + if len(list_of_users) != 0: + target = list_of_users[0].user + target_name = target.first_name + target_id = str(target.id) + else: + await msg.reply_text(locale("no_user_warnings", "message").format(msg.command[1])) # type: ignore + return + + if target_id not in warnings: + await msg.reply_text(locale("no_warnings", "message").format(target_name, target_id)) # type: ignore + else: + if warnings[target_id] <= 5: + await msg.reply_text(locale("warnings_1", "message").format(target_name, target_id, warnings[target_id])) # type: ignore + else: + await msg.reply_text(locale("warnings_2", "message").format(target_name, target_id, warnings[target_id])) # type: ignore +# ============================================================================================================================== + + # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & filters.private & filters.command(["applications"], prefixes=["", "/"])) +@app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"])) async def cmd_applications(app, msg): - if await isAnAdmin(msg.from_user.id): + if (await isAnAdmin(msg.from_user.id)) or (msg.chat.id == configGet("admin_group")): await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT) await msg.reply_document(document=f"{configGet('data', 'locations')}{sep}applications.json") # ============================================================================================================================== # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & filters.private & filters.command(["application"], prefixes=["", "/"])) +@app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"])) async def cmd_application(app, msg): - if await isAnAdmin(msg.from_user.id): + if (await isAnAdmin(msg.from_user.id)) or (msg.chat.id == configGet("admin_group")): try: if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]): user_id = int(msg.command[1]) @@ -92,17 +146,17 @@ async def cmd_application(app, msg): list_of_users.append(m) user_id = list_of_users[0].user.id try: - user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id.user.id}.json") + user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json") application_content = [] i = 1 for question in configGet("application", file=str(msg.from_user.id)): if i == 2: - age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(user_id.user.id))['2'], '%d.%m.%Y')) - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(user_id.user.id))['2']} ({age.years} р.)") + age = relativedelta(datetime.now(), datetime.strptime(configGet('application', file=str(user_id))['2'], '%d.%m.%Y')) + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(user_id))['2']} ({age.years} р.)") else: - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(user_id.user.id))[question]}") + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {configGet('application', file=str(user_id))[question]}") i += 1 - application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id.user.id)] + application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)] if user_data["sent"]: if user_data["approved"]: application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M")) # type: ignore @@ -117,10 +171,10 @@ async def cmd_application(app, msg): application_status = locale("application_status_refused", "message").format((await app.get_users(application["refused_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M")) # type: ignore else: application_status = locale("application_status_not_send", "message") - logWrite(f"User {msg.from_user.id} requested application of {user_id.user.id}") - await msg.reply_text(locale("contact", "message").format(str(user_id.user.id), "\n".join(application_content), application_status)) # type: ignore + logWrite(f"User {msg.from_user.id} requested application of {user_id}") + await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status)) # type: ignore except FileNotFoundError: - logWrite(f"User {msg.from_user.id} requested application of {user_id.user.id} but user does not exists") + logWrite(f"User {msg.from_user.id} requested application of {user_id} but user does not exists") await msg.reply_text(locale("contact_invalid", "message")) except IndexError: @@ -129,7 +183,7 @@ async def cmd_application(app, msg): # Reapply command ============================================================================================================== -@app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["", "/"])) +@app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"])) async def cmd_reapply(app, msg): if configGet("approved", file=str(msg.from_user.id)) or configGet("refused", file=str(msg.from_user.id)): @@ -138,12 +192,12 @@ async def cmd_reapply(app, msg): configSet("confirmed", False, file=str(msg.from_user.id)) await welcome_pass(app, msg, once_again=True) else: - await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0])) + await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0])) # type: ignore else: if configGet("sent", file=str(msg.from_user.id)): await msg.reply_text(locale("reapply_forbidden", "message")) else: - await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0])) + await msg.reply_text(locale("reapply_in_progress", "message").format(locale("confirm", "keyboard")[1][0])) # type: ignore # ============================================================================================================================== @@ -380,7 +434,7 @@ async def callback_query_refuse(app, clb): # Callbacks application ======================================================================================================== @app.on_callback_query(filters.regex("reapply_yes_[\s\S]*")) # type: ignore -async def callback_query_accept(app, clb): +async def callback_reapply_query_accept(app, clb): fullclb = clb.data.split("_") @@ -404,7 +458,7 @@ async def callback_query_accept(app, clb): await clb.answer(text=locale("sub_accepted", "callback").format(fullclb[2]), show_alert=True) # type: ignore @app.on_callback_query(filters.regex("reapply_no_[\s\S]*")) # type: ignore -async def callback_query_refuse(app, clb): +async def callback_query_reapply_refuse(app, clb): fullclb = clb.data.split("_") @@ -666,9 +720,21 @@ if __name__ == "__main__": app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=admin)) # type: ignore except bad_request_400.PeerIdInvalid: pass - + app.set_bot_commands(commands_admin_list, scope=BotCommandScopeChat(chat_id=configGet("owner"))) # type: ignore + # Registering admin group commands + commands_group_admin_list = [] + for command in configGet("commands_group_admin"): + commands_group_admin_list.append(BotCommand(command, configGet("commands_group_admin")[command])) + app.set_bot_commands(commands_group_admin_list, scope=BotCommandScopeChat(chat_id=configGet("admin_group"))) # type: ignore + + # Registering destination group commands + commands_group_destination_list = [] + for command in configGet("commands_group_destination"): + commands_group_destination_list.append(BotCommand(command, configGet("commands_group_destination")[command])) + app.set_bot_commands(commands_group_destination_list, scope=BotCommandScopeChat(chat_id=configGet("destination_group"))) # type: ignore + idle() app.send_message(configGet("owner"), f"Shutting with pid `{pid}`") # type: ignore diff --git a/modules/utils.py b/modules/utils.py index 54d7893..0cd664e 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -20,7 +20,6 @@ def jsonLoad(filename): except FileNotFoundError: logWrite(f"Could not load json file {filename}: file does not seem to exist!\n{print_exc()}") raise - file.close() return output def jsonSave(contents, filename): @@ -28,7 +27,6 @@ def jsonSave(contents, filename): try: with open(filename, "w", encoding='utf8') as file: file.write(dumps(contents, ensure_ascii=False, indent=4)) - file.close() except Exception as exp: logWrite(f"Could not save json file {filename}: {exp}\n{print_exc()}") return @@ -44,7 +42,8 @@ def configSet(key: str, value, *args: str, file: str = "config"): """ if file == "config": filepath = "" - if this_dict["debug"]: + this_dict = jsonLoad(f"{filepath}{file}.json") + if this_dict["debug"] is True: try: this_dict = jsonLoad("config_debug.json") file = "config_debug" @@ -52,7 +51,7 @@ def configSet(key: str, value, *args: str, file: str = "config"): print("Debug mode is set but config_debug.json is not there! Falling back to config.json", flush=True) else: filepath = f"data{sep}users{sep}" - this_dict = jsonLoad(f"{filepath}{file}.json") + this_dict = jsonLoad(f"{filepath}{file}.json") string = "this_dict" for arg in args: string += f'["{arg}"]' @@ -79,7 +78,7 @@ def configGet(key: str, *args: str, file: str = "config"): except FileNotFoundError: print("Config file not found! Copy config_example.json to config.json, configure it and rerun the bot!", flush=True) exit() - if this_dict["debug"]: + if this_dict["debug"] is True: try: this_dict = jsonLoad("config_debug.json") except FileNotFoundError: From 8601814642b1cbfe87e539e7746778bc9801bb55 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:52:16 +0100 Subject: [PATCH 2/4] Improved behavior with large text in utils --- modules/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/utils.py b/modules/utils.py index 0cd664e..17afbca 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -56,7 +56,11 @@ def configSet(key: str, value, *args: str, file: str = "config"): for arg in args: string += f'["{arg}"]' if type(value) in [str]: - string += f'["{key}"] = "{value}"' + value.replace("'", "\'").replace('"', '\"') + if len(value) < 30: + string += f'["{key}"] = "{value}"' + else: + string += f'["{key}"] = """\n{value}\n"""' else: string += f'["{key}"] = {value}' exec(string) From 1e23f6eb8c2ff0c2936a18da17772cac59fa6589 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Mon, 14 Nov 2022 19:24:22 +0100 Subject: [PATCH 3/4] Fixed useless \n in utils --- modules/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/utils.py b/modules/utils.py index 17afbca..7d69a7c 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -60,7 +60,7 @@ def configSet(key: str, value, *args: str, file: str = "config"): if len(value) < 30: string += f'["{key}"] = "{value}"' else: - string += f'["{key}"] = """\n{value}\n"""' + string += f'["{key}"] = """{value}"""' else: string += f'["{key}"] = {value}' exec(string) From 45505a82c442ee60e33efafc96d4b99fa9b8e9dd Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Mon, 21 Nov 2022 00:29:18 +0100 Subject: [PATCH 4/4] Fixed long line --- modules/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/utils.py b/modules/utils.py index 7d69a7c..1d462d4 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -57,10 +57,10 @@ def configSet(key: str, value, *args: str, file: str = "config"): string += f'["{arg}"]' if type(value) in [str]: value.replace("'", "\'").replace('"', '\"') - if len(value) < 30: - string += f'["{key}"] = "{value}"' - else: - string += f'["{key}"] = """{value}"""' + #if len(value) < 30: + # string += f'["{key}"] = "{value}"' + #else: + string += f'["{key}"] = """{value}"""' else: string += f'["{key}"] = {value}' exec(string)