From 0c78f21c96ac49765954352f67ed32a8111b26a2 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 1 Feb 2023 14:21:48 +0100 Subject: [PATCH 01/29] This commit closes #23 --- modules/commands/resetcommands.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/commands/resetcommands.py b/modules/commands/resetcommands.py index e9f2c5a..cf648a2 100644 --- a/modules/commands/resetcommands.py +++ b/modules/commands/resetcommands.py @@ -27,11 +27,24 @@ async def cmd_resetcommands(app: Client, msg: Message): logWrite(f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")}', debug=True) await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("admin", "groups"))) await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("users", "groups"))) + for lc in valid_locales: + try: + logWrite(f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")} [{lc}]', debug=True) + await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")), language_code=lc) + await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("users", "groups")), language_code=lc) + except: + pass for admin in configGet("admins"): try: logWrite(f'Resetting commands for admin {admin}', debug=True) await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin)) + for lc in valid_locales: + try: + logWrite(f'Resetting commands for admin {admin} [{lc}]', debug=True) + await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin), language_code=lc) + except: + pass except bad_request_400.PeerIdInvalid: pass -- 2.39.2 From ed2361638a1f47a7867e66d0bbd0b1b301bd8f54 Mon Sep 17 00:00:00 2001 From: profitroll Date: Tue, 7 Feb 2023 11:35:47 +0100 Subject: [PATCH 02/29] This commit closes #27 --- modules/commands/nearby.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index 993322b..b214f3a 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -1,3 +1,4 @@ +from os import path from traceback import print_exc from app import app from pyrogram import filters @@ -6,7 +7,7 @@ from pyrogram.client import Client from classes.holo_user import HoloUser from modules import custom_filters from modules.logging import logWrite -from modules.utils import configGet, locale, should_quote, find_location +from modules.utils import configGet, jsonLoad, locale, should_quote, find_location from modules.database import col_applications, col_users from classes.errors.geo import PlaceNotFoundError @@ -43,10 +44,11 @@ async def cmd_nearby(app: Client, msg: Message): if not entry["user"] == msg.from_user.id: user = col_users.find_one( {"user": entry["user"]} ) if user is not None: - if user["tg_username"] not in [None, "None", ""]: # Check if user has any name - output.append(f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') - else: - output.append(f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') + if entry["user"] in jsonLoad(path.join(configGet("cache", "locations"), "group_members")): + if user["tg_username"] not in [None, "None", ""]: # Check if user has any name + output.append(f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') + else: + output.append(f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') logWrite(f"{holo_user.id} tried to find someone nearby {location[1]} {location[0]} in the radius of {configGet('search_radius')} kilometers") -- 2.39.2 From 8d18ed212648716c2e553da4db26332c5147fb0b Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 15 Feb 2023 11:13:07 +0100 Subject: [PATCH 03/29] This commit closes #29 --- locale/uk.json | 5 +++-- modules/callbacks/spoiler.py | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index 440becb..50599db 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -256,7 +256,8 @@ "sponsor_started": "ℹ️ Заповнення форми розпочато", "sponsor_accepted": "✅ Форму {0} схвалено", "sponsor_rejected": "❌ Форму {0} відхилено", - "spoiler_sent": "✅ Повідомлення надіслано в холо-чат" + "spoiler_sent": "✅ Повідомлення надіслано в холо-чат", + "spoiler_forbidden": "❌ Треба бути учасником чату" }, "inline": { "forbidden": { @@ -279,7 +280,7 @@ "description": "Надіслати цей спойлер до чату" } }, - "rules_msg": "📢Правила можуть доповнюватись та змінюватись, залежно від потреби. У такому разі, порушення, які були вчинені до введення (змінення) правила, порушеннями вважатися не будуть. Про всі зміни в правилах, ви будете проінформовані за допомогою закріплених повідомлень. Але вони не будуть закріплені на постійній основі, тому, час від часу, перевіряйте актуальність правил у боті.\n\n🔔Якщо ви бачите, як хтось із учасників порушив правила, тегніть одного із адмінів, у відповідь на повідомлення, яке, на вашу думку, є порушенням. У дописі до тегу, вкажіть, по якому пункту ви побачили порушення. Або перешліть повідомлення до будь кого із адміністраторів у особисті повідомлення, та коротко опишіть ситуацію.\nСписок адміністраторів: @Chirkopol @Za_NerZula @Denialvapr\nЗ питань функціонування бота звертайтесь до @Profitroll2281337\n\n❗️Будь-який заборонений контент, може бути відправлений за допомогою команди /spoiler у бота - з повним описом контенту, що міститься під спойлером. За неправильний або некоректний опис, може бути видане попередження.\n\n‼️Видалені або змінені повідомлення, все ще є повідомленнями від вашого імені, які могли побачити учасники чату, і які можуть бути відстежені через адмінську панель.\n\n🔨 За порушення - ви отримаєте попередження. За наявності 3-х попереджень - мут на добу. За повторні порушення, ви одразу отримаєте покарання, без додаткових попереджень.", + "rules_msg": "📢Правила можуть доповнюватись та змінюватись, залежно від потреби. У такому разі, порушення, які були вчинені до введення (змінення) правила, порушеннями вважатися не будуть. Про всі зміни в правилах, ви будете проінформовані за допомогою закріплених повідомлень. Але вони не будуть закріплені на постійній основі, тому, час від часу, перевіряйте актуальність правил у боті.\n\n🔔Якщо ви бачите, як хтось із учасників порушив правила, тегніть одного із адмінів, у відповідь на повідомлення, яке, на вашу думку, є порушенням. У дописі до тегу, вкажіть, по якому пункту ви побачили порушення. Або перешліть повідомлення до будь кого із адміністраторів у особисті повідомлення, та коротко опишіть ситуацію.\nСписок адміністраторів: @Chirkopol @Za_NerZula @Toxinushka\nЗ питань функціонування бота звертайтесь до @Profitroll2281337\n\n❗️Будь-який заборонений контент, може бути відправлений за допомогою команди /spoiler у бота - з повним описом контенту, що міститься під спойлером. За неправильний або некоректний опис, може бути видане попередження.\n\n‼️Видалені або змінені повідомлення, все ще є повідомленнями від вашого імені, які могли побачити учасники чату, і які можуть бути відстежені через адмінську панель.\n\n🔨 За порушення - ви отримаєте попередження. За наявності 3-х попереджень - мут на добу. За повторні порушення, ви одразу отримаєте покарання, без додаткових попереджень.", "rules": [ "1️⃣) \"HoloKyiv Chat\" та \"HoloUA (Hololive Ukraine) Chat\" створені виключно для українців (13+). В них можуть знаходитись тільки люди які: \n- Народились в Україні, та проживають, на данний момент, у ній.\n- Народились за межами України, але проживають у ній.\n- Народились в Україні але, на даний момент, не проживають у ній.\n\"HoloUA (Hololive Ukraine) Chat\" відкритий для усіх українців. Щоб потрапити до нього, заповніть, будь ласка, анкету, та дочекайтесь, поки її схвалять адміни.\nУ \"HoloKyiv Chat\" можна потрапити тільки особисто, якщо ви проживаєте у Київі, або є близьким другом одного із учасників чату. Із приводу додавання до чату пишіть @Chirkopol у приватні повідомлення.\n🔨 Якщо у процесі спілкування виявиться, що ви не українець, вас буде видалено із чату, до моменту, поки ви їм не станете. Без образ. Ми створюємо виключно українське ком'юніті.", "2️⃣) Заборонено поширення NSFW-контенту з прямим або частково прихованим порнографічним змістом. На контенті \"еротичного характеру\" повинні бути закриті \"сумнівні\" ділянки тіл. \nЗаборонено поширення шок-контенту з великою наявністю крові та/або фізичних пошкоджень.", diff --git a/modules/callbacks/spoiler.py b/modules/callbacks/spoiler.py index 8118a34..387658d 100644 --- a/modules/callbacks/spoiler.py +++ b/modules/callbacks/spoiler.py @@ -1,3 +1,4 @@ +from os import path from app import app from pyrogram.types import CallbackQuery, InlineKeyboardMarkup, InlineKeyboardButton from pyrogram.client import Client @@ -5,7 +6,7 @@ from pyrogram import filters from modules.database import col_spoilers from bson.objectid import ObjectId -from modules.utils import configGet, locale +from modules.utils import configGet, jsonLoad, locale # Callback sid ================================================================================================================= @app.on_callback_query(filters.regex("sid_[\s\S]*")) @@ -17,6 +18,10 @@ async def callback_query_sid(app: Client, clb: CallbackQuery): @app.on_callback_query(filters.regex("shc_[\s\S]*")) async def callback_query_shc(app: Client, clb: CallbackQuery): + if (clb.from_user.id not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))): + await clb.answer(locale("spoiler_forbidden", "callback", locale=clb.from_user), show_alert=True) + return + spoil = col_spoilers.find_one( {"_id": ObjectId(clb.data.split("_")[1])} ) if spoil["description"] == "": -- 2.39.2 From 64b7a6a4baea5b1b1ac0351e83904b89d2af4c20 Mon Sep 17 00:00:00 2001 From: profitroll Date: Mon, 20 Feb 2023 15:04:09 +0100 Subject: [PATCH 04/29] Made message about JAPANESE girls even bolder --- locale/uk.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locale/uk.json b/locale/uk.json index 50599db..a7b8b49 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -9,7 +9,7 @@ "question4": "Коли вперше довелось дізнатись про Хололайв?", "question5": "Чим тебе зацікавив Хололайв?", "question6": "Контент якої дівчини тобі подобається найбільше?", - "question7": "Назви контент хоча б п'яти **ЯПОНСЬКИХ** холодівчат, які тобі подобаються найбільше.", + "question7": "Назви контент хоча б п'яти **__--ЯПОНСЬКИХ--__** холодівчат, які тобі подобаються найбільше.", "question8": "Чи дивишся ти стріми дівчат Хололайву?", "question9": "Чиї пісні з Хололайву тобі подобаються найбільше?", "question10": "Ну і нарешті, розкажи трохи про себе. Про хобі, чим тобі подобається займатись. Одним повідомленням, будь ласка.", -- 2.39.2 From 5b8951fe07e8a76cedc27648b63133447c7d7abf Mon Sep 17 00:00:00 2001 From: profitroll Date: Mon, 20 Feb 2023 15:04:24 +0100 Subject: [PATCH 05/29] This commit closes #30 --- modules/callbacks/reapply.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index 13671f2..390e2ba 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -116,13 +116,16 @@ async def callback_query_reapply_new(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") - if HoloUser(clb.from_user).sponsorship_state()[0] == "fill": + holo_user = HoloUser(clb.from_user) + + if holo_user.sponsorship_state()[0] == "fill": await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False) return await clb.answer(locale("reapply_stopped", "callback", locale=clb.from_user)) message = await app.get_messages(clb.from_user.id, int(fullclb[2])) - col_tmp.update_one({"user": clb.from_user.id}, {"$set": {"state": "fill", "completed": False, "stage": 1}}) + col_tmp.update_one({"user": clb.from_user.id, "type": "application"}, {"$set": {"state": "fill", "completed": False, "stage": 1}}) + holo_user.application_restart(reapply=True) await welcome_pass(app, message, once_again=True) logWrite(f"User {clb.from_user.id} restarted the application after leaving the chat earlier") await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button", locale=clb.from_user), "nothing")]])) -- 2.39.2 From 3df57f1c42c53d07290fac538e247115883db434 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 1 Mar 2023 19:15:53 +0100 Subject: [PATCH 06/29] Added one more venv to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 796d839..ec263ab 100644 --- a/.gitignore +++ b/.gitignore @@ -162,5 +162,6 @@ TASK.md inline_bot.py .vscode migrate.py +venv_linux validation/* !validation/*.json \ No newline at end of file -- 2.39.2 From 8c21ae1844ce9b9a9d30a13cb0d12fc0ff9a84a3 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 1 Mar 2023 19:16:13 +0100 Subject: [PATCH 07/29] Fixed absence of /warnings in config --- config_example.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/config_example.json b/config_example.json index 6ed09ec..f088ea0 100644 --- a/config_example.json +++ b/config_example.json @@ -136,6 +136,15 @@ "warnings" ] }, + "warnings": { + "permissions": [ + "admins", + "group_admins" + ], + "modules": [ + "warnings" + ] + }, "reapply": { "permissions": [ "users", -- 2.39.2 From 3012c3d5ae1caff94e36bb73c9f2d4cdfa1a4e0e Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 1 Mar 2023 19:16:34 +0100 Subject: [PATCH 08/29] Fixed object type and db lookup --- modules/commands/warnings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index a25e734..50524c1 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -27,12 +27,12 @@ async def cmd_warnings(app: Client, msg: Message): if len(list_of_users) != 0: target = list_of_users[0].user target_name = target.first_name - target_id = str(target.id) + target_id = target.id else: await msg.reply_text(locale("no_user_warnings", "message", locale=msg.from_user).format(msg.command[1])) return - warns = len(list(col_warnings.find({"user": target_id}))) + warns = col_warnings.count_documents({"user": target_id}) if warns == 0: await msg.reply_text(locale("no_warnings", "message", locale=msg.from_user).format(target_name, target_id), quote=should_quote(msg)) -- 2.39.2 From e50cdd53b35ffea02eacbe58a4472ba6ca0e5051 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 1 Mar 2023 19:16:41 +0100 Subject: [PATCH 09/29] Updated dependencies --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 01ea0a5..fde04be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -APScheduler==3.9.1.post1 +APScheduler==3.10.0 fastapi~=0.88.0 psutil==5.9.4 pymongo==4.3.3 -Pyrogram~=2.0.97 +Pyrogram~=2.0.100 requests==2.28.2 tgcrypto==1.2.5 python_dateutil==2.8.2 -- 2.39.2 From 393a7584d5b6394b9c59fda9072a766f59784bb5 Mon Sep 17 00:00:00 2001 From: profitroll Date: Mon, 6 Mar 2023 19:28:31 +0100 Subject: [PATCH 10/29] uk locale update --- locale/uk.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index a7b8b49..d1e23ac 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -1,8 +1,8 @@ { "message": { - "start": "Привіт і ласкаво просимо!\n\nЦей бот створено для прийому заявок на вступ до нашої спільноти. Для продовження нас цікавить відповідь на одне питання:\n\nЧи хочеш ти доєднатися до українського ком'юніті фанатів Хололайв?", + "start": "Привіт і ласкаво просимо!\n\nМи будуємо українське ком'юніті фанатів Гололайву і раді кожному, хто поділяє наші інтереси або тільки зацікавився цією тематикою та хоче дізнатись більше. Чим ми відрізняеємось від звичайного тематичного чату? Ми намагаємось створювати усі можливі умови, щоб люди знаходили однодумців у своїх містах та збирались разом. Інколи проводимо великі зустрічі на честь Голо-івентів у Києві. Збираємось у Дискорді для сумісних переглядів концертів, музичних топів, ігор тощо. Проводимо різні івенти у чаті. Об'єднуємось, щоб замовляти офіційний мерч із Японії. Підтримуємо україномовних кліперів та будуємо плани по поширенню нашого ком'юніті на майбутнє.\n\nЦей бот створений для прийому заявок на вступ до нашої чат-спільноти. Усі анкети, після підтвердження адміністрацією, можуть дивитися й інші учасники чату у будь-який момент. Тому, будь ласка, віднесіться до її заповнення відповідально.\n\nЯкщо вашу анкету відхилили, то, скоріше за все:\n1) Вона порушує перше правило чату (/rules - ознайомитись перед вступом до чату).\n2) Ви намагаєтесь додати до чату \"додатковий/запасний\" акаунт.\n3) Ви не дуже відповідально віднеслись до її заповнення.\n\nЯкщо із вашою анкетою щось не так, то вам через бота прийде повідомлення від адміністраторів для вирішення питання. Якщо ви зіштовхнулись із якоюсь проблемою або бот не надсилає вам необхідні повідомлення - напишіть мені у приватні повідомлення @Chirkopol.\n\nПісля прийому вашої анкети бот згенерує вам одноразове посилання. Не забудьте перейти по ньому, щоб потрапити до чату.\n\nДля продовження, нас цікавить відповідь на питання:\nЧи хочеш ти доєднатись до українського ком'юніті фанатів Гололайв та чи зобов'язуєшся ти дотримуватися усіх правил?", "goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.", - "privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.", + "privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти та подальшої взаємодії в ній.", "question1": "Як до тебе можна звертатись?", "question2": "Коли в тебе день народження?\n\nБудь ласка, у форматі ДД.ММ.РРРР", "question3": "З якого ти міста або де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київ\" або \"Київська Область\" є достатньою конкретизацією.\n\nПриклади:\n• Київ\n• Одеська область\n• Макіївка (Луганська область)", @@ -44,7 +44,7 @@ "startup_downtime_minutes": "Запуск бота з підом `{0}` (лежав {1} хв.)", "startup_downtime_hours": "Запуск бота з підом `{0}` (лежав {1} год.)", "startup_downtime_days": "Запуск бота з підом `{0}` (лежав {1} дн.)", - "approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ. Скористайся кнопкою під повідомленням щоб вступити до нашої лампової спільноти!", + "approved": "Вітаємо! Твою анкету переглянули та підтвердили твоє право на вступ.\n\nПеред тим, як ти натиснеш на кнопочку під повідомленням, щоб вступити до нашої лампової спільноти, дамо тобі трішечки додаткової інформації.\nПам'ятай, що натискаючи її, ти підтверджуєш, що ознайомився із нашими правилами (/rules) та зобов'язуєшся їх дотримуватись.\n\nПісля того, як потрапиш до чату, не закидуй цього бота далеко.\nПрописавши @holoua_bot у боті, ти відкриєш список із усіх наших анкет. Ти можеш натискати на будь-яку із них та дізнаватись про кожного із нас більше інформації.\nЗавдяки команді /nearby, ти зможеш дізнатись, чи є серед нас однодумці із твого міста.\nЯкщо у тебе є спонсорська підписка на будь-кого із учасниць Гололайву, то ти маєш право отримати унікальну роль у нашому чаті (/sponsorship) та виділятись серед інших учасників. (А ще зможеш отримати декілька додаткових функцій. Але нікому про це не кажи!)", "approved_joined": "Вітаємо! Твою анкету переглянули та підтвердили її правильність. Дякуємо за витрачений на заповнення час та гарного дня!", "read_rules": "Будь ласка, прочитай ці правила перш ніж натискати на кнопку та приєднуватись до чату.", "rejected": "Ой лишенько! Твою анкету переглянули, однак не підтвердили право на вступ до спільноти. Better luck next time!\n\nТи можеш спробувати повторно заповнити анкету командою /reapply", @@ -85,7 +85,7 @@ "message_no_user": "⚠️ **Помилка надсилання**\nВказано невірний ID користувача, тому не вдалось надіслати йому повідомлення. Перевірте чи в якості ID надано те число, яке було показане в анкеті.", "message_invalid_syntax": "Неправильний синтаксис!\nТреба: `/message ID ПОВІДОМЛЕННЯ`", "message_from": "Повідомлення від **{0}** (`{1}`):\n\n", - "message_reply_notice": "\n\n**Щоб надіслати відповідь на це повідомлення, тегніть його.**", + "message_reply_notice": "\n\n__Для того, щоб адміністрація побачила вашу відповідь, відправте її **реплаєм на це повідомлення**__", "message_error": "⚠️ **Сталась помилка**\nНе вдалось надіслати ваше повідомлення. Розробника повідомлено про цю помилку.", "message_traceback": "⚠️ **Сталась помилка**\nПомилка повідомлень: `{0}` -> `{1}`\nПомилка: `{2}`\n\nTraceback:\n```\n{3}\n```", "no_user_application": "Не знайдено користувачів за запитом **{0}**", @@ -283,16 +283,16 @@ "rules_msg": "📢Правила можуть доповнюватись та змінюватись, залежно від потреби. У такому разі, порушення, які були вчинені до введення (змінення) правила, порушеннями вважатися не будуть. Про всі зміни в правилах, ви будете проінформовані за допомогою закріплених повідомлень. Але вони не будуть закріплені на постійній основі, тому, час від часу, перевіряйте актуальність правил у боті.\n\n🔔Якщо ви бачите, як хтось із учасників порушив правила, тегніть одного із адмінів, у відповідь на повідомлення, яке, на вашу думку, є порушенням. У дописі до тегу, вкажіть, по якому пункту ви побачили порушення. Або перешліть повідомлення до будь кого із адміністраторів у особисті повідомлення, та коротко опишіть ситуацію.\nСписок адміністраторів: @Chirkopol @Za_NerZula @Toxinushka\nЗ питань функціонування бота звертайтесь до @Profitroll2281337\n\n❗️Будь-який заборонений контент, може бути відправлений за допомогою команди /spoiler у бота - з повним описом контенту, що міститься під спойлером. За неправильний або некоректний опис, може бути видане попередження.\n\n‼️Видалені або змінені повідомлення, все ще є повідомленнями від вашого імені, які могли побачити учасники чату, і які можуть бути відстежені через адмінську панель.\n\n🔨 За порушення - ви отримаєте попередження. За наявності 3-х попереджень - мут на добу. За повторні порушення, ви одразу отримаєте покарання, без додаткових попереджень.", "rules": [ "1️⃣) \"HoloKyiv Chat\" та \"HoloUA (Hololive Ukraine) Chat\" створені виключно для українців (13+). В них можуть знаходитись тільки люди які: \n- Народились в Україні, та проживають, на данний момент, у ній.\n- Народились за межами України, але проживають у ній.\n- Народились в Україні але, на даний момент, не проживають у ній.\n\"HoloUA (Hololive Ukraine) Chat\" відкритий для усіх українців. Щоб потрапити до нього, заповніть, будь ласка, анкету, та дочекайтесь, поки її схвалять адміни.\nУ \"HoloKyiv Chat\" можна потрапити тільки особисто, якщо ви проживаєте у Київі, або є близьким другом одного із учасників чату. Із приводу додавання до чату пишіть @Chirkopol у приватні повідомлення.\n🔨 Якщо у процесі спілкування виявиться, що ви не українець, вас буде видалено із чату, до моменту, поки ви їм не станете. Без образ. Ми створюємо виключно українське ком'юніті.", - "2️⃣) Заборонено поширення NSFW-контенту з прямим або частково прихованим порнографічним змістом. На контенті \"еротичного характеру\" повинні бути закриті \"сумнівні\" ділянки тіл. \nЗаборонено поширення шок-контенту з великою наявністю крові та/або фізичних пошкоджень.", - "3️⃣) Анонімність учасників Хололайв та Холостарз.\nЗаборонено: \n- Фотографії\n- Імена\n- Місце проживання\n- Точний вік (слово \"холохеґз\" не підпадає)\n- Подробиці особистого життя\n- Пости з руммейт акаунтів чи згадка про них з конкретними даними (тобто фраза \"там на ірл каналі Каллі щось вийшло\" - можна, а \"там на *назва ірл каналу* щось вийшло\" - ні)\n- Подробиці з минулого дівчат - лише поверхнево і без конкретики (тобто \"була офісним працівником\" - ок, \"була в *компанія_нейм*\" - ні).\nВиключення - якщо дівчата самі згадували про це на архівних(!) стрімах.\n❗️Це правило не стосується тих, хто вже не знаходиться у Хололайві, або ніколи і не був його частиною. Але, прохання, відноситись до особистого життя інших вітуберів із повагою, та не перебільшувати із деанонами їх особистостей.", - "4️⃣) Заборонено флуд однотипними повідомленнями, емодзі, смайликами, стікерами, гіфками тощо. Орієнтовна кількість повідомлень, які можуть отримати попередження за це правило - 5. Кожна ситуація може розглядатись окремо, але вкладайте усі свої думки в одне повідомлення.", - "5️⃣) Заборонені відео та аудіо-повідомлення, які не несуть цілі передати почуте, або побачене. Якщо ви бажаєте розповісти про те, як пройшов ваш день, але не маєте можливості друкувати повідомлення, використовуйте магічний перетворювач войсів у текст - https://t.me/voicybot", + "2️⃣) Заборонено поширення артів, на яких зображено:\n2.1 - NSFW-контент з прямим або частково прихованим порнографічним змістом.\n2.2 - Контент \"еротичного характеру\" із неприкритими \"сумнівними\" ділянками тіл (так звані \"private parts\") або їх помітними силуетами крізь одяг.\n2.3 - Фетиш-контент, який спрямований на дуже вузьке коло шанувальників та може порушувати закон. Наприклад: копрофілія, педофілія, зоофілія.\n2.4 - Шок-контент із великою кількістю крові та/або фізичних пошкоджень.\n2.5 - Контент, який порушує будь-яке інше правило.\n❗️Якщо якійсь арт викликає у вас сумніви і ви не впевнені, що він не порушує правила, скористайтесь командою /spoiler у боті. Це точно збереже вас від зайвих проблем. Але не забувайте робити опис спойлеру!", + "3️⃣) Анонімність учасників Гололайв та Голостарз.\nЗаборонено: \n- Фотографії.\n- Імена.\n- Місце проживання.\n- Точний вік (слово \"холохеґз\" не підпадає).\n- Подробиці особистого життя, які не було розкриті на Гололайв-акаунтах.\n- Пости з руммейт-акаунтів чи згадка про них з конкретними даними. Пояснення: фраза \"там на ірл каналі Каллі щось вийшло\" - можна, а \"там на *назва ірл каналу* щось вийшло\" - ні.\n- Подробиці з минулого дівчат - лише поверхнево і без конкретики (тобто, \"була офісним працівником\" - ок, \"була в *компанія_нейм*\" - ні).\nВиключення - якщо дівчата самі згадували про це на архівних(!) стрімах.\n❗️Це правило не стосується тих, хто вже не знаходиться у Гололайві або ніколи і не був його частиною. Але, прохання, відноситись до особистого життя інших вітуберів із повагою та не перебільшувати із деанонами їх особистостей.", + "4️⃣) Заборонено флуд однотипними текстовими повідомленнями, які не несуть у собі сенсу, емоджі, смайликами, стікерами, ґіфками, великою кількістю артів тощо. Орієнтовна кількість повідомлень, за які можна отримати попередження за це правило - 5. \nЯкщо учасник буде цілеспрямовано відправляти по менше ніж 5 повідомлень, але робити це регулярно, то попередження також може бути видане.\nПояснення: \"Відправлю зараз 4 гіфки, почекаю, поки хтось напише декілька повідомлень, і знову відправлю 4 гіфки\".\n- Попередження про флуд одночасно можуть отримати декілька учасників.\nПояснення: декілька учасників чату, по черзі, відправляють по декілька (менше п'яти) стікерів, але спільними зусиллями, і їх стає дуже багато.\n❗️Кожна ситуація може і буде розглядатись окремо, але намагайтеся вкладати всі свої думки в одне повідомлення.\n❗️Якщо ви масово відправляєте контент зі сторонніх ресурсів, будь то якісь новини у великій кількості (анонси мерчу, концертів тощо) або арти, кліпи та подібне, і ви ніяк не зможете посприяти тому, щоб уся інформація була подана більш компактно, то це правило на вас не розповсюджується, але не зловживайте цим.\n‼️Це правило не стосується організованих івентів та флешмобів, затверджених адміністраторами.", + "5️⃣) Заборонені відео- та аудіо-повідомлення, які не несуть цілі передати почуте або побачене. \n❗️Якщо ви бажаєте розповісти про те, як пройшов ваш день, але не маєте можливості друкувати повідомлення, використовуйте магічний перетворювач войсів у текст - https://t.me/voicybot", "6️⃣) Заборонені образи, погрози, булінг, приниження, тролінг учасників, членів їхніх сімей, друзів та іншого кола, що є наближеними до учасника чату. Повідомлення на кшталт: \"йди на ... \" - також є образами. Ви можете отримати попередження, навіть, якщо це був ваш приятель. Воно буде зняте, якщо приятель підтвердить, що не ображений на вас.\n🔨 Якщо на прохання учасника або адміністратора, ви не зміните темп спілкування і не вибачитесь, то отримаєте попередження. \n⚒ Якщо ваша поведінка спричинить те, що учасник залишив чат, покарання може бути жорсткішим.", - "7️⃣) Заборонено провокування конфліктів та розпалювання ненависті між учасниками чату.", - "8️⃣) Заборонені прояви расизму, сексизму, гомофобії та засудження за політичні та (або) релігійні упередження. Дані теми все ще можуть бути частиною діалогу, якщо не несуть у собі прямих засуджень, образ тощо.", + "7️⃣) Правила щодо провокаційних тем у чаті:\n7.1 - У чаті немає заборони на обговорення будь-яких тем, однак, заборонені радикальні висловлювання у бік будь-якої із позицій. Якщо ви на 100% впевнені у своїй правоті і розумієте, що будуть люди, які не поділяють вашу точку зору і ви абсолютно точно не збираєтесь прислухатися до їхньої позиції, а налаштовуєтеся на заперечення будь-якого аргументу - то закрийте чат і займіться своїми справами.\n7.2 - Відносьтесь до позиції співрозмовника із повагою. Пам'ятайте, що всі ми різні і погляди у нас, аналогічно, різні.\n7.3 - Якщо ви розумієте, що обстановка в обговоренні загострюється, то запропонуйте співрозмовнику зупинитися і розійдіться, залишившись кожен при своїй думці та намагайтеся більше на проблемну тему не спілкуватися.\n7.4 - Вкидання спірної інформації, яка може призвести до конфлікту, навіть без прямої участі в ньому, може розцінюватися як провокація.\n7.5 - Навмисні образи когось чи чогось, кому чи чому може симпатизувати хтось із учасників чату, після прохання так більше не робити, розцінюватиметься як провокація.\nПриклад: образи кого-небудь із Голо-дівчат, знаючи про те, що у чаті є ті, кому вона може бути цікава і що людині не сподобаються подібні повідомлення.\n7.6 Адміністрація, на свій розсуд, може попросити згорнути тему, якщо розуміє, що вона може призвести до конфлікту.\n❗️Кожна ситуація може розглядатися адміністрацією окремо. Ми не хочемо, щоб учасники пересварилися один з одним і вирішили залишити чат. Дані правила прописані насамперед для збереження чистоти та дружньої атмосфери. Якщо ви здатні спілкуватися на заборонені теми шляхом адекватного обміну думками та інформацією, ми можемо заплющити очі на порушення. Але це залежить лише від вашого вміння стримувати свій запал і здібностей викладати думки.", + "8️⃣) Заборонені прояви расизму, сексизму, гомофобії та засудження за політичні та (або) релігійні упередження. \n❗️Дані теми все ще можуть бути обговорювані в чаті \"з нейтральної точки зору\", якщо ви при цьому не порушуєте розділ правил 7️⃣.", "9️⃣) Заборонені аватарки, нікнейми, ролі, які порушують інші правила." ], - "rules_additional": "Додаткові правила, які несуть рекомендаційний характер, та не мають явних покарань за порушення:\n1️⃣) У чаті немає заборони на російську мову. Ми поважаємо кожного українця і не бажаємо розпалювати мовні конфлікти.\n2️⃣) У чаті немає заборони на російський контент. Але, майте на увазі, що учасники, здебільшого, не будуть зацікавлені у тому, щоб обговорювати його і він може бути проігнорованим.\n3️⃣) Не зловживайте матами. Намагайтесь спілкуватись чистою мовою.\n4️⃣) Поважайте авторські права контентмейкерів. Якщо ви знаходите арт, анімацію, музику тощо, на офіційних ресурсах (pixiv, twitter, deviantart тощо), відправляйте на нього посилання.\nЯкщо хтось із учасників відправив арт із не офіційного ресурсу і ви бажаєте дізнатись його автора, відправте у відповідь повідомлення із текстом `/search` на повідомлення із артом.", + "rules_additional": "Додаткові правила, які несуть рекомендаційний характер та не мають явних покарань за порушення:\n1️⃣) У чаті немає заборони на російську мову. Ми поважаємо кожного українця і не бажаємо розпалювати мовні конфлікти.\n2️⃣) У чаті немає заборони на російський контент. Але майте на увазі, що учасники, здебільшого, не будуть зацікавлені у тому, щоб обговорювати його і він може бути проігнорованим.\n3️⃣) Не зловживайте матами. Намагайтесь спілкуватись чистою мовою.\n4️⃣) Поважайте авторські права контент-мейкерів. Якщо ви знаходите арт, анімацію, музику тощо на офіційних ресурсах (pixiv, twitter, deviantart тощо), відправляйте на нього посилання.\nЯкщо хтось із учасників відправив арт із не офіційного ресурсу і ви бажаєте дізнатись його автора, відправте у відповідь повідомлення із текстом /search на повідомлення із артом.\n5️⃣) В особливо критичних ситуаціях порушник може отримати бан або бути повністю видаленим із чату, без попереджень.\n6️⃣) Якщо з кимось із учасників у вас трапиться якесь непорозуміння і вам неприємно буде перебувати в чаті один з одним (навіть, якщо конфлікт стався з кимось із адміністраторів) - напишіть мені в особисті повідомлення @Chirkopol. Я, як засновник чату та головний адміністратор, найбільше зацікавлений у збереженні цілісності чату та розвитку нашого ком'юніті, і я зроблю все, що в моїх силах, щоб допомогти вирішити вашу ситуацію.", "commands": { "application": "Переглянути анкету користувача", "applications": "Отримати всі анкети як JSON", -- 2.39.2 From 3304339244ab8b54e516d0bd121409ae6934eb45 Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 9 Mar 2023 16:25:06 +0100 Subject: [PATCH 11/29] Changed code style to black --- api_avatars.py | 18 +- app.py | 19 +- classes/errors/geo.py | 7 +- classes/errors/holo_user.py | 24 +- classes/holo_user.py | 683 ++++++++++++++++++++++++------ classes/templates.py | 12 +- holochecker.py | 52 ++- modules/callbacks/ban.py | 18 +- modules/callbacks/nothing.py | 5 +- modules/callbacks/reapply.py | 232 ++++++++-- modules/callbacks/rules.py | 65 ++- modules/callbacks/spoiler.py | 71 +++- modules/callbacks/sponsorship.py | 153 +++++-- modules/callbacks/sub.py | 172 ++++++-- modules/callbacks/sus.py | 91 +++- modules/commands/application.py | 83 +++- modules/commands/applications.py | 25 +- modules/commands/cancel.py | 30 +- modules/commands/identify.py | 83 +++- modules/commands/issue.py | 25 +- modules/commands/label.py | 35 +- modules/commands/message.py | 66 ++- modules/commands/nearby.py | 105 ++++- modules/commands/reapply.py | 178 +++++--- modules/commands/reboot.py | 26 +- modules/commands/resetcommands.py | 86 +++- modules/commands/rules.py | 37 +- modules/commands/spoiler.py | 43 +- modules/commands/sponsorship.py | 35 +- modules/commands/start.py | 67 ++- modules/commands/warn.py | 39 +- modules/commands/warnings.py | 53 ++- modules/custom_filters.py | 41 +- modules/database.py | 25 +- modules/handlers/confirmation.py | 237 ++++++++--- modules/handlers/contact.py | 75 +++- modules/handlers/everything.py | 311 +++++++++++--- modules/handlers/group_join.py | 145 +++++-- modules/handlers/voice.py | 10 +- modules/handlers/welcome.py | 50 ++- modules/inline.py | 263 +++++++++--- modules/logging.py | 37 +- modules/scheduled.py | 259 ++++++++--- modules/utils.py | 88 ++-- 44 files changed, 3243 insertions(+), 936 deletions(-) diff --git a/api_avatars.py b/api_avatars.py index 0ec1916..85fcf62 100644 --- a/api_avatars.py +++ b/api_avatars.py @@ -8,21 +8,33 @@ makedirs(f'{configGet("cache", "locations")}{sep}avatars', exist_ok=True) app = FastAPI(title="HoloUA Avatars API", docs_url=None, redoc_url=None, version="1.0") + @app.get("/check", response_class=JSONResponse, include_in_schema=False) @app.head("/check", response_class=JSONResponse, include_in_schema=False) async def check(): return JSONResponse({"detail": "I'm alright, thank you"}) + @app.get("/", response_class=FileResponse, include_in_schema=False) async def avatar_get(avatar_id: str): if path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}'): - return FileResponse(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}', media_type="image/jpg") + return FileResponse( + f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}', + media_type="image/jpg", + ) else: raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="File not found") + @app.head("/", response_class=Response, include_in_schema=False) async def avatar_head(avatar_id: str): if path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}'): - return Response(headers={"Content-Length": path.getsize(f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}')}) + return Response( + headers={ + "Content-Length": path.getsize( + f'{configGet("cache", "locations")}{sep}avatars{sep}{avatar_id}' + ) + } + ) else: - raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="File not found") \ No newline at end of file + raise HTTPException(status_code=HTTP_404_NOT_FOUND, detail="File not found") diff --git a/app.py b/app.py index 59f33a3..b30c147 100644 --- a/app.py +++ b/app.py @@ -5,10 +5,15 @@ from modules.utils import configGet, jsonLoad from pyrogram.client import Client from pyrogram.errors import bad_request_400 -app = Client("holochecker", bot_token=configGet("bot_token", "bot"), api_id=configGet("api_id", "bot"), api_hash=configGet("api_hash", "bot")) +app = Client( + "holochecker", + bot_token=configGet("bot_token", "bot"), + api_id=configGet("api_id", "bot"), + api_hash=configGet("api_hash", "bot"), +) + async def isAnAdmin(admin_id): - # Check if user is mentioned in config if (admin_id == configGet("owner")) or (admin_id in configGet("admins")): return True @@ -19,14 +24,16 @@ async def isAnAdmin(admin_id): return True if admin_id in jsonLoad(f"cache{sep}admins") else False except (FileNotFoundError, JSONDecodeError): pass - + # Check if user is in admin group try: async for member in app.get_chat_members(configGet("admin", "groups")): if member.user.id == admin_id: return True except bad_request_400.ChannelInvalid: - logWrite(f"Could not get users in admin group to answer isAnAdmin(). Bot is likely not in the group.") + logWrite( + f"Could not get users in admin group to answer isAnAdmin(). Bot is likely not in the group." + ) return False - - return False \ No newline at end of file + + return False diff --git a/classes/errors/geo.py b/classes/errors/geo.py index b4b8b02..e8c3a39 100644 --- a/classes/errors/geo.py +++ b/classes/errors/geo.py @@ -1,5 +1,8 @@ class PlaceNotFoundError(Exception): - """Query provided did not lead to any city or populated area""" + """Query provided did not lead to any city or populated area""" + def __init__(self, query): self.query = query - super().__init__(f"Could not find any place on geonames.org of feature classes A and P by query '{self.query}'") \ No newline at end of file + super().__init__( + f"Could not find any place on geonames.org of feature classes A and P by query '{self.query}'" + ) diff --git a/classes/errors/holo_user.py b/classes/errors/holo_user.py index a4fbb6b..c3f9078 100644 --- a/classes/errors/holo_user.py +++ b/classes/errors/holo_user.py @@ -1,24 +1,38 @@ """Exceptions that are meant to be used by HoloUser class and other modules that handle those exceptions""" + class UserNotFoundError(Exception): """HoloUser could not find user with such an ID in database""" + def __init__(self, user, user_id): self.user = user self.user_id = user_id - super().__init__(f"User of type {type(self.user)} with id {self.user_id} was not found") + super().__init__( + f"User of type {type(self.user)} with id {self.user_id} was not found" + ) + class UserInvalidError(Exception): - """Provided to HoloUser object is not supported""" + """Provided to HoloUser object is not supported""" + def __init__(self, user): self.user = user - super().__init__(f"Could not find HoloUser by using {type(self.user)} as an input type") + super().__init__( + f"Could not find HoloUser by using {type(self.user)} as an input type" + ) + class LabelTooLongError(Exception): def __init__(self, label: str) -> None: self.label = label - super().__init__(f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)") + super().__init__( + f"Could not set label to '{label}' because it is {len(label)} characters long (16 is maximum)" + ) + class LabelSettingError(Exception): def __init__(self, exp: Exception, trace: str) -> None: - super().__init__(f"❌ **Could not set label**\n\nException: `{exp}`\n\n**Traceback:**\n```\n{trace}\n```") \ No newline at end of file + super().__init__( + f"❌ **Could not set label**\n\nException: `{exp}`\n\n**Traceback:**\n```\n{trace}\n```" + ) diff --git a/classes/holo_user.py b/classes/holo_user.py index 9def05e..99c9515 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -4,21 +4,47 @@ from ftfy import fix_text from traceback import format_exc from app import app, isAnAdmin from typing import Any, List, Literal, Union -from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice, ForceReply, ReplyKeyboardMarkup +from pyrogram.types import ( + User, + ChatMember, + ChatPrivileges, + Chat, + Message, + Photo, + Video, + Document, + Animation, + Voice, + ForceReply, + ReplyKeyboardMarkup, +) from pyrogram.errors import bad_request_400 from dateutil.relativedelta import relativedelta from classes.errors.geo import PlaceNotFoundError -from classes.errors.holo_user import UserInvalidError, UserNotFoundError, LabelTooLongError, LabelSettingError +from classes.errors.holo_user import ( + UserInvalidError, + UserNotFoundError, + LabelTooLongError, + LabelSettingError, +) from classes.templates import DefaultApplicationTemp, DefaultSponsorshipTemp -from modules.database import col_tmp, col_users, col_applications, col_sponsorships, col_messages, col_spoilers +from modules.database import ( + col_tmp, + col_users, + col_applications, + col_sponsorships, + col_messages, + col_spoilers, +) from modules.logging import logWrite from modules.utils import configGet, find_location, locale, should_quote -class HoloUser(): + +class HoloUser: """This object represents a user of HoloChecker bot. It is primarily used to interact with a database in a more python-friendly way, as well as provide better programming experience in case of adding new features, etc. - """ + """ def __init__(self, user: Union[User, List[User], ChatMember, int]) -> None: """A user of Holo bot. Used to simplify DB interaction. @@ -29,7 +55,7 @@ class HoloUser(): ### Raises: * UserInvalidError: Provided to `HoloUser` object is not supported * UserNotFoundError: `HoloUser` could not find user with such an ID in database - """ + """ # Determine input object class and extract id if isinstance(user, list) and len(user) != 0: @@ -67,34 +93,52 @@ class HoloUser(): self.username = holo_user["tg_username"] if isinstance(user, User): - - if (self.name != user.first_name) and hasattr(user, "first_name") and (user.first_name is not None): + if ( + (self.name != user.first_name) + and hasattr(user, "first_name") + and (user.first_name is not None) + ): self.set("name", user.first_name, db_key="tg_name") - if (self.phone != user.phone_number) and hasattr(user, "phone") and (user.phone_number is not None): + if ( + (self.phone != user.phone_number) + and hasattr(user, "phone") + and (user.phone_number is not None) + ): self.set("phone", user.phone_number, db_key="tg_phone") - if (self.locale != user.language_code) and hasattr(user, "locale") and (user.language_code is not None): + if ( + (self.locale != user.language_code) + and hasattr(user, "locale") + and (user.language_code is not None) + ): self.set("locale", user.language_code, db_key="tg_locale") - if (self.username != user.username) and hasattr(user, "username") and (user.username is not None): + if ( + (self.username != user.username) + and hasattr(user, "username") + and (user.username is not None) + ): self.set("username", user.username, db_key="tg_username") - + def set(self, key: str, value: Any, db_key: Union[str, None] = None) -> None: """Set attribute data and save it into database ### Args: * `key` (`str`): Attribute to be changed * `value` (`Any`): Value to set - """ + """ if not hasattr(self, key): raise AttributeError() setattr(self, key, value) db_key = key if db_key is None else db_key - col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { db_key: value } }, upsert=True) + col_users.update_one( + filter={"_id": self.db_id}, update={"$set": {db_key: value}}, upsert=True + ) logWrite(f"Set attribute {key} of user {self.id} to {value}") - async def message(self, + async def message( + self, context: Message, origin: Union[Message, None] = None, text: Union[str, None] = None, @@ -105,7 +149,7 @@ class HoloUser(): animation: Union[str, Animation, None] = None, voice: Union[str, Voice, None] = None, adm_origin: bool = False, - adm_context: bool = False + adm_context: bool = False, ) -> None: """Send a message to user @@ -121,7 +165,7 @@ class HoloUser(): * voice (`Union[str, Voice, None]`, *optional*): Voice as a voice object or file_id as a string. Defaults to None. * adm_origin (`bool`, *optional*): Whether origin sender is an admin. Defaults to False. * adm_context (`bool`, *optional*): Whether context sender is an admin. Defaults to False. - """ + """ if text is not None: text = fix_text(text) @@ -130,18 +174,30 @@ class HoloUser(): # Check if any text available and log message sending if text is not None: - logWrite(f"{context.from_user.id} sent message '{text}' to {self.id} (source message: {context.id})") + logWrite( + f"{context.from_user.id} sent message '{text}' to {self.id} (source message: {context.id})" + ) elif caption is not None: - logWrite(f"{context.from_user.id} sent message '{caption}' to {self.id} (source message: {context.id})") + logWrite( + f"{context.from_user.id} sent message '{caption}' to {self.id} (source message: {context.id})" + ) else: - logWrite(f"{context.from_user.id} sent message to {self.id} (source message: {context.id})") + logWrite( + f"{context.from_user.id} sent message to {self.id} (source message: {context.id})" + ) # Add notices for admin or user if text is not None: if adm_context: text += locale("message_reply_notice", "message") elif adm_origin: - text = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + text + locale("message_reply_notice", "message") + text = ( + locale("message_from", "message").format( + context.from_user.first_name, context.from_user.id + ) + + text + + locale("message_reply_notice", "message") + ) else: text = locale("message_reply_notice", "message") @@ -149,77 +205,118 @@ class HoloUser(): if adm_context: caption += locale("message_reply_notice", "message") elif adm_origin: - caption = locale("message_from", "message").format(context.from_user.first_name, context.from_user.id) + caption + locale("message_reply_notice", "message") + caption = ( + locale("message_from", "message").format( + context.from_user.first_name, context.from_user.id + ) + + caption + + locale("message_reply_notice", "message") + ) else: caption = locale("message_reply_notice", "message") # Try sending the message try: - # Check if origin message exists # This check decides whether we send_ a message or reply_ to one if origin is not None: - if photo is not None: if isinstance(photo, Photo): photo = photo.file_id - new_message = await origin.reply_cached_media(photo, caption=caption, quote=True) + new_message = await origin.reply_cached_media( + photo, caption=caption, quote=True + ) elif video is not None: if isinstance(video, Video): video = video.file_id - new_message = await origin.reply_cached_media(video, caption=caption, quote=True) + new_message = await origin.reply_cached_media( + video, caption=caption, quote=True + ) elif file is not None: if isinstance(file, Document): file = file.file_id - new_message = await origin.reply_cached_media(file, caption=caption, quote=True) + new_message = await origin.reply_cached_media( + file, caption=caption, quote=True + ) elif animation is not None: if isinstance(animation, Animation): animation = animation.file_id - new_message = await origin.reply_cached_media(animation, caption=caption, quote=True) + new_message = await origin.reply_cached_media( + animation, caption=caption, quote=True + ) elif voice is not None: if isinstance(voice, Voice): voice = voice.file_id - new_message = await origin.reply_voice(voice, caption=caption, quote=True) + new_message = await origin.reply_voice( + voice, caption=caption, quote=True + ) else: new_message = await origin.reply_text(text, quote=True) else: - if photo is not None: if isinstance(photo, Photo): photo = photo.file_id - new_message = await app.send_cached_media(self.id, photo, caption=caption) + new_message = await app.send_cached_media( + self.id, photo, caption=caption + ) elif video is not None: if isinstance(video, Video): video = video.file_id - new_message = await app.send_cached_media(self.id, video, caption=caption) + new_message = await app.send_cached_media( + self.id, video, caption=caption + ) elif file is not None: if isinstance(file, Document): file = file.file_id - new_message = await app.send_cached_media(self.id, file, caption=caption) + new_message = await app.send_cached_media( + self.id, file, caption=caption + ) elif animation is not None: if isinstance(animation, Animation): animation = animation.file_id - new_message = await app.send_cached_media(self.id, animation, caption=caption) + new_message = await app.send_cached_media( + self.id, animation, caption=caption + ) elif voice is not None: if isinstance(voice, Voice): voice = voice.file_id - new_message = await app.send_cached_media(self.id, voice, caption=caption) + new_message = await app.send_cached_media( + self.id, voice, caption=caption + ) else: new_message = await app.send_message(self.id, text) # Acknowledge sending a message and save entry into DB - await context.reply_text(locale("message_sent", "message"), quote=should_quote(context)) - col_messages.insert_one({"origin": {"chat": context.chat.id, "id": context.id}, "destination": {"chat": new_message.chat.id, "id": new_message.id}}) + await context.reply_text( + locale("message_sent", "message"), quote=should_quote(context) + ) + col_messages.insert_one( + { + "origin": {"chat": context.chat.id, "id": context.id}, + "destination": {"chat": new_message.chat.id, "id": new_message.id}, + } + ) # Report to admin and to sender about message sending failure except Exception as exp: - logWrite(f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{format_exc()}") + logWrite( + f"Exception {exp} happened as {context.from_user.id} tried to send message to {self.id}. Traceback:\n{format_exc()}" + ) try: - await app.send_message(configGet("owner"), locale("message_traceback", "message").format(context.from_user.id, self.id, exp, format_exc())) + await app.send_message( + configGet("owner"), + locale("message_traceback", "message").format( + context.from_user.id, self.id, exp, format_exc() + ), + ) except bad_request_400.PeerIdInvalid: - logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!") - await context.reply_text(locale("message_error", "message"), quote=should_quote(context)) + logWrite( + f"Could not notify admin about failure when sending message! Admin has never interacted with bot!" + ) + await context.reply_text( + locale("message_error", "message"), quote=should_quote(context) + ) async def label_set(self, chat: Chat, label: str) -> None: """Set label in destination group @@ -227,15 +324,23 @@ class HoloUser(): ### Args: * chat (`Chat`): Telegram chat * label (`str`): Label you want to set - """ + """ if len(label) > 16: raise LabelTooLongError(label) self.label = label try: - await app.promote_chat_member(configGet("users", "groups"), self.id, privileges=ChatPrivileges(can_pin_messages=True, can_manage_video_chats=True)) + await app.promote_chat_member( + configGet("users", "groups"), + self.id, + privileges=ChatPrivileges( + can_pin_messages=True, can_manage_video_chats=True + ), + ) if not await isAnAdmin(self.id): await sleep(0.5) - await app.set_administrator_title(configGet("users", "groups"), self.id, label) + await app.set_administrator_title( + configGet("users", "groups"), self.id, label + ) self.set("label", label) except Exception as exp: logWrite(f"Could not set {self.id}'s title to '{self.label}' due to {exp}") @@ -246,23 +351,29 @@ class HoloUser(): ### Args: * chat (`Chat`): Telegram chat - """ + """ self.label = "" self.set("label", "") await app.set_administrator_title(configGet("users", "groups"), self.id, "") if not await isAnAdmin(self.id): - await app.promote_chat_member(configGet("users", "groups"), self.id, privileges=ChatPrivileges( - can_manage_chat=False, - can_pin_messages=False, - can_manage_video_chats=False - )) + await app.promote_chat_member( + configGet("users", "groups"), + self.id, + privileges=ChatPrivileges( + can_manage_chat=False, + can_pin_messages=False, + can_manage_video_chats=False, + ), + ) - def application_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: + def application_state( + self, + ) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: """Check the current state of application in tmp collection ### Returns: * `tuple[Literal["none", "fill", "approved", "rejected"], bool]`: First element is an enum of a state and the second one is whether application is complete. - """ + """ tmp_application = col_tmp.find_one({"user": self.id, "type": "application"}) if tmp_application is None: return "none", False @@ -274,16 +385,22 @@ class HoloUser(): ### Returns: * `bool`: `True` if yes and `False` if no - """ - return True if col_applications.find_one({"user": self.id}) is not None else False + """ + return ( + True if col_applications.find_one({"user": self.id}) is not None else False + ) def application_restart(self, reapply: bool = False) -> None: - """Reset application of a user in tmp collection and replace it with an empty one - """ + """Reset application of a user in tmp collection and replace it with an empty one""" if col_tmp.find_one({"user": self.id, "type": "application"}) is None: - col_tmp.insert_one(document=DefaultApplicationTemp(self.id, reapply=reapply).dict) + col_tmp.insert_one( + document=DefaultApplicationTemp(self.id, reapply=reapply).dict + ) else: - col_tmp.find_one_and_replace({"user": self.id, "type": "application"}, DefaultApplicationTemp(self.id, reapply=reapply).dict) + col_tmp.find_one_and_replace( + {"user": self.id, "type": "application"}, + DefaultApplicationTemp(self.id, reapply=reapply).dict, + ) async def application_next(self, query: str, msg: Message) -> None: """Move on filling application of user @@ -291,7 +408,7 @@ class HoloUser(): ### Args: * query (`str`): Some kind of input * msg (`Message`): Message that should receive replies - """ + """ # if col_tmp.find_one({"user": self.id, "type": "application"}) is None: @@ -311,102 +428,294 @@ class HoloUser(): return stage = progress["stage"] - + # if self.sponsorship_state()[0] == "fill": # await msg.reply_text(locale("finish_sponsorship", "message"), quote=should_quote(msg)) # return if progress["state"] == "fill" and progress["sent"] is False: - if msg.text is not None: msg.text = fix_text(str(msg.text)) if stage == 2: - try: input_dt = datetime.strptime(query, "%d.%m.%Y") except ValueError: - logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format") - await msg.reply_text(locale(f"question2_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format" + ) + await msg.reply_text( + locale(f"question2_invalid", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return - if (datetime.now() <= input_dt) or ((datetime.now() - input_dt).days) > ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_maximum"))).days): - logWrite(f"User {msg.from_user.id} failed stage {stage} due to joking") - await msg.reply_text(locale("question2_joke", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply", locale=self.locale)))) + if (datetime.now() <= input_dt) or ( + (datetime.now() - input_dt).days + ) > ( + ( + datetime.now() + - datetime.now().replace( + year=datetime.now().year - configGet("age_maximum") + ) + ).days + ): + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to joking" + ) + await msg.reply_text( + locale("question2_joke", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale("question2", "force_reply", locale=self.locale) + ) + ), + ) return - elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days): - logWrite(f"User {msg.from_user.id} failed stage {stage} due to being underage") - await msg.reply_text(locale("question2_underage", "message", locale=self.locale).format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply", locale=self.locale)))) + elif ((datetime.now() - input_dt).days) < ( + ( + datetime.now() + - datetime.now().replace( + year=datetime.now().year - configGet("age_allowed") + ) + ).days + ): + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to being underage" + ) + await msg.reply_text( + locale( + "question2_underage", "message", locale=self.locale + ).format(str(configGet("age_allowed"))), + reply_markup=ForceReply( + placeholder=str( + locale("question2", "force_reply", locale=self.locale) + ) + ), + ) return else: progress["application"][str(stage)] = input_dt - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "application"}}, + { + "$set": { + "application": progress["application"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale(f"question{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage+1}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) elif stage == 3: try: progress["application"][str(stage)] = find_location(query) - if ("lat" in progress["application"][str(stage)] and "lng" in progress["application"][str(stage)]): - progress["application"][str(stage)]["location"] = [float(progress["application"][str(stage)]["lng"]), float(progress["application"][str(stage)]["lat"])] + if ( + "lat" in progress["application"][str(stage)] + and "lng" in progress["application"][str(stage)] + ): + progress["application"][str(stage)]["location"] = [ + float(progress["application"][str(stage)]["lng"]), + float(progress["application"][str(stage)]["lat"]), + ] del progress["application"][str(stage)]["lat"] del progress["application"][str(stage)]["lng"] - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale("question3_found", "message", locale=self.locale).format(progress["application"][str(stage)]["name"], progress["application"][str(stage)]["adminName1"])) - await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "application"}}, + { + "$set": { + "application": progress["application"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale("question3_found", "message", locale=self.locale).format( + progress["application"][str(stage)]["name"], + progress["application"][str(stage)]["adminName1"], + ) + ) + await msg.reply_text( + locale(f"question{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage+1}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) except PlaceNotFoundError: - await msg.reply_text(locale("question3_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) + await msg.reply_text( + locale("question3_invalid", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return except Exception as exp: - await msg.reply_text(locale("question3_error", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) + await msg.reply_text( + locale("question3_error", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) try: - await app.send_message(configGet("owner"), locale("question3_traceback", "message", locale=self.locale).format(query, exp, format_exc())) + await app.send_message( + configGet("owner"), + locale( + "question3_traceback", "message", locale=self.locale + ).format(query, exp, format_exc()), + ) except bad_request_400.PeerIdInvalid: - logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!") + logWrite( + f"Could not notify admin about failure when sending message! Admin has never interacted with bot!" + ) return elif stage == 10: if len(query) > 1024: - await msg.reply_text(locale("question10_too_long", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) + await msg.reply_text( + locale("question10_too_long", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return progress["application"][str(stage)] = query - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "complete": True}}) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "application"}}, + { + "$set": { + "application": progress["application"], + "complete": True, + } + }, + ) application_content = [] i = 1 for question in progress["application"]: if i == 2: - age = relativedelta(datetime.now(), progress['application']['2']) - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta( + datetime.now(), progress["application"]["2"] + ) + application_content.append( + f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if progress['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})") + if progress["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})" + ) else: - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})") + application_content.append( + f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application'][question]}") + application_content.append( + f"{locale('question'+str(i), 'message', 'question_titles', locale=self.locale)} {progress['application'][question]}" + ) i += 1 - await msg.reply_text(locale("confirm", "message", locale=self.locale).format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) + await msg.reply_text( + locale("confirm", "message", locale=self.locale).format( + "\n".join(application_content) + ), + reply_markup=ReplyKeyboardMarkup( + locale("confirm", "keyboard", locale=self.locale), + resize_keyboard=True, + ), + ) else: if len(query) > 256: - await msg.reply_text(locale("question_too_long", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply", locale=self.locale)))) + await msg.reply_text( + locale("question_too_long", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return progress["application"][str(stage)] = query - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale(f"question{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "application"}}, + { + "$set": { + "application": progress["application"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale(f"question{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"question{stage+1}", "force_reply", locale=self.locale + ) + ) + ), + ) logWrite(f"User {self.id} completed stage {stage} of application") else: return - def sponsorship_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: + def sponsorship_state( + self, + ) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: """Check the current state of sponsorship in tmp collection ### Returns: * `tuple[Literal["none", "fill", "approved", "rejected"], bool]`: First element is an enum of a state and the second one is whether sponsorship application is complete. - """ + """ tmp_sponsorship = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) if tmp_sponsorship is None: return "none", False @@ -418,30 +727,37 @@ class HoloUser(): ### Returns: * `bool`: `True` if yes and `False` if no - """ - return True if col_sponsorships.find_one({"user": self.id, "expires": {"$gt": datetime.now()}}) is not None else False + """ + return ( + True + if col_sponsorships.find_one( + {"user": self.id, "expires": {"$gt": datetime.now()}} + ) + is not None + else False + ) def sponsorship_restart(self) -> None: - """Reset sponsorship of a user in tmp collection and replace it with an empty one - """ + """Reset sponsorship of a user in tmp collection and replace it with an empty one""" if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is None: col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict) else: col_tmp.delete_one({"user": self.id, "type": "sponsorship"}) col_tmp.insert_one(document=DefaultSponsorshipTemp(self.id).dict) - async def sponsorship_next(self, query: str, msg: Message, photo: Union[Photo, None] = None) -> None: + async def sponsorship_next( + self, query: str, msg: Message, photo: Union[Photo, None] = None + ) -> None: """Move on filling sponsorship of user ### Args: * query (`str`): Some kind of input * msg (`Message`): Message that should receive replies - """ + """ progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) if progress is not None: - stage = progress["stage"] if msg.text is not None: @@ -450,58 +766,171 @@ class HoloUser(): msg.caption = fix_text(msg.caption) if progress["state"] == "fill" and progress["sent"] is False: - if stage == 1: - if len(query) > 240: - logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format") - await msg.reply_text(locale(f"sponsor1_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage}", "force_reply", locale=self.locale)))) + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format" + ) + await msg.reply_text( + locale(f"sponsor1_invalid", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"sponsor{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return progress["sponsorship"]["streamer"] = query - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, + { + "$set": { + "sponsorship": progress["sponsorship"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale(f"sponsor{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"sponsor{stage+1}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) elif stage == 2: - try: input_dt = datetime.strptime(query, "%d.%m.%Y") except ValueError: - logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format") - await msg.reply_text(locale(f"sponsor2_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage}", "force_reply", locale=self.locale)))) + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format" + ) + await msg.reply_text( + locale(f"sponsor2_invalid", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"sponsor{stage}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) return if datetime.now() >= input_dt: - logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending date in the past") - await msg.reply_text(locale("sponsor2_past", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale("sponsor2", "force_reply", locale=self.locale)))) + logWrite( + f"User {msg.from_user.id} failed stage {stage} due to sending date in the past" + ) + await msg.reply_text( + locale("sponsor2_past", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + "sponsor2", "force_reply", locale=self.locale + ) + ) + ), + ) return else: progress["sponsorship"]["expires"] = input_dt - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, + { + "$set": { + "sponsorship": progress["sponsorship"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale(f"sponsor{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"sponsor{stage+1}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) elif stage == 3: - if photo is not None: progress["sponsorship"]["proof"] = photo.file_id - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "stage": progress["stage"]+1}}) - await msg.reply_text(locale(f"sponsor{stage+1}", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor{stage+1}", "force_reply", locale=self.locale)))) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, + { + "$set": { + "sponsorship": progress["sponsorship"], + "stage": progress["stage"] + 1, + } + }, + ) + await msg.reply_text( + locale(f"sponsor{stage+1}", "message", locale=self.locale), + reply_markup=ForceReply( + placeholder=str( + locale( + f"sponsor{stage+1}", + "force_reply", + locale=self.locale, + ) + ) + ), + ) elif stage == 4: if len(query) > 16: - await msg.reply_text(locale("label_too_long", "message"), reply_markup=ForceReply(placeholder=str(locale("sponsor4", "force_reply", locale=self.locale)))) + await msg.reply_text( + locale("label_too_long", "message"), + reply_markup=ForceReply( + placeholder=str( + locale( + "sponsor4", "force_reply", locale=self.locale + ) + ) + ), + ) return progress["sponsorship"]["label"] = query - col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}}) + col_tmp.update_one( + {"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, + { + "$set": { + "sponsorship": progress["sponsorship"], + "complete": True, + } + }, + ) await msg.reply_cached_media( progress["sponsorship"]["proof"], - caption=locale("sponsor_confirm", "message", locale=self.locale).format( + caption=locale( + "sponsor_confirm", "message", locale=self.locale + ).format( progress["sponsorship"]["streamer"], progress["sponsorship"]["expires"].strftime("%d.%m.%Y"), - progress["sponsorship"]["label"] + progress["sponsorship"]["label"], ), - reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) + reply_markup=ReplyKeyboardMarkup( + locale("confirm", "keyboard", locale=self.locale), + resize_keyboard=True, + ), + ) else: return @@ -516,5 +945,9 @@ class HoloUser(): ### Returns: * `bool`: `True` if any not finished spoilers available and `False` if none. - """ - return False if col_spoilers.find_one({"user": self.id, "completed": False}) is None else True \ No newline at end of file + """ + return ( + False + if col_spoilers.find_one({"user": self.id, "completed": False}) is None + else True + ) diff --git a/classes/templates.py b/classes/templates.py index 08a848b..85b7321 100644 --- a/classes/templates.py +++ b/classes/templates.py @@ -2,6 +2,7 @@ from datetime import datetime + class DefaultApplicationTemp(dict): def __init__(self, user: int, reapply: bool = False): super().__init__({}) @@ -23,10 +24,11 @@ class DefaultApplicationTemp(dict): "7": None, "8": None, "9": None, - "10": None - } + "10": None, + }, } + class DefaultSponsorshipTemp(dict): def __init__(self, user: int): super().__init__({}) @@ -41,6 +43,6 @@ class DefaultSponsorshipTemp(dict): "streamer": None, "expires": datetime.fromtimestamp(0), "proof": None, - "label": "" - } - } \ No newline at end of file + "label": "", + }, + } diff --git a/holochecker.py b/holochecker.py index 50d434d..c7b0ad0 100644 --- a/holochecker.py +++ b/holochecker.py @@ -48,7 +48,6 @@ from modules.handlers.everything import * from modules.scheduled import * if __name__ == "__main__": - logWrite(f"Starting up with pid {pid}") # Yes, it should be in some kind of async main() function but I don't give a shit. @@ -57,17 +56,43 @@ if __name__ == "__main__": try: if path.exists(path.join(configGet("cache", "locations"), "shutdown_time")): - downtime = relativedelta(datetime.now(), datetime.fromtimestamp(jsonLoad(path.join(configGet("cache", "locations"), "shutdown_time"))["timestamp"])) + downtime = relativedelta( + datetime.now(), + datetime.fromtimestamp( + jsonLoad( + path.join(configGet("cache", "locations"), "shutdown_time") + )["timestamp"] + ), + ) if downtime.days >= 1: - app.send_message(configGet("owner"), locale("startup_downtime_days", "message").format(pid, downtime.days)) + app.send_message( + configGet("owner"), + locale("startup_downtime_days", "message").format( + pid, downtime.days + ), + ) elif downtime.hours >= 1: - app.send_message(configGet("owner"), locale("startup_downtime_hours", "message").format(pid, downtime.hours)) + app.send_message( + configGet("owner"), + locale("startup_downtime_hours", "message").format( + pid, downtime.hours + ), + ) else: - app.send_message(configGet("owner"), locale("startup_downtime_minutes", "message").format(pid, downtime.minutes)) + app.send_message( + configGet("owner"), + locale("startup_downtime_minutes", "message").format( + pid, downtime.minutes + ), + ) else: - app.send_message(configGet("owner"), locale("startup", "message").format(pid)) + app.send_message( + configGet("owner"), locale("startup", "message").format(pid) + ) except bad_request_400.PeerIdInvalid: - logWrite(f"Could not send startup message to bot owner. Perhaps user has not started the bot yet.") + logWrite( + f"Could not send startup message to bot owner. Perhaps user has not started the bot yet." + ) scheduler.start() @@ -76,11 +101,16 @@ if __name__ == "__main__": try: app.send_message(configGet("owner"), locale("shutdown", "message").format(pid)) except bad_request_400.PeerIdInvalid: - logWrite(f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet.") + logWrite( + f"Could not send shutdown message to bot owner. Perhaps user has not started the bot yet." + ) app.stop() makedirs(configGet("cache", "locations"), exist_ok=True) - jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time")) - - killProc(pid) \ No newline at end of file + jsonSave( + {"timestamp": time()}, + path.join(configGet("cache", "locations"), "shutdown_time"), + ) + + killProc(pid) diff --git a/modules/callbacks/ban.py b/modules/callbacks/ban.py index b34ad76..a96602a 100644 --- a/modules/callbacks/ban.py +++ b/modules/callbacks/ban.py @@ -6,17 +6,25 @@ from modules.utils import locale from modules.database import col_bans from modules.logging import logWrite + @app.on_callback_query(filters.regex("ban_[\s\S]*")) async def callback_query_reject(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") if not await isAnAdmin(int(fullclb[1])): - col_bans.insert_one( {"user": int(fullclb[1])} ) + col_bans.insert_one({"user": int(fullclb[1])}) - edited_markup = [[InlineKeyboardButton(text=str(locale("banned", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("banned", "button")), callback_data="nothing" + ) + ] + ] - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) await clb.answer(text=locale("sub_banned", "callback", locale=clb.from_user)) logWrite(f"User {fullclb[1]} has been banned by {clb.from_user.id}") @@ -24,4 +32,4 @@ async def callback_query_reject(app: Client, clb: CallbackQuery): try: await app.send_message(int(fullclb[1]), locale("you_are_banned", "message")) except Exception as exp: - logWrite(f"Could send ban message to {fullclb[1]} due to {exp}") \ No newline at end of file + logWrite(f"Could send ban message to {fullclb[1]} due to {exp}") diff --git a/modules/callbacks/nothing.py b/modules/callbacks/nothing.py index 538ed27..1550f55 100644 --- a/modules/callbacks/nothing.py +++ b/modules/callbacks/nothing.py @@ -4,8 +4,11 @@ from pyrogram.types import CallbackQuery from pyrogram.client import Client from modules.utils import locale + # Callback empty =============================================================================================================== @app.on_callback_query(filters.regex("nothing")) async def callback_query_nothing(app: Client, clb: CallbackQuery): await clb.answer(text=locale("nothing", "callback", locale=clb.from_user)) -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index 390e2ba..82798f5 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -1,6 +1,11 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove, CallbackQuery +from pyrogram.types import ( + InlineKeyboardMarkup, + InlineKeyboardButton, + ReplyKeyboardRemove, + CallbackQuery, +) from pyrogram.client import Client from pyrogram import filters from classes.holo_user import HoloUser @@ -9,91 +14,194 @@ from modules.handlers.confirmation import confirm_yes from modules.handlers.welcome import welcome_pass from modules.database import col_tmp, col_applications + # Callbacks reapply ============================================================================================================ @app.on_callback_query(filters.regex("reapply_yes_[\s\S]*")) async def callback_reapply_query_accept(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - logWrite(f"User {holo_user.id} got their reapplication approved by {clb.from_user.id}") + await app.send_message( + configGet("admin", "groups"), + locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), + disable_notification=True, + ) + logWrite( + f"User {holo_user.id} got their reapplication approved by {clb.from_user.id}" + ) - await app.send_message(holo_user.id, locale("approved_joined", "message", locale=holo_user)) + await app.send_message( + holo_user.id, locale("approved_joined", "message", locale=holo_user) + ) applications = col_applications.find({"user": holo_user.id}) if len(list(applications)) > 1: col_applications.delete_many({"user": holo_user.id}) - col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]}) + col_applications.insert_one( + { + "user": holo_user.id, + "date": datetime.now(), + "admin": clb.from_user.id, + "application": col_tmp.find_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}} + )["application"], + } + ) elif applications == 1: - col_applications.find_one_and_replace({"user": holo_user.id}, {"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]}) + col_applications.find_one_and_replace( + {"user": holo_user.id}, + { + "user": holo_user.id, + "date": datetime.now(), + "admin": clb.from_user.id, + "application": col_tmp.find_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}} + )["application"], + }, + ) else: - col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]}) - col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"state": "approved", "sent": False}}) + col_applications.insert_one( + { + "user": holo_user.id, + "date": datetime.now(), + "admin": clb.from_user.id, + "application": col_tmp.find_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}} + )["application"], + } + ) + col_tmp.update_one( + {"user": holo_user.id, "type": "application"}, + {"$set": {"state": "approved", "sent": False}}, + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("accepted", "button")), callback_data="nothing" + ) + ] + ] - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sub_accepted", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sub_accepted", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) need_link = True async for member in app.get_chat_members(configGet("users", "groups")): if member.user.id == holo_user.id: need_link = False - - if need_link: - link = await app.create_chat_invite_link(configGet("users", "groups"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1)) - await app.send_message(holo_user.id, locale("read_rules", "message", locale=holo_user)) + if need_link: + link = await app.create_chat_invite_link( + configGet("users", "groups"), + name=f"Invite for {holo_user.id}", + member_limit=1, + ) # , expire_date=datetime.now()+timedelta(days=1)) + + await app.send_message( + holo_user.id, locale("read_rules", "message", locale=holo_user) + ) for rule_msg in locale("rules", locale=holo_user): await app.send_message(holo_user.id, rule_msg) - await app.send_message(holo_user.id, locale("approved", "message"), reply_markup=InlineKeyboardMarkup( - [[ - InlineKeyboardButton(str(locale("join", "button", locale=holo_user)), url=link.invite_link) - ]] - )) + await app.send_message( + holo_user.id, + locale("approved", "message"), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + str(locale("join", "button", locale=holo_user)), + url=link.invite_link, + ) + ] + ] + ), + ) holo_user.set("link", link.invite_link) logWrite(f"User {holo_user.id} got an invite link {link.invite_link}") else: - await app.send_message(holo_user.id, locale("approved_joined", "message", locale=holo_user)) + await app.send_message( + holo_user.id, locale("approved_joined", "message", locale=holo_user) + ) + @app.on_callback_query(filters.regex("reapply_no_[\s\S]*")) async def callback_query_reapply_reject(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]), disable_notification=True) - await app.send_message(holo_user.id, locale("rejected", "message", locale=holo_user)) - logWrite(f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}") + await app.send_message( + configGet("admin", "groups"), + locale("rejected_by", "message").format(clb.from_user.first_name, fullclb[2]), + disable_notification=True, + ) + await app.send_message( + holo_user.id, locale("rejected", "message", locale=holo_user) + ) + logWrite( + f"User {fullclb[2]} got their reapplication rejected by {clb.from_user.id}" + ) - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}}) + col_tmp.update_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, + {"$set": {"state": "rejected", "sent": False}}, + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")], [InlineKeyboardButton(text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("declined", "button")), callback_data="nothing" + ) + ], + [ + InlineKeyboardButton( + text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}" + ) + ], + ] + + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sub_rejected", "callback", locale=clb.from_user).format( + fullclb[2] + ), + show_alert=True, + ) - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sub_rejected", "callback", locale=clb.from_user).format(fullclb[2]), show_alert=True) # Use old application when user reapplies after leaving the chat @app.on_callback_query(filters.regex("reapply_old_[\s\S]*")) async def callback_query_reapply_old(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(clb.from_user) if holo_user.sponsorship_state()[0] == "fill": - await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False) + await clb.message.reply_text( + locale("finish_sponsorship", "message"), quote=False + ) return message = await app.get_messages(clb.from_user.id, int(fullclb[2])) - if col_tmp.find_one({"user": holo_user.id, "type": "application"}) is None and col_applications.find_one({"user": holo_user.id}) is not None: + if ( + col_tmp.find_one({"user": holo_user.id, "type": "application"}) is None + and col_applications.find_one({"user": holo_user.id}) is not None + ): col_tmp.insert_one( { "user": holo_user.id, @@ -103,37 +211,68 @@ async def callback_query_reapply_old(app: Client, clb: CallbackQuery): "state": "fill", "reapply": True, "stage": 10, - "application": col_applications.find_one({"user": holo_user.id})["application"] + "application": col_applications.find_one({"user": holo_user.id})[ + "application" + ], } ) - + await confirm_yes(app, message, kind="application") - await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button", locale=clb.from_user), "nothing")]])) + await clb.message.edit( + clb.message.text, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("done", "button", locale=clb.from_user), "nothing" + ) + ] + ] + ), + ) + # Start a new application when user reapplies after leaving the chat @app.on_callback_query(filters.regex("reapply_new_[\s\S]*")) async def callback_query_reapply_new(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(clb.from_user) if holo_user.sponsorship_state()[0] == "fill": - await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False) + await clb.message.reply_text( + locale("finish_sponsorship", "message"), quote=False + ) return await clb.answer(locale("reapply_stopped", "callback", locale=clb.from_user)) message = await app.get_messages(clb.from_user.id, int(fullclb[2])) - col_tmp.update_one({"user": clb.from_user.id, "type": "application"}, {"$set": {"state": "fill", "completed": False, "stage": 1}}) + col_tmp.update_one( + {"user": clb.from_user.id, "type": "application"}, + {"$set": {"state": "fill", "completed": False, "stage": 1}}, + ) holo_user.application_restart(reapply=True) await welcome_pass(app, message, once_again=True) - logWrite(f"User {clb.from_user.id} restarted the application after leaving the chat earlier") - await clb.message.edit(clb.message.text, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("done", "button", locale=clb.from_user), "nothing")]])) + logWrite( + f"User {clb.from_user.id} restarted the application after leaving the chat earlier" + ) + await clb.message.edit( + clb.message.text, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("done", "button", locale=clb.from_user), "nothing" + ) + ] + ] + ), + ) + # Abort application fill in progress and restart it @app.on_callback_query(filters.regex("reapply_stop_[\s\S]*")) async def callback_query_reapply_stop(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(clb.from_user) @@ -142,5 +281,10 @@ async def callback_query_reapply_stop(app: Client, clb: CallbackQuery): message = await app.get_messages(clb.from_user.id, int(fullclb[2])) await welcome_pass(app, message, once_again=True) logWrite(f"User {clb.from_user.id} restarted the application due to typo in it") - await clb.message.edit(locale("reapply_restarted", "message", locale=holo_user), reply_markup=ReplyKeyboardRemove()) -# ============================================================================================================================== \ No newline at end of file + await clb.message.edit( + locale("reapply_restarted", "message", locale=holo_user), + reply_markup=ReplyKeyboardRemove(), + ) + + +# ============================================================================================================================== diff --git a/modules/callbacks/rules.py b/modules/callbacks/rules.py index 8cba64c..ce33eca 100644 --- a/modules/callbacks/rules.py +++ b/modules/callbacks/rules.py @@ -6,10 +6,10 @@ from pyrogram import filters from modules.utils import locale, logWrite from modules.commands.rules import DefaultRulesMarkup + # Callback rule ================================================================================================================ @app.on_callback_query(filters.regex("rule_[\s\S]*")) async def callback_query_rule(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") logWrite(f"User {clb.from_user.id} requested to check out rule {fullclb[1]}") @@ -18,55 +18,88 @@ async def callback_query_rule(app: Client, clb: CallbackQuery): if rule_num == len(locale("rules")): lower_buttons = [ - InlineKeyboardButton(locale("rules_prev", "button", locale=clb.from_user), callback_data=f"rule_{rule_num-1}") + InlineKeyboardButton( + locale("rules_prev", "button", locale=clb.from_user), + callback_data=f"rule_{rule_num-1}", + ) ] elif rule_num == 1: lower_buttons = [ - InlineKeyboardButton(locale("rules_next", "button", locale=clb.from_user), callback_data=f"rule_{rule_num+1}") + InlineKeyboardButton( + locale("rules_next", "button", locale=clb.from_user), + callback_data=f"rule_{rule_num+1}", + ) ] else: lower_buttons = [ - InlineKeyboardButton(locale("rules_prev", "button", locale=clb.from_user), callback_data=f"rule_{rule_num-1}"), - InlineKeyboardButton(locale("rules_next", "button", locale=clb.from_user), callback_data=f"rule_{rule_num+1}") + InlineKeyboardButton( + locale("rules_prev", "button", locale=clb.from_user), + callback_data=f"rule_{rule_num-1}", + ), + InlineKeyboardButton( + locale("rules_next", "button", locale=clb.from_user), + callback_data=f"rule_{rule_num+1}", + ), ] try: - await clb.message.edit(text=locale("rules", locale=clb.from_user)[rule_num-1], disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup( + await clb.message.edit( + text=locale("rules", locale=clb.from_user)[rule_num - 1], + disable_web_page_preview=True, + reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(locale("rules_home", "button", locale=clb.from_user), callback_data="rules_home"), - InlineKeyboardButton(locale("rules_additional", "button", locale=clb.from_user), callback_data="rules_additional") + InlineKeyboardButton( + locale("rules_home", "button", locale=clb.from_user), + callback_data="rules_home", + ), + InlineKeyboardButton( + locale("rules_additional", "button", locale=clb.from_user), + callback_data="rules_additional", + ), ], - lower_buttons + lower_buttons, ] - ) + ), ) except bad_request_400.MessageNotModified: pass - await clb.answer(text=locale("rules_page", "callback", locale=clb.from_user).format(fullclb[1])) + await clb.answer( + text=locale("rules_page", "callback", locale=clb.from_user).format(fullclb[1]) + ) + @app.on_callback_query(filters.regex("rules_home")) async def callback_query_rules_home(app: Client, clb: CallbackQuery): - logWrite(f"User {clb.from_user.id} requested to check out homepage rules") try: - await clb.message.edit(text=locale("rules_msg", locale=clb.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(clb.from_user).keyboard) + await clb.message.edit( + text=locale("rules_msg", locale=clb.from_user), + disable_web_page_preview=True, + reply_markup=DefaultRulesMarkup(clb.from_user).keyboard, + ) except bad_request_400.MessageNotModified: pass await clb.answer(text=locale("rules_home", "callback", locale=clb.from_user)) + @app.on_callback_query(filters.regex("rules_additional")) async def callback_query_rules_additional(app: Client, clb: CallbackQuery): - logWrite(f"User {clb.from_user.id} requested to check out additional rules") try: - await clb.message.edit(text=locale("rules_additional", locale=clb.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(clb.from_user).keyboard) + await clb.message.edit( + text=locale("rules_additional", locale=clb.from_user), + disable_web_page_preview=True, + reply_markup=DefaultRulesMarkup(clb.from_user).keyboard, + ) except bad_request_400.MessageNotModified: pass await clb.answer(text=locale("rules_additional", "callback", locale=clb.from_user)) -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/callbacks/spoiler.py b/modules/callbacks/spoiler.py index 387658d..5a48755 100644 --- a/modules/callbacks/spoiler.py +++ b/modules/callbacks/spoiler.py @@ -8,29 +8,78 @@ from bson.objectid import ObjectId from modules.utils import configGet, jsonLoad, locale + # Callback sid ================================================================================================================= @app.on_callback_query(filters.regex("sid_[\s\S]*")) async def callback_query_sid(app: Client, clb: CallbackQuery): - await clb.answer(url=f'https://t.me/{(await app.get_me()).username}?start={clb.data.split("_")[1]}') + await clb.answer( + url=f'https://t.me/{(await app.get_me()).username}?start={clb.data.split("_")[1]}' + ) + + # ============================================================================================================================== + # Callback shc ================================================================================================================= @app.on_callback_query(filters.regex("shc_[\s\S]*")) async def callback_query_shc(app: Client, clb: CallbackQuery): - - if (clb.from_user.id not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))): - await clb.answer(locale("spoiler_forbidden", "callback", locale=clb.from_user), show_alert=True) + if clb.from_user.id not in jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ): + await clb.answer( + locale("spoiler_forbidden", "callback", locale=clb.from_user), + show_alert=True, + ) return - spoil = col_spoilers.find_one( {"_id": ObjectId(clb.data.split("_")[1])} ) + spoil = col_spoilers.find_one({"_id": ObjectId(clb.data.split("_")[1])}) if spoil["description"] == "": - desc = locale("spoiler_empty_named", "message", locale=clb.from_user).format(locale(spoil["category"], "message", "spoiler_categories"), clb.from_user.first_name) + desc = locale("spoiler_empty_named", "message", locale=clb.from_user).format( + locale(spoil["category"], "message", "spoiler_categories"), + clb.from_user.first_name, + ) else: - desc = locale("spoiler_described_named", "message", locale=clb.from_user).format(locale(spoil["category"], "message", "spoiler_categories"), clb.from_user.first_name, spoil["description"]) + desc = locale( + "spoiler_described_named", "message", locale=clb.from_user + ).format( + locale(spoil["category"], "message", "spoiler_categories"), + clb.from_user.first_name, + spoil["description"], + ) - await app.send_message(configGet("users", "groups"), desc, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_view", "button", locale=clb.from_user), callback_data=f'sid_{clb.data.split("_")[1]}')]])) - await app.send_message(configGet("admin", "groups"), desc, reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_view", "button", locale=clb.from_user), callback_data=f'sid_{clb.data.split("_")[1]}')]])) + await app.send_message( + configGet("users", "groups"), + desc, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("spoiler_view", "button", locale=clb.from_user), + callback_data=f'sid_{clb.data.split("_")[1]}', + ) + ] + ] + ), + ) + await app.send_message( + configGet("admin", "groups"), + desc, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("spoiler_view", "button", locale=clb.from_user), + callback_data=f'sid_{clb.data.split("_")[1]}', + ) + ] + ] + ), + ) - await clb.answer(locale("spoiler_sent", "callback", locale=clb.from_user), show_alert=True) -# ============================================================================================================================== \ No newline at end of file + await clb.answer( + locale("spoiler_sent", "callback", locale=clb.from_user), show_alert=True + ) + + +# ============================================================================================================================== diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 918135f..05732e0 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -1,6 +1,11 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply, CallbackQuery +from pyrogram.types import ( + InlineKeyboardMarkup, + InlineKeyboardButton, + ForceReply, + CallbackQuery, +) from pyrogram.client import Client from pyrogram import filters from classes.errors.holo_user import LabelSettingError @@ -8,46 +13,79 @@ from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite, should_quote from modules.database import col_tmp, col_sponsorships + # Callbacks sponsorship ======================================================================================================== @app.on_callback_query(filters.regex("sponsor_apply_[\s\S]*")) async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) if holo_user.application_state()[0] == "fill": - await clb.message.reply_text(locale("finish_application", "message"), quote=should_quote(clb.message)) + await clb.message.reply_text( + locale("finish_application", "message"), quote=should_quote(clb.message) + ) return logWrite(f"User {holo_user.id} applied for sponsorship") holo_user.sponsorship_restart() - edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("sponsor_started", "button")), callback_data="nothing" + ) + ] + ] + + await clb.message.edit( + text=locale("sponsorship_applying", "message", locale=holo_user), + reply_markup=InlineKeyboardMarkup(edited_markup), + ) + await app.send_message( + holo_user.id, + locale(f"sponsor1", "message", locale=holo_user), + reply_markup=ForceReply( + placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale)) + ), + ) + await clb.answer( + text=locale("sponsor_started", "callback", locale=holo_user).format( + holo_user.id + ), + show_alert=False, + ) - await clb.message.edit(text=locale("sponsorship_applying", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup(edited_markup)) - await app.send_message(holo_user.id, locale(f"sponsor1", "message", locale=holo_user), reply_markup=ForceReply(placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale)))) - await clb.answer(text=locale("sponsor_started", "callback", locale=holo_user).format(holo_user.id), show_alert=False) @app.on_callback_query(filters.regex("sponsor_yes_[\s\S]*")) async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("sponsor_approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - await app.send_message(holo_user.id, locale("sponsor_approved", "message", locale=holo_user)) + await app.send_message( + configGet("admin", "groups"), + locale("sponsor_approved_by", "message").format( + clb.from_user.first_name, holo_user.id + ), + disable_notification=True, + ) + await app.send_message( + holo_user.id, locale("sponsor_approved", "message", locale=holo_user) + ) logWrite(f"User {holo_user.id} got sponsorship approved by {clb.from_user.id}") if col_sponsorships.find_one({"user": holo_user.id}) is not None: - col_sponsorships.update_one({"user": holo_user.id}, + col_sponsorships.update_one( + {"user": holo_user.id}, { "$set": { "date": datetime.now(), "admin": clb.from_user.id, - "sponsorship": col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})["sponsorship"] + "sponsorship": col_tmp.find_one( + {"user": holo_user.id, "type": "sponsorship"} + )["sponsorship"], } - } + }, ) else: col_sponsorships.insert_one( @@ -55,49 +93,84 @@ async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery): "user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, - "sponsorship": col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})["sponsorship"] + "sponsorship": col_tmp.find_one( + {"user": holo_user.id, "type": "sponsorship"} + )["sponsorship"], } ) - - col_tmp.update_one({"user": holo_user.id, "type":"sponsorship"}, - { - "$set": { - "state": "approved", - "sent": False - } - } + + col_tmp.update_one( + {"user": holo_user.id, "type": "sponsorship"}, + {"$set": {"state": "approved", "sent": False}}, ) try: - await holo_user.label_set(configGet("users", "groups"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"]) + await holo_user.label_set( + configGet("users", "groups"), + col_tmp.find_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}} + )["sponsorship"]["label"], + ) except LabelSettingError as exp: - await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True) + await app.send_message( + configGet("admin", "groups"), exp.__str__(), disable_notification=True + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("accepted", "button")), callback_data="nothing" + ) + ] + ] + + await app.edit_message_caption( + clb.message.chat.id, + clb.message.id, + caption=clb.message.caption, + reply_markup=InlineKeyboardMarkup(edited_markup), + ) + await clb.answer( + text=locale("sponsor_accepted", "callback").format(fullclb[2]), show_alert=False + ) - await app.edit_message_caption(clb.message.chat.id, clb.message.id, caption=clb.message.caption, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sponsor_accepted", "callback").format(fullclb[2]), show_alert=False) @app.on_callback_query(filters.regex("sponsor_no_[\s\S]*")) async def callback_query_sponsor_no(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("sponsor_rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - await app.send_message(holo_user.id, locale("sponsor_rejected", "message", locale=holo_user)) + await app.send_message( + configGet("admin", "groups"), + locale("sponsor_rejected_by", "message").format( + clb.from_user.first_name, holo_user.id + ), + disable_notification=True, + ) + await app.send_message( + holo_user.id, locale("sponsor_rejected", "message", locale=holo_user) + ) logWrite(f"User {holo_user.id} got sponsorship rejected by {clb.from_user.id}") - col_tmp.update_one({"user": holo_user.id, "type": "sponsorship"}, - { - "$set": { - "state": "rejected", - "sent": False - } - } + col_tmp.update_one( + {"user": holo_user.id, "type": "sponsorship"}, + {"$set": {"state": "rejected", "sent": False}}, ) - edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("declined", "button")), callback_data="nothing" + ) + ] + ] - await app.edit_message_caption(clb.message.chat.id, clb.message.id, caption=clb.message.caption, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sponsor_rejected", "callback").format(fullclb[2]), show_alert=False) \ No newline at end of file + await app.edit_message_caption( + clb.message.chat.id, + clb.message.id, + caption=clb.message.caption, + reply_markup=InlineKeyboardMarkup(edited_markup), + ) + await clb.answer( + text=locale("sponsor_rejected", "callback").format(fullclb[2]), show_alert=False + ) diff --git a/modules/callbacks/sub.py b/modules/callbacks/sub.py index e9ba485..ef6954c 100644 --- a/modules/callbacks/sub.py +++ b/modules/callbacks/sub.py @@ -8,14 +8,18 @@ from modules.utils import configGet, locale, logWrite from modules.database import col_tmp, col_applications from modules.commands.rules import DefaultRulesMarkup + # Callbacks application ======================================================================================================== @app.on_callback_query(filters.regex("sub_yes_[\s\S]*")) async def callback_query_accept(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) + await app.send_message( + configGet("admin", "groups"), + locale("approved_by", "message").format(clb.from_user.first_name, holo_user.id), + disable_notification=True, + ) logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}") need_link = True @@ -23,65 +27,167 @@ async def callback_query_accept(app: Client, clb: CallbackQuery): async for member in app.get_chat_members(configGet("users", "groups")): if member.user.id == holo_user.id: need_link = False - + if need_link: - link = await app.create_chat_invite_link(configGet("users", "groups"), name=f"Invite for {holo_user.id}", member_limit=1) #, expire_date=datetime.now()+timedelta(days=1)) + link = await app.create_chat_invite_link( + configGet("users", "groups"), + name=f"Invite for {holo_user.id}", + member_limit=1, + ) # , expire_date=datetime.now()+timedelta(days=1)) - await app.send_message(holo_user.id, locale("read_rules", "message", locale=holo_user)) + await app.send_message( + holo_user.id, locale("read_rules", "message", locale=holo_user) + ) - await app.send_message(holo_user.id, locale("rules_msg", locale=holo_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(holo_user).keyboard) + await app.send_message( + holo_user.id, + locale("rules_msg", locale=holo_user), + disable_web_page_preview=True, + reply_markup=DefaultRulesMarkup(holo_user).keyboard, + ) - await app.send_message(holo_user.id, locale("approved", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup( - [[ - InlineKeyboardButton(str(locale("join", "button", locale=holo_user)), url=link.invite_link) - ]] - )) + await app.send_message( + holo_user.id, + locale("approved", "message", locale=holo_user), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + str(locale("join", "button", locale=holo_user)), + url=link.invite_link, + ) + ] + ] + ), + ) holo_user.set("link", link.invite_link) logWrite(f"User {holo_user.id} got an invite link {link.invite_link}") else: - await app.send_message(holo_user.id, locale("approved_joined", "message", locale=holo_user)) + await app.send_message( + holo_user.id, locale("approved_joined", "message", locale=holo_user) + ) - col_applications.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "application": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}})["application"]}) - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}}) + col_applications.insert_one( + { + "user": holo_user.id, + "date": datetime.now(), + "admin": clb.from_user.id, + "application": col_tmp.find_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}} + )["application"], + } + ) + col_tmp.update_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, + {"$set": {"state": "approved", "sent": False}}, + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("accepted", "button")), callback_data="nothing" + ) + ] + ] + + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sub_accepted", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sub_accepted", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) @app.on_callback_query(filters.regex("sub_no_[\s\S]*")) async def callback_query_reject(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - await app.send_message(holo_user.id, locale("rejected", "message", locale=holo_user)) + await app.send_message( + configGet("admin", "groups"), + locale("rejected_by", "message").format(clb.from_user.first_name, holo_user.id), + disable_notification=True, + ) + await app.send_message( + holo_user.id, locale("rejected", "message", locale=holo_user) + ) logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id}") - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}}) + col_tmp.update_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, + {"$set": {"state": "rejected", "sent": False}}, + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")], [InlineKeyboardButton(text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("declined", "button")), callback_data="nothing" + ) + ], + [ + InlineKeyboardButton( + text=str(locale("ban", "button")), callback_data=f"ban_{fullclb[2]}" + ) + ], + ] + + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sub_rejected", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sub_rejected", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) @app.on_callback_query(filters.regex("sub_russian_[\s\S]*")) async def callback_query_reject_russian(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("rejected_by_rus", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - await app.send_message(holo_user.id, locale("rejected_russian", "message", locale=holo_user)) - logWrite(f"User {holo_user.id} got rejected by {clb.from_user.id} due to being russian") + await app.send_message( + configGet("admin", "groups"), + locale("rejected_by_rus", "message").format( + clb.from_user.first_name, holo_user.id + ), + disable_notification=True, + ) + await app.send_message( + holo_user.id, locale("rejected_russian", "message", locale=holo_user) + ) + logWrite( + f"User {holo_user.id} got rejected by {clb.from_user.id} due to being russian" + ) - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}}) + col_tmp.update_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, + {"$set": {"state": "rejected", "sent": False}}, + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("declined", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("declined", "button")), callback_data="nothing" + ) + ] + ] - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sub_russian", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) -# ============================================================================================================================== \ No newline at end of file + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sub_russian", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) + + +# ============================================================================================================================== diff --git a/modules/callbacks/sus.py b/modules/callbacks/sus.py index a01da45..4c51471 100644 --- a/modules/callbacks/sus.py +++ b/modules/callbacks/sus.py @@ -1,49 +1,104 @@ from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions, CallbackQuery +from pyrogram.types import ( + InlineKeyboardMarkup, + InlineKeyboardButton, + ChatPermissions, + CallbackQuery, +) from pyrogram.client import Client from pyrogram import filters from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite from modules.database import col_tmp + # Callbacks sus users ========================================================================================================== @app.on_callback_query(filters.regex("sus_allow_[\s\S]*")) async def callback_query_sus_allow(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("sus_allowed_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - logWrite(f"User {holo_user.id} was allowed to join with another link by {clb.from_user.id}") + await app.send_message( + configGet("admin", "groups"), + locale("sus_allowed_by", "message").format( + clb.from_user.first_name, holo_user.id + ), + disable_notification=True, + ) + logWrite( + f"User {holo_user.id} was allowed to join with another link by {clb.from_user.id}" + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("sus_allowed", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("sus_allowed", "button")), callback_data="nothing" + ) + ] + ] - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sus_allowed", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sus_allowed", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) - await app.restrict_chat_member(configGet("users", "groups"), holo_user.id, permissions=ChatPermissions( + await app.restrict_chat_member( + configGet("users", "groups"), + holo_user.id, + permissions=ChatPermissions( can_send_messages=True, can_send_media_messages=True, can_send_other_messages=True, - can_send_polls=True - ) + can_send_polls=True, + ), ) + @app.on_callback_query(filters.regex("sus_reject_[\s\S]*")) async def callback_query_sus_reject(app: Client, clb: CallbackQuery): - fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) - await app.send_message(configGet("admin", "groups"), locale("sus_rejected_by", "message").format(clb.from_user.first_name, holo_user.id), disable_notification=True) - logWrite(f"User {holo_user.id} was rejected to join with another link by {clb.from_user.id}") + await app.send_message( + configGet("admin", "groups"), + locale("sus_rejected_by", "message").format( + clb.from_user.first_name, holo_user.id + ), + disable_notification=True, + ) + logWrite( + f"User {holo_user.id} was rejected to join with another link by {clb.from_user.id}" + ) - edited_markup = [[InlineKeyboardButton(text=str(locale("sus_rejected", "button")), callback_data="nothing")]] + edited_markup = [ + [ + InlineKeyboardButton( + text=str(locale("sus_rejected", "button")), callback_data="nothing" + ) + ] + ] - await clb.message.edit(text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sus_rejected", "callback", locale=clb.from_user).format(holo_user.id), show_alert=True) + await clb.message.edit( + text=clb.message.text, reply_markup=InlineKeyboardMarkup(edited_markup) + ) + await clb.answer( + text=locale("sus_rejected", "callback", locale=clb.from_user).format( + holo_user.id + ), + show_alert=True, + ) await app.ban_chat_member(configGet("users", "groups"), holo_user.id) - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}}) -# ============================================================================================================================== \ No newline at end of file + col_tmp.update_one( + {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, + {"$set": {"state": "rejected", "sent": False}}, + ) + + +# ============================================================================================================================== diff --git a/modules/commands/application.py b/modules/commands/application.py index 069c03e..f68f5e6 100644 --- a/modules/commands/application.py +++ b/modules/commands/application.py @@ -12,51 +12,92 @@ from dateutil.relativedelta import relativedelta from modules.database import col_applications from modules import custom_filters + # Application command ========================================================================================================== -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["application"], prefixes=["/"]) & custom_filters.admin) +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.command(["application"], prefixes=["/"]) + & custom_filters.admin +) async def cmd_application(app: Client, msg: Message): - try: - try: holo_user = HoloUser(int(msg.command[1])) except (ValueError, UserNotFoundError): try: holo_user = HoloUser((await app.get_users(msg.command[1])).id) - except (bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid, bad_request_400.UsernameNotOccupied): - await msg.reply_text(locale("no_user_application", "message", locale=msg.from_user).format(msg.command[1]), quote=should_quote(msg)) + except ( + bad_request_400.UsernameInvalid, + bad_request_400.PeerIdInvalid, + bad_request_400.UsernameNotOccupied, + ): + await msg.reply_text( + locale( + "no_user_application", "message", locale=msg.from_user + ).format(msg.command[1]), + quote=should_quote(msg), + ) return application = col_applications.find_one({"user": holo_user.id}) if application is None: - logWrite(f"User {msg.from_user.id} requested application of {holo_user.id} but user does not exists") - await msg.reply_text(locale("user_invalid", "message", locale=msg.from_user), quote=should_quote(msg)) + logWrite( + f"User {msg.from_user.id} requested application of {holo_user.id} but user does not exists" + ) + await msg.reply_text( + locale("user_invalid", "message", locale=msg.from_user), + quote=should_quote(msg), + ) return application_content = [] i = 1 - for question in application['application']: - + for question in application["application"]: if i == 2: - age = relativedelta(datetime.now(), application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta(datetime.now(), application["application"]["2"]) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']}") + if application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application'][question]}" + ) + i += 1 - application_status = locale("application_status_accepted", "message", locale=msg.from_user).format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M")) + application_status = locale( + "application_status_accepted", "message", locale=msg.from_user + ).format( + (await app.get_users(application["admin"])).first_name, + application["date"].strftime("%d.%m.%Y, %H:%M"), + ) logWrite(f"User {msg.from_user.id} requested application of {holo_user.id}") - await msg.reply_text(locale("contact", "message", locale=msg.from_user).format(holo_user.id, "\n".join(application_content), application_status), parse_mode=ParseMode.MARKDOWN, quote=should_quote(msg)) - + await msg.reply_text( + locale("contact", "message", locale=msg.from_user).format( + holo_user.id, "\n".join(application_content), application_status + ), + parse_mode=ParseMode.MARKDOWN, + quote=should_quote(msg), + ) + except IndexError: - await msg.reply_text(locale("application_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("application_invalid_syntax", "message", locale=msg.from_user), + quote=should_quote(msg), + ) + + +# ============================================================================================================================== diff --git a/modules/commands/applications.py b/modules/commands/applications.py index 3f4feb3..bdb4a6d 100644 --- a/modules/commands/applications.py +++ b/modules/commands/applications.py @@ -10,10 +10,15 @@ from modules.utils import should_quote, jsonSave from modules.database import col_applications from modules import custom_filters -# Applications command ========================================================================================================= -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["applications"], prefixes=["/"]) & custom_filters.admin) -async def cmd_applications(app: Client, msg: Message): +# Applications command ========================================================================================================= +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.command(["applications"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_applications(app: Client, msg: Message): logWrite(f"Admin {msg.from_user.id} requested export of a database") await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT) filename = uuid1() @@ -21,10 +26,18 @@ async def cmd_applications(app: Client, msg: Message): for entry in col_applications.find(): del entry["_id"] entry["date"] = entry["date"].strftime("%d.%m.%Y, %H:%M") - entry["application"]["2"] = entry["application"]["2"].strftime("%d.%m.%Y, %H:%M") + entry["application"]["2"] = entry["application"]["2"].strftime( + "%d.%m.%Y, %H:%M" + ) output.append(entry) makedirs("tmp", exist_ok=True) jsonSave(output, f"tmp{sep}{filename}.json") - await msg.reply_document(document=f"tmp{sep}{filename}.json", file_name="applications", quote=should_quote(msg)) + await msg.reply_document( + document=f"tmp{sep}{filename}.json", + file_name="applications", + quote=should_quote(msg), + ) remove(f"tmp{sep}{filename}.json") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/cancel.py b/modules/commands/cancel.py index d46fa6f..7d32276 100644 --- a/modules/commands/cancel.py +++ b/modules/commands/cancel.py @@ -6,14 +6,30 @@ from modules.utils import should_quote, logWrite, locale from modules.database import col_tmp, col_spoilers, col_applications from modules import custom_filters + # Cancel command =============================================================================================================== -@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("cancel", prefixes=["/"]) & ~custom_filters.banned) +@app.on_message( + (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) + & ~filters.scheduled + & filters.command("cancel", prefixes=["/"]) + & ~custom_filters.banned +) async def command_cancel(app: Client, msg: Message): - col_tmp.delete_many( {"user": msg.from_user.id, "sent": False} ) - col_spoilers.delete_many( {"user": msg.from_user.id, "completed": False} ) - if col_applications.find_one( {"user": msg.from_user.id} ) is None: - await msg.reply_text(locale("cancel_reapply", "message", locale=msg.from_user), quote=should_quote(msg), reply_markup=ReplyKeyboardRemove()) + col_tmp.delete_many({"user": msg.from_user.id, "sent": False}) + col_spoilers.delete_many({"user": msg.from_user.id, "completed": False}) + if col_applications.find_one({"user": msg.from_user.id}) is None: + await msg.reply_text( + locale("cancel_reapply", "message", locale=msg.from_user), + quote=should_quote(msg), + reply_markup=ReplyKeyboardRemove(), + ) else: - await msg.reply_text(locale("cancel", "message", locale=msg.from_user), quote=should_quote(msg), reply_markup=ReplyKeyboardRemove()) + await msg.reply_text( + locale("cancel", "message", locale=msg.from_user), + quote=should_quote(msg), + reply_markup=ReplyKeyboardRemove(), + ) logWrite(f"Cancelling all ongoing tmp operations for {msg.from_user.id}") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/identify.py b/modules/commands/identify.py index 83a450b..167177a 100644 --- a/modules/commands/identify.py +++ b/modules/commands/identify.py @@ -7,15 +7,30 @@ from pyrogram.errors import bad_request_400 from pyrogram.enums.chat_action import ChatAction from classes.errors.holo_user import UserNotFoundError, UserInvalidError from classes.holo_user import HoloUser -from modules.utils import jsonLoad, should_quote, logWrite, locale, download_tmp, create_tmp, find_user +from modules.utils import ( + jsonLoad, + should_quote, + logWrite, + locale, + download_tmp, + create_tmp, + find_user, +) from modules import custom_filters -# Identify command ============================================================================================================= -@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.command("identify", prefixes=["/"]) & custom_filters.admin) -async def cmd_identify(app: Client, msg: Message): +# Identify command ============================================================================================================= +@app.on_message( + (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) + & ~filters.scheduled + & filters.command("identify", prefixes=["/"]) + & custom_filters.admin +) +async def cmd_identify(app: Client, msg: Message): if len(msg.command) != 2: - await msg.reply_text(locale("identify_invalid_syntax", "message", locale=msg.from_user)) + await msg.reply_text( + locale("identify_invalid_syntax", "message", locale=msg.from_user) + ) return try: @@ -23,17 +38,44 @@ async def cmd_identify(app: Client, msg: Message): holo_user = HoloUser(int(msg.command[1])) except ValueError: holo_user = HoloUser(await find_user(app, msg.command[1])) - except (UserInvalidError, UserNotFoundError, bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid, bad_request_400.UsernameNotOccupied, TypeError): - await msg.reply_text(locale("identify_not_found", "message", locale=msg.from_user).format(msg.command[1])) + except ( + UserInvalidError, + UserNotFoundError, + bad_request_400.UsernameInvalid, + bad_request_400.PeerIdInvalid, + bad_request_400.UsernameNotOccupied, + TypeError, + ): + await msg.reply_text( + locale("identify_not_found", "message", locale=msg.from_user).format( + msg.command[1] + ) + ) return role = holo_user.label - has_application = locale("yes", "message", locale=msg.from_user) if holo_user.application_approved() is True else locale("no", "message", locale=msg.from_user) - has_sponsorship = locale("yes", "message", locale=msg.from_user) if holo_user.sponsorship_valid() is True else locale("no", "message", locale=msg.from_user) + has_application = ( + locale("yes", "message", locale=msg.from_user) + if holo_user.application_approved() is True + else locale("no", "message", locale=msg.from_user) + ) + has_sponsorship = ( + locale("yes", "message", locale=msg.from_user) + if holo_user.sponsorship_valid() is True + else locale("no", "message", locale=msg.from_user) + ) username = holo_user.username if holo_user.username is not None else "N/A" - in_chat = locale("yes", "message", locale=msg.from_user) if (holo_user.id in jsonLoad(path.join("cache", "group_members"))) else locale("no", "message", locale=msg.from_user) - is_admin = locale("yes", "message", locale=msg.from_user) if (await isAnAdmin(holo_user.id)) else locale("no", "message", locale=msg.from_user) + in_chat = ( + locale("yes", "message", locale=msg.from_user) + if (holo_user.id in jsonLoad(path.join("cache", "group_members"))) + else locale("no", "message", locale=msg.from_user) + ) + is_admin = ( + locale("yes", "message", locale=msg.from_user) + if (await isAnAdmin(holo_user.id)) + else locale("no", "message", locale=msg.from_user) + ) output = locale("identify_success", "message", locale=msg.from_user).format( holo_user.id, @@ -43,24 +85,25 @@ async def cmd_identify(app: Client, msg: Message): is_admin, role, has_application, - has_sponsorship + has_sponsorship, ) - + user = await app.get_users(holo_user.id) if user.photo is not None: await app.send_chat_action(msg.chat.id, action=ChatAction.UPLOAD_PHOTO) await msg.reply_photo( - create_tmp((await download_tmp(app, user.photo.big_file_id))[1], kind="image"), + create_tmp( + (await download_tmp(app, user.photo.big_file_id))[1], kind="image" + ), quote=should_quote(msg), - caption=output + caption=output, ) else: await app.send_chat_action(msg.chat.id, action=ChatAction.TYPING) - await msg.reply_text( - output, - quote=should_quote(msg) - ) + await msg.reply_text(output, quote=should_quote(msg)) logWrite(f"User {msg.from_user.id} identified user {holo_user.id}") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/issue.py b/modules/commands/issue.py index b6dd9bb..70610f6 100644 --- a/modules/commands/issue.py +++ b/modules/commands/issue.py @@ -9,13 +9,28 @@ from classes.holo_user import HoloUser # Issue command ================================================================================================================ -@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["issue"], prefixes=["/"]) & ~custom_filters.banned) +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.private + & filters.command(["issue"], prefixes=["/"]) + & ~custom_filters.banned +) async def cmd_issue(app: Client, msg: Message): - await msg.reply_text(locale("issue", "message", locale=msg.from_user), disable_web_page_preview=True, reply_markup=InlineKeyboardMarkup( + await msg.reply_text( + locale("issue", "message", locale=msg.from_user), + disable_web_page_preview=True, + reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(locale("issue", "button", locale=msg.from_user), url=configGet("issues")) + InlineKeyboardButton( + locale("issue", "button", locale=msg.from_user), + url=configGet("issues"), + ) ] ] - )) -# ============================================================================================================================== \ No newline at end of file + ), + ) + + +# ============================================================================================================================== diff --git a/modules/commands/label.py b/modules/commands/label.py index 70821b8..b9eaf70 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -7,10 +7,15 @@ from classes.errors.holo_user import LabelTooLongError, LabelSettingError from classes.holo_user import HoloUser from modules import custom_filters -# Label command ================================================================================================================ -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.command(["label"], prefixes=["/"]) & custom_filters.admin) -async def cmd_label(app: Client, msg: Message): +# Label command ================================================================================================================ +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.command(["label"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_label(app: Client, msg: Message): if len(msg.command) < 3: await msg.reply_text("Invalid syntax:\n`/label USER LABEL`") return @@ -18,15 +23,16 @@ async def cmd_label(app: Client, msg: Message): target = await find_user(app, msg.command[1]) if target is not None: - target = HoloUser(target) label = " ".join(msg.command[2:]) if label.lower() == "reset": await target.label_reset(msg.chat) - await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg)) - + await msg.reply_text( + f"Resetting **{target.id}**'s label...", quote=should_quote(msg) + ) + else: try: await target.label_set(msg.chat, label) @@ -34,10 +40,19 @@ async def cmd_label(app: Client, msg: Message): await msg.reply_text(locale("label_too_long", "message")) return except LabelSettingError as exp: - await app.send_message(configGet("admin", "groups"), exp.__str__(), disable_notification=True) + await app.send_message( + configGet("admin", "groups"), + exp.__str__(), + disable_notification=True, + ) return - await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg)) - + await msg.reply_text( + f"Setting **{target.id}**'s label to **{label}**...", + quote=should_quote(msg), + ) + else: await msg.reply_text(f"User not found") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/message.py b/modules/commands/message.py index b2f582a..cca0490 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -7,28 +7,70 @@ from classes.holo_user import HoloUser from modules.utils import logWrite, locale, should_quote, find_user from modules import custom_filters + # Message command ============================================================================================================== -@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.command(["message"], prefixes=["/"]) & custom_filters.admin) +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.command(["message"], prefixes=["/"]) + & custom_filters.admin +) async def cmd_message(app: Client, msg: Message): - try: - try: destination = HoloUser(int(msg.command[1])) except (ValueError, UserInvalidError): destination = HoloUser(await find_user(app, query=msg.command[1])) - if ((msg.text is not None) and (len(str(msg.text).split()) > 2)): - await destination.message(context=msg, text=" ".join(str(msg.text).split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True) - elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)): - await destination.message(context=msg, text=str(msg.text), caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True) + if (msg.text is not None) and (len(str(msg.text).split()) > 2): + await destination.message( + context=msg, + text=" ".join(str(msg.text).split()[2:]), + caption=msg.caption, + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) + elif (msg.caption is not None) and (len(msg.caption.split()) > 2): + await destination.message( + context=msg, + text=str(msg.text), + caption=" ".join(msg.caption.split()[2:]), + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) else: - await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, voice=msg.voice, animation=msg.animation, adm_context=True) - + await destination.message( + context=msg, + text=None, + caption=None, + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) + except IndexError: - await msg.reply_text(locale("message_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg)) + await msg.reply_text( + locale("message_invalid_syntax", "message", locale=msg.from_user), + quote=should_quote(msg), + ) logWrite(f"Admin {msg.from_user.id} tried to send message but 'IndexError'") except ValueError: - await msg.reply_text(locale("message_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg)) + await msg.reply_text( + locale("message_invalid_syntax", "message", locale=msg.from_user), + quote=should_quote(msg), + ) logWrite(f"Admin {msg.from_user.id} tried to send message but 'ValueError'") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index b214f3a..563d809 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -11,50 +11,111 @@ from modules.utils import configGet, jsonLoad, locale, should_quote, find_locati from modules.database import col_applications, col_users from classes.errors.geo import PlaceNotFoundError -# Nearby command =============================================================================================================== -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & (filters.private | (filters.chat(configGet("admin", "groups")) | filters.chat(configGet("users", "groups")))) & filters.command(["nearby"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin) & ~custom_filters.banned) -async def cmd_nearby(app: Client, msg: Message): +# Nearby command =============================================================================================================== +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & ( + filters.private + | ( + filters.chat(configGet("admin", "groups")) + | filters.chat(configGet("users", "groups")) + ) + ) + & filters.command(["nearby"], prefixes=["/"]) + & (custom_filters.allowed | custom_filters.admin) + & ~custom_filters.banned +) +async def cmd_nearby(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) # Check if any place provided - if len(msg.command) == 1: # Action if no place provided + if len(msg.command) == 1: # Action if no place provided application = col_applications.find_one({"user": msg.from_user.id}) if application is None: - await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user)) + await msg.reply_text( + locale("nearby_user_empty", "message", locale=holo_user) + ) return - location = application["application"]["3"]["location"][0], application["application"]["3"]["location"][1] - else: # Find a place from input query + location = ( + application["application"]["3"]["location"][0], + application["application"]["3"]["location"][1], + ) + else: # Find a place from input query logWrite(f"Looking for the location by query '{' '.join(msg.command[1:])}'") try: location_coordinates = find_location(" ".join(msg.command[1:])) - location = float(location_coordinates["lng"]), float(location_coordinates["lat"]) - except PlaceNotFoundError: # Place is not found - await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user), quote=should_quote(msg)) + location = float(location_coordinates["lng"]), float( + location_coordinates["lat"] + ) + except PlaceNotFoundError: # Place is not found + await msg.reply_text( + locale("nearby_invalid", "message", locale=holo_user), + quote=should_quote(msg), + ) return - except Exception as exp: # Error occurred while finding the place - await msg.reply_text(locale("nearby_error", "message", locale=holo_user).format(exp, print_exc()), quote=should_quote(msg)) + except Exception as exp: # Error occurred while finding the place + await msg.reply_text( + locale("nearby_error", "message", locale=holo_user).format( + exp, print_exc() + ), + quote=should_quote(msg), + ) return # Find all users registered in the area provided output = [] - applications_nearby = col_applications.find( {"application.3.location": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } ) + applications_nearby = col_applications.find( + { + "application.3.location": { + "$nearSphere": { + "$geometry": { + "type": "Point", + "coordinates": [location[0], location[1]], + }, + "$maxDistance": configGet("search_radius") * 1000, + } + } + } + ) for entry in applications_nearby: if not entry["user"] == msg.from_user.id: - user = col_users.find_one( {"user": entry["user"]} ) + user = col_users.find_one({"user": entry["user"]}) if user is not None: - if entry["user"] in jsonLoad(path.join(configGet("cache", "locations"), "group_members")): - if user["tg_username"] not in [None, "None", ""]: # Check if user has any name - output.append(f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') + if entry["user"] in jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ): + if user["tg_username"] not in [ + None, + "None", + "", + ]: # Check if user has any name + output.append( + f'• **{user["tg_name"]}** (@{user["tg_username"]}):\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}' + ) else: - output.append(f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}') + output.append( + f'• **{user["tg_name"]}**:\n - {entry["application"]["3"]["name"]}, {entry["application"]["3"]["adminName1"]}' + ) - logWrite(f"{holo_user.id} tried to find someone nearby {location[1]} {location[0]} in the radius of {configGet('search_radius')} kilometers") + logWrite( + f"{holo_user.id} tried to find someone nearby {location[1]} {location[0]} in the radius of {configGet('search_radius')} kilometers" + ) # Check if any users found if len(output) > 0: - await msg.reply_text(locale("nearby_result", "message", locale=holo_user).format("\n".join(output)), quote=should_quote(msg)) + await msg.reply_text( + locale("nearby_result", "message", locale=holo_user).format( + "\n".join(output) + ), + quote=should_quote(msg), + ) else: - await msg.reply_text(locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg) + ) + + +# ============================================================================================================================== diff --git a/modules/commands/reapply.py b/modules/commands/reapply.py index 70e5105..2ba8468 100644 --- a/modules/commands/reapply.py +++ b/modules/commands/reapply.py @@ -9,18 +9,32 @@ from modules.handlers.welcome import welcome_pass from modules.database import col_tmp, col_applications from modules import custom_filters -# Reapply command ============================================================================================================== -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"]) & ~custom_filters.banned) -async def cmd_reapply(app: Client, msg: Message): +# Reapply command ============================================================================================================== +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.private + & filters.command(["reapply"], prefixes=["/"]) + & ~custom_filters.banned +) +async def cmd_reapply(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) # Check if user has approved/rejected tmp application - if ((holo_user.application_state()[0] in ["approved", "rejected"]) or (holo_user.application_state()[0] == "none")) and holo_user.spoiler_state() is False: - + if ( + (holo_user.application_state()[0] in ["approved", "rejected"]) + or (holo_user.application_state()[0] == "none") + ) and holo_user.spoiler_state() is False: # Check if user's tmp application is already completed or even sent - if ((holo_user.application_state()[1] is True) and (not col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"])) or (holo_user.application_state()[0] == "none"): - + if ( + (holo_user.application_state()[1] is True) + and ( + not col_tmp.find_one({"user": holo_user.id, "type": "application"})[ + "sent" + ] + ) + ) or (holo_user.application_state()[0] == "none"): left_chat = True async for member in app.get_chat_members(configGet("users", "groups")): @@ -28,64 +42,132 @@ async def cmd_reapply(app: Client, msg: Message): left_chat = False if left_chat is True: - - if (holo_user.application_state()[1] is True and holo_user.application_state()[0] not in ["fill", "rejected"]): + if holo_user.application_state()[ + 1 + ] is True and holo_user.application_state()[0] not in [ + "fill", + "rejected", + ]: + await msg.reply_text( + locale("reapply_left_chat", "message", locale=holo_user), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale( + "reapply_old_one", + "button", + locale=holo_user, + ), + f"reapply_old_{msg.id}", + ) + ], + [ + InlineKeyboardButton( + locale( + "reapply_new_one", + "button", + locale=holo_user, + ), + f"reapply_new_{msg.id}", + ) + ], + ] + ), + ) - await msg.reply_text(locale("reapply_left_chat", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup([ - [ - InlineKeyboardButton(locale("reapply_old_one", "button", locale=holo_user), f"reapply_old_{msg.id}") - ], - [ - InlineKeyboardButton(locale("reapply_new_one", "button", locale=holo_user), f"reapply_new_{msg.id}") - ] - ])) - - elif col_tmp.find_one({"user": holo_user.id, "type": "application"}) is None and col_applications.find_one({"user": holo_user.id}) is not None: - - await msg.reply_text(locale("reapply_left_chat", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup([ - [ - InlineKeyboardButton(locale("reapply_old_one", "button", locale=holo_user), f"reapply_old_{msg.id}") - ], - [ - InlineKeyboardButton(locale("reapply_new_one", "button", locale=holo_user), f"reapply_new_{msg.id}") - ] - ])) + elif ( + col_tmp.find_one({"user": holo_user.id, "type": "application"}) + is None + and col_applications.find_one({"user": holo_user.id}) is not None + ): + await msg.reply_text( + locale("reapply_left_chat", "message", locale=holo_user), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale( + "reapply_old_one", + "button", + locale=holo_user, + ), + f"reapply_old_{msg.id}", + ) + ], + [ + InlineKeyboardButton( + locale( + "reapply_new_one", + "button", + locale=holo_user, + ), + f"reapply_new_{msg.id}", + ) + ], + ] + ), + ) else: - holo_user.application_restart(reapply=True) await welcome_pass(app, msg, once_again=True) else: - if holo_user.sponsorship_state()[0] == "fill": - await msg.reply_text(locale("finish_sponsorship", "message"), quote=should_quote(msg)) + await msg.reply_text( + locale("finish_sponsorship", "message"), quote=should_quote(msg) + ) return - + holo_user.application_restart(reapply=True) await welcome_pass(app, msg, once_again=True) else: - - await msg.reply_text(locale("reapply_in_progress", "message", locale=holo_user).format(locale("confirm", "keyboard", locale=holo_user)[1][0]), reply_markup=InlineKeyboardMarkup([ - [ - InlineKeyboardButton(locale("applying_stop", "button", locale=holo_user), f"reapply_stop_{msg.id}") - ] - ])) + await msg.reply_text( + locale("reapply_in_progress", "message", locale=holo_user).format( + locale("confirm", "keyboard", locale=holo_user)[1][0] + ), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("applying_stop", "button", locale=holo_user), + f"reapply_stop_{msg.id}", + ) + ] + ] + ), + ) elif holo_user.spoiler_state() is True: - await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user)) else: + if (holo_user.application_state()[0] == "fill") and ( + col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"] + is True + ): + await msg.reply_text( + locale("reapply_forbidden", "message", locale=holo_user) + ) - if (holo_user.application_state()[0] == "fill") and (col_tmp.find_one({"user": holo_user.id, "type": "application"})["sent"] is True): - await msg.reply_text(locale("reapply_forbidden", "message", locale=holo_user)) - else: - await msg.reply_text(locale("reapply_in_progress", "message", locale=holo_user).format(locale("confirm", "keyboard", locale=holo_user)[1][0]), reply_markup=InlineKeyboardMarkup([ - [ - InlineKeyboardButton(locale("applying_stop", "button", locale=holo_user), f"reapply_stop_{msg.id}") - ] - ])) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("reapply_in_progress", "message", locale=holo_user).format( + locale("confirm", "keyboard", locale=holo_user)[1][0] + ), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale("applying_stop", "button", locale=holo_user), + f"reapply_stop_{msg.id}", + ) + ] + ] + ), + ) + + +# ============================================================================================================================== diff --git a/modules/commands/reboot.py b/modules/commands/reboot.py index 74834aa..fedb312 100644 --- a/modules/commands/reboot.py +++ b/modules/commands/reboot.py @@ -11,14 +11,28 @@ from modules import custom_filters pid = getpid() -# Reboot command =============================================================================================================== -@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"]) & custom_filters.admin) -async def cmd_kill(app: Client, msg: Message): +# Reboot command =============================================================================================================== +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.private + & filters.command(["kill", "die", "reboot"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_kill(app: Client, msg: Message): logWrite(f"Shutting down bot with pid {pid}") - await msg.reply_text(locale("shutdown", "message", locale=msg.from_user).format(pid), quote=should_quote(msg)) + await msg.reply_text( + locale("shutdown", "message", locale=msg.from_user).format(pid), + quote=should_quote(msg), + ) scheduler.shutdown() makedirs(configGet("cache", "locations"), exist_ok=True) - jsonSave({"timestamp": time()}, path.join(configGet("cache", "locations"), "shutdown_time")) + jsonSave( + {"timestamp": time()}, + path.join(configGet("cache", "locations"), "shutdown_time"), + ) exit() -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/resetcommands.py b/modules/commands/resetcommands.py index cf648a2..b5a962d 100644 --- a/modules/commands/resetcommands.py +++ b/modules/commands/resetcommands.py @@ -9,40 +9,65 @@ from modules import custom_filters pid = getpid() + # Reset commands command ======================================================================================================= -@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & filters.command(["resetcommands"], prefixes=["/"]) & custom_filters.admin) +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.private + & filters.command(["resetcommands"], prefixes=["/"]) + & custom_filters.admin +) async def cmd_resetcommands(app: Client, msg: Message): - if msg.from_user.id == configGet("owner"): - logWrite(f"Resetting all commands on owner's request") valid_locales = [] files_locales = listdir(f'{configGet("locale", "locations")}') - + for entry in files_locales: if entry.endswith(".json"): valid_locales.append(".".join(entry.split(".")[:-1])) - logWrite(f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")}', debug=True) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("admin", "groups"))) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("users", "groups"))) + logWrite( + f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")}', + debug=True, + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")) + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("users", "groups")) + ) for lc in valid_locales: try: - logWrite(f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")} [{lc}]', debug=True) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")), language_code=lc) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("users", "groups")), language_code=lc) + logWrite( + f'Resetting commands in groups {configGet("admin", "groups")} and {configGet("users", "groups")} [{lc}]', + debug=True, + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")), + language_code=lc, + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("users", "groups")), + language_code=lc, + ) except: pass for admin in configGet("admins"): try: - logWrite(f'Resetting commands for admin {admin}', debug=True) + logWrite(f"Resetting commands for admin {admin}", debug=True) await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin)) for lc in valid_locales: try: - logWrite(f'Resetting commands for admin {admin} [{lc}]', debug=True) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=admin), language_code=lc) + logWrite( + f"Resetting commands for admin {admin} [{lc}]", debug=True + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=admin), language_code=lc + ) except: pass except bad_request_400.PeerIdInvalid: @@ -51,21 +76,40 @@ async def cmd_resetcommands(app: Client, msg: Message): try: logWrite(f'Resetting commands for owner {configGet("owner")}', debug=True) for lc in valid_locales: - logWrite(f'Resetting commands for owner {configGet("owner")} [{lc}]', debug=True) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner")), language_code=lc) - await app.delete_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner"))) + logWrite( + f'Resetting commands for owner {configGet("owner")} [{lc}]', + debug=True, + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("owner")), + language_code=lc, + ) + await app.delete_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("owner")) + ) except bad_request_400.PeerIdInvalid: pass for lc in valid_locales: - logWrite(f'Resetting commands for locale {lc}', debug=True) - await app.delete_bot_commands(scope=BotCommandScopeDefault(), language_code=lc) + logWrite(f"Resetting commands for locale {lc}", debug=True) + await app.delete_bot_commands( + scope=BotCommandScopeDefault(), language_code=lc + ) - logWrite(f'Resetting default commands', debug=True) + logWrite(f"Resetting default commands", debug=True) await app.delete_bot_commands() await msg.reply_text("OK", quote=should_quote(msg)) logWrite(str(await app.get_bot_commands()), debug=True) - logWrite(str(await app.get_bot_commands(scope=BotCommandScopeChat(chat_id=configGet("owner")))), debug=True) -# ============================================================================================================================== \ No newline at end of file + logWrite( + str( + await app.get_bot_commands( + scope=BotCommandScopeChat(chat_id=configGet("owner")) + ) + ), + debug=True, + ) + + +# ============================================================================================================================== diff --git a/modules/commands/rules.py b/modules/commands/rules.py index 3ddc3b5..a7fe6fd 100644 --- a/modules/commands/rules.py +++ b/modules/commands/rules.py @@ -7,36 +7,55 @@ from modules.utils import locale from modules import custom_filters from classes.holo_user import HoloUser + class DefaultRulesMarkup(list): def __init__(self, language_code: Union[str, HoloUser, User, None]): super().__init__([]) self.keyboard = InlineKeyboardMarkup( [ [ - InlineKeyboardButton(locale("rules_home", "button", locale=language_code), callback_data="rules_home"), - InlineKeyboardButton(locale("rules_additional", "button", locale=language_code), callback_data="rules_additional") + InlineKeyboardButton( + locale("rules_home", "button", locale=language_code), + callback_data="rules_home", + ), + InlineKeyboardButton( + locale("rules_additional", "button", locale=language_code), + callback_data="rules_additional", + ), ], [ InlineKeyboardButton("1", callback_data="rule_1"), InlineKeyboardButton("2", callback_data="rule_2"), - InlineKeyboardButton("3", callback_data="rule_3") + InlineKeyboardButton("3", callback_data="rule_3"), ], [ InlineKeyboardButton("4", callback_data="rule_4"), InlineKeyboardButton("5", callback_data="rule_5"), - InlineKeyboardButton("6", callback_data="rule_6") + InlineKeyboardButton("6", callback_data="rule_6"), ], [ InlineKeyboardButton("7", callback_data="rule_7"), InlineKeyboardButton("8", callback_data="rule_8"), - InlineKeyboardButton("9", callback_data="rule_9") - ] + InlineKeyboardButton("9", callback_data="rule_9"), + ], ] ) # Rules command ============================================================================================================= -@app.on_message(custom_filters.enabled_general & ~filters.scheduled & filters.private & ~custom_filters.banned & filters.command(["rules"], prefixes=["/"])) +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.private + & ~custom_filters.banned + & filters.command(["rules"], prefixes=["/"]) +) async def cmd_rules(app: Client, msg: Message): - await msg.reply_text(locale("rules_msg", locale=msg.from_user), disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(msg.from_user).keyboard) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("rules_msg", locale=msg.from_user), + disable_web_page_preview=True, + reply_markup=DefaultRulesMarkup(msg.from_user).keyboard, + ) + + +# ============================================================================================================================== diff --git a/modules/commands/spoiler.py b/modules/commands/spoiler.py index b28429c..24d40ee 100644 --- a/modules/commands/spoiler.py +++ b/modules/commands/spoiler.py @@ -9,24 +9,30 @@ from modules.utils import locale from modules.database import col_spoilers, col_applications from modules import custom_filters -# Spoiler command ============================================================================================================== -@app.on_message(custom_filters.enabled_spoilers & ~filters.scheduled & filters.private & ~custom_filters.banned & filters.command(["spoiler"], prefixes=["/"])) -async def cmd_spoiler(app: Client, msg: Message): +# Spoiler command ============================================================================================================== +@app.on_message( + custom_filters.enabled_spoilers + & ~filters.scheduled + & filters.private + & ~custom_filters.banned + & filters.command(["spoiler"], prefixes=["/"]) +) +async def cmd_spoiler(app: Client, msg: Message): try: holo_user = HoloUser(msg.from_user) except (UserInvalidError, UserNotFoundError): return - if col_applications.find_one( {"user": holo_user.id} ) is None: - + if col_applications.find_one({"user": holo_user.id}) is None: await msg.reply_text(locale("not_member", "message", locale=msg.from_user)) return - if holo_user.application_state()[0] != "fill" and holo_user.sponsorship_state()[0] != "fill": - - if col_spoilers.find_one( {"user": holo_user.id, "completed": False} ) is None: - + if ( + holo_user.application_state()[0] != "fill" + and holo_user.sponsorship_state()[0] != "fill" + ): + if col_spoilers.find_one({"user": holo_user.id, "completed": False}) is None: col_spoilers.insert_one( { "user": holo_user.id, @@ -39,13 +45,24 @@ async def cmd_spoiler(app: Client, msg: Message): "animation": None, "document": None, "caption": None, - "text": None + "text": None, } ) - await msg.reply_text(locale("spoiler_started", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("spoiler_categories", "keyboard"), resize_keyboard=True, one_time_keyboard=True)) + await msg.reply_text( + locale("spoiler_started", "message", locale=msg.from_user), + reply_markup=ReplyKeyboardMarkup( + locale("spoiler_categories", "keyboard"), + resize_keyboard=True, + one_time_keyboard=True, + ), + ) logWrite(f"User {msg.from_user.id} started creating new spoiler") else: - await msg.reply_text(locale("spoiler_unfinished", "message", locale=msg.from_user)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("spoiler_unfinished", "message", locale=msg.from_user) + ) + + +# ============================================================================================================================== diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index 46cc05a..3856c39 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -7,17 +7,44 @@ from modules import custom_filters from modules.utils import locale, should_quote from modules.database import col_applications + # Sponsorship command ========================================================================================================== -@app.on_message(custom_filters.enabled_sponsorships & ~filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]) & ~custom_filters.banned & (custom_filters.allowed | custom_filters.admin)) +@app.on_message( + custom_filters.enabled_sponsorships + & ~filters.scheduled + & filters.command(["sponsorship"], prefixes=["/"]) + & ~custom_filters.banned + & (custom_filters.allowed | custom_filters.admin) +) async def cmd_sponsorship(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) if holo_user.application_state()[0] == "fill": - await msg.reply_text(locale("finish_application", "message", locale=msg.from_user), quote=should_quote(msg)) + await msg.reply_text( + locale("finish_application", "message", locale=msg.from_user), + quote=should_quote(msg), + ) return if holo_user.spoiler_state() is True: await msg.reply_text(locale("spoiler_in_progress", "message", locale=holo_user)) return - await msg.reply_text(locale("sponsorship_apply", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button", locale=msg.from_user)), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg)) + await msg.reply_text( + locale("sponsorship_apply", "message", locale=msg.from_user), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=str( + locale("sponsor_apply", "button", locale=msg.from_user) + ), + callback_data=f"sponsor_apply_{msg.from_user.id}", + ) + ] + ] + ), + quote=should_quote(msg), + ) # else: # await msg.reply_text(locale("sponsorship_application_empty", "message")) -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/start.py b/modules/commands/start.py index 0452507..6e9ea9d 100644 --- a/modules/commands/start.py +++ b/modules/commands/start.py @@ -8,42 +8,67 @@ from modules import custom_filters from bson.objectid import ObjectId from bson.errors import InvalidId -# Start command ================================================================================================================ -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"]) & ~custom_filters.banned) -async def cmd_start(app: Client, msg: Message): +# Start command ================================================================================================================ +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.private + & filters.command(["start"], prefixes=["/"]) + & ~custom_filters.banned +) +async def cmd_start(app: Client, msg: Message): user = col_users.find_one({"user": msg.from_user.id}) if user is None: - - col_users.insert_one({ - "user": msg.from_user.id, - "link": None, - "label": "", - "tg_name": msg.from_user.first_name, - "tg_phone": msg.from_user.phone_number, - "tg_locale": msg.from_user.language_code, - "tg_username": msg.from_user.username - }) + col_users.insert_one( + { + "user": msg.from_user.id, + "link": None, + "label": "", + "tg_name": msg.from_user.first_name, + "tg_phone": msg.from_user.phone_number, + "tg_locale": msg.from_user.language_code, + "tg_username": msg.from_user.username, + } + ) logWrite(f"User {msg.from_user.id} started bot interaction") - await msg.reply_text(locale("start", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("welcome", "keyboard", locale=msg.from_user), resize_keyboard=True)) + await msg.reply_text( + locale("start", "message", locale=msg.from_user), + reply_markup=ReplyKeyboardMarkup( + locale("welcome", "keyboard", locale=msg.from_user), + resize_keyboard=True, + ), + ) if len(msg.command) > 1: try: - spoiler = col_spoilers.find_one( {"_id": ObjectId(msg.command[1])} ) + spoiler = col_spoilers.find_one({"_id": ObjectId(msg.command[1])}) if spoiler["photo"] is not None: - await msg.reply_cached_media(spoiler["photo"], caption=spoiler["caption"]) + await msg.reply_cached_media( + spoiler["photo"], caption=spoiler["caption"] + ) if spoiler["video"] is not None: - await msg.reply_cached_media(spoiler["video"], caption=spoiler["caption"]) + await msg.reply_cached_media( + spoiler["video"], caption=spoiler["caption"] + ) if spoiler["audio"] is not None: - await msg.reply_cached_media(spoiler["audio"], caption=spoiler["caption"]) + await msg.reply_cached_media( + spoiler["audio"], caption=spoiler["caption"] + ) if spoiler["animation"] is not None: - await msg.reply_cached_media(spoiler["animation"], caption=spoiler["caption"]) + await msg.reply_cached_media( + spoiler["animation"], caption=spoiler["caption"] + ) if spoiler["document"] is not None: - await msg.reply_cached_media(spoiler["document"], caption=spoiler["caption"]) + await msg.reply_cached_media( + spoiler["document"], caption=spoiler["caption"] + ) if spoiler["text"] is not None: await msg.reply_text(spoiler["text"]) except InvalidId: await msg.reply_text(f"Got an invalid ID {msg.command[1]}") -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/commands/warn.py b/modules/commands/warn.py index 3482eaf..0c61908 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -7,16 +7,41 @@ from modules.utils import configGet, locale from modules.database import col_warnings from modules import custom_filters -# Warn command ================================================================================================================= -@app.on_message(custom_filters.enabled_warnings & ~filters.scheduled & filters.command(["warn"], prefixes=["/"]) & custom_filters.admin) -async def cmd_warn(app: Client, msg: Message): +# Warn command ================================================================================================================= +@app.on_message( + custom_filters.enabled_warnings + & ~filters.scheduled + & filters.command(["warn"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_warn(app: Client, msg: Message): if msg.chat.id == configGet("users", "groups"): if msg.reply_to_message_id != None: message = " ".join(msg.command[1:]) if len(msg.command) > 1 else "" - col_warnings.insert_one({"user": msg.reply_to_message.from_user.id, "admin": msg.from_user.id, "date": datetime.now(), "reason": message}) + col_warnings.insert_one( + { + "user": msg.reply_to_message.from_user.id, + "admin": msg.from_user.id, + "date": datetime.now(), + "reason": message, + } + ) if message == "": - await msg.reply_text(locale("warned", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id)) + await msg.reply_text( + locale("warned", "message").format( + msg.reply_to_message.from_user.first_name, + msg.reply_to_message.from_user.id, + ) + ) else: - await msg.reply_text(locale("warned_reason", "message").format(msg.reply_to_message.from_user.first_name, msg.reply_to_message.from_user.id, message)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("warned_reason", "message").format( + msg.reply_to_message.from_user.first_name, + msg.reply_to_message.from_user.id, + message, + ) + ) + + +# ============================================================================================================================== diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index a25e734..8c4d9f8 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -7,12 +7,20 @@ from modules.utils import configGet, locale, should_quote from modules.database import col_users, col_warnings from modules import custom_filters -# Warnings command ============================================================================================================= -@app.on_message(custom_filters.enabled_warnings & ~filters.scheduled & filters.command(["warnings"], prefixes=["/"]) & custom_filters.admin) -async def cmd_warnings(app: Client, msg: Message): +# Warnings command ============================================================================================================= +@app.on_message( + custom_filters.enabled_warnings + & ~filters.scheduled + & filters.command(["warnings"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_warnings(app: Client, msg: Message): if len(msg.command) <= 1: - await msg.reply_text(locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg)) + await msg.reply_text( + locale("syntax_warnings", "message", locale=msg.from_user), + quote=should_quote(msg), + ) return try: @@ -21,7 +29,11 @@ async def cmd_warnings(app: Client, msg: Message): target_name = user_db["tg_name"] except: list_of_users = [] - async for m in app.get_chat_members(configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): + async for m in app.get_chat_members( + configGet("users", "groups"), + filter=ChatMembersFilter.SEARCH, + query=msg.command[1], + ): list_of_users.append(m) if len(list_of_users) != 0: @@ -29,16 +41,37 @@ async def cmd_warnings(app: Client, msg: Message): target_name = target.first_name target_id = str(target.id) else: - await msg.reply_text(locale("no_user_warnings", "message", locale=msg.from_user).format(msg.command[1])) + await msg.reply_text( + locale("no_user_warnings", "message", locale=msg.from_user).format( + msg.command[1] + ) + ) return warns = len(list(col_warnings.find({"user": target_id}))) if warns == 0: - await msg.reply_text(locale("no_warnings", "message", locale=msg.from_user).format(target_name, target_id), quote=should_quote(msg)) + await msg.reply_text( + locale("no_warnings", "message", locale=msg.from_user).format( + target_name, target_id + ), + quote=should_quote(msg), + ) else: if warns <= 5: - await msg.reply_text(locale("warnings_1", "message", locale=msg.from_user).format(target_name, target_id, warns), quote=should_quote(msg)) + await msg.reply_text( + locale("warnings_1", "message", locale=msg.from_user).format( + target_name, target_id, warns + ), + quote=should_quote(msg), + ) else: - await msg.reply_text(locale("warnings_2", "message", locale=msg.from_user).format(target_name, target_id, warns), quote=should_quote(msg)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("warnings_2", "message", locale=msg.from_user).format( + target_name, target_id, warns + ), + quote=should_quote(msg), + ) + + +# ============================================================================================================================== diff --git a/modules/custom_filters.py b/modules/custom_filters.py index bc217cc..5680a84 100644 --- a/modules/custom_filters.py +++ b/modules/custom_filters.py @@ -12,44 +12,73 @@ from pyrogram.types import Message async def admin_func(_, __, msg: Message): return await isAnAdmin(msg.from_user.id) + async def member_func(_, __, msg: Message): - return True if (msg.from_user.id in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))) else False + return ( + True + if ( + msg.from_user.id + in jsonLoad(path.join(configGet("cache", "locations"), "group_members")) + ) + else False + ) + async def allowed_func(_, __, msg: Message): output = False - output = True if (col_applications.find_one({"user": msg.from_user.id}) is not None) else False - if path.exists(path.join(configGet("cache", "locations"), "group_members")) and (msg.from_user.id not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))): + output = ( + True + if (col_applications.find_one({"user": msg.from_user.id}) is not None) + else False + ) + if path.exists(path.join(configGet("cache", "locations"), "group_members")) and ( + msg.from_user.id + not in jsonLoad(path.join(configGet("cache", "locations"), "group_members")) + ): output = False return output async def banned_func(_, __, msg: Message): - return True if col_bans.find_one( {"user": msg.from_user.id} ) is not None else False + return True if col_bans.find_one({"user": msg.from_user.id}) is not None else False async def enabled_general_func(_, __, msg: Message): return configGet("enabled", "features", "general") + async def enabled_applications_func(_, __, msg: Message): return configGet("enabled", "features", "applications") + async def enabled_sponsorships_func(_, __, msg: Message): return configGet("enabled", "features", "sponsorships") + async def enabled_warnings_func(_, __, msg: Message): return configGet("enabled", "features", "warnings") + async def enabled_invites_check_func(_, __, msg: Message): return configGet("enabled", "features", "invites_check") + async def enabled_dinovoice_func(_, __, msg: Message): return configGet("enabled", "features", "dinovoice") + async def enabled_spoilers_func(_, __, msg: Message): return configGet("enabled", "features", "spoilers") + async def filling_sponsorship_func(_, __, msg: Message): - return True if col_tmp.find_one({"user": msg.from_user.id, "type": "sponsorship"}) is not None else False + return ( + True + if col_tmp.find_one({"user": msg.from_user.id, "type": "sponsorship"}) + is not None + else False + ) + admin = filters.create(admin_func) member = filters.create(member_func) @@ -65,4 +94,4 @@ enabled_invites_check = filters.create(enabled_invites_check_func) enabled_dinovoice = filters.create(enabled_dinovoice_func) enabled_spoilers = filters.create(enabled_spoilers_func) -filling_sponsorship = filters.create(filling_sponsorship_func) \ No newline at end of file +filling_sponsorship = filters.create(filling_sponsorship_func) diff --git a/modules/database.py b/modules/database.py index 94775e8..86e59f4 100644 --- a/modules/database.py +++ b/modules/database.py @@ -9,18 +9,16 @@ with open("config.json", "r", encoding="utf-8") as f: f.close() if db_config["user"] is not None and db_config["password"] is not None: - con_string = 'mongodb://{0}:{1}@{2}:{3}/{4}'.format( + con_string = "mongodb://{0}:{1}@{2}:{3}/{4}".format( db_config["user"], db_config["password"], db_config["host"], db_config["port"], - db_config["name"] + db_config["name"], ) else: - con_string = 'mongodb://{0}:{1}/{2}'.format( - db_config["host"], - db_config["port"], - db_config["name"] + con_string = "mongodb://{0}:{1}/{2}".format( + db_config["host"], db_config["port"], db_config["name"] ) db_client = MongoClient(con_string) @@ -28,7 +26,18 @@ db = db_client.get_database(name=db_config["name"]) collections = db.list_collection_names() -for collection in ["tmp", "bans", "users", "context", "youtube", "spoilers", "messages", "warnings", "applications", "sponsorships"]: +for collection in [ + "tmp", + "bans", + "users", + "context", + "youtube", + "spoilers", + "messages", + "warnings", + "applications", + "sponsorships", +]: if not collection in collections: db.create_collection(collection) @@ -43,4 +52,4 @@ col_warnings = db.get_collection("warnings") col_applications = db.get_collection("applications") col_sponsorships = db.get_collection("sponsorships") -col_applications.create_index([("application.3.location", GEOSPHERE)]) \ No newline at end of file +col_applications.create_index([("application.3.location", GEOSPHERE)]) diff --git a/modules/handlers/confirmation.py b/modules/handlers/confirmation.py index 51e82da..8448123 100644 --- a/modules/handlers/confirmation.py +++ b/modules/handlers/confirmation.py @@ -3,7 +3,13 @@ from dateutil.relativedelta import relativedelta from datetime import datetime from app import app from pyrogram import filters -from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton, ForceReply, Message +from pyrogram.types import ( + ReplyKeyboardRemove, + InlineKeyboardMarkup, + InlineKeyboardButton, + ForceReply, + Message, +) from pyrogram.client import Client from pyrogram.enums.parse_mode import ParseMode from classes.holo_user import HoloUser @@ -16,16 +22,30 @@ from modules import custom_filters confirmation_1 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_1.append(pattern[0][0]) -@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.private & filters.command(confirmation_1, prefixes=[""]) & ~custom_filters.banned) -async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "sponsorship", "unknown"] = "unknown"): + +@app.on_message( + (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) + & ~filters.scheduled + & filters.private + & filters.command(confirmation_1, prefixes=[""]) + & ~custom_filters.banned +) +async def confirm_yes( + app: Client, + msg: Message, + kind: Literal["application", "sponsorship", "unknown"] = "unknown", +): holo_user = HoloUser(msg.from_user) if configGet("enabled", "features", "applications") is True: - - if (kind == "application") or ((holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True)): - - tmp_application = col_tmp.find_one({"user": holo_user.id, "type": "application"}) + if (kind == "application") or ( + (holo_user.application_state()[0] == "fill") + and (holo_user.application_state()[1] is True) + ): + tmp_application = col_tmp.find_one( + {"user": holo_user.id, "type": "application"} + ) if tmp_application is None: logWrite(f"Application of {holo_user.id} is nowhere to be found.") @@ -34,73 +54,120 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s if tmp_application["sent"] is True: return - await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove()) + await msg.reply_text( + locale("application_sent", "message"), + reply_markup=ReplyKeyboardRemove(), + ) application_content = [] i = 1 - for question in tmp_application['application']: - + for question in tmp_application["application"]: if i == 2: - age = relativedelta(datetime.now(), tmp_application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta( + datetime.now(), tmp_application["application"]["2"] + ) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if tmp_application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}") + if tmp_application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']} ({tmp_application['application']['3']['adminName1']}, {tmp_application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application']['3']['name']} ({tmp_application['application']['3']['adminName1']}, {tmp_application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {tmp_application['application'][question]}" + ) + i += 1 - if tmp_application["reapply"] is True and col_applications.find_one({"user": holo_user.id}) is not None: + if ( + tmp_application["reapply"] is True + and col_applications.find_one({"user": holo_user.id}) is not None + ): await app.send_message( chat_id=configGet("admin", "groups"), - text=(locale("reapply_got", "message")).format(str(holo_user.id),msg.from_user.first_name, msg.from_user.username, "\n".join(application_content)), + text=(locale("reapply_got", "message")).format( + str(holo_user.id), + msg.from_user.first_name, + msg.from_user.username, + "\n".join(application_content), + ), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(text=str(locale("reapply_yes", "button")), callback_data=f"reapply_yes_{holo_user.id}") + InlineKeyboardButton( + text=str(locale("reapply_yes", "button")), + callback_data=f"reapply_yes_{holo_user.id}", + ) ], [ - InlineKeyboardButton(text=str(locale("reapply_no", "button")), callback_data=f"reapply_no_{holo_user.id}") - ] + InlineKeyboardButton( + text=str(locale("reapply_no", "button")), + callback_data=f"reapply_no_{holo_user.id}", + ) + ], ] - ) + ), ) else: await app.send_message( chat_id=configGet("admin", "groups"), - text=(locale("application_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(application_content)), + text=(locale("application_got", "message")).format( + str(holo_user.id), + msg.from_user.first_name, + msg.from_user.username, + "\n".join(application_content), + ), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(text=str(locale("sub_yes", "button")), callback_data=f"sub_yes_{holo_user.id}") + InlineKeyboardButton( + text=str(locale("sub_yes", "button")), + callback_data=f"sub_yes_{holo_user.id}", + ) ], [ - InlineKeyboardButton(text=str(locale("sub_no", "button")), callback_data=f"sub_no_{holo_user.id}") + InlineKeyboardButton( + text=str(locale("sub_no", "button")), + callback_data=f"sub_no_{holo_user.id}", + ) ], [ - InlineKeyboardButton(text=str(locale("sub_russian", "button")), callback_data=f"sub_russian_{holo_user.id}") - ] + InlineKeyboardButton( + text=str(locale("sub_russian", "button")), + callback_data=f"sub_russian_{holo_user.id}", + ) + ], ] - ) + ), ) - logWrite(f"User {holo_user.id} sent his application and it will now be reviewed") + logWrite( + f"User {holo_user.id} sent his application and it will now be reviewed" + ) - col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}}) + col_tmp.update_one( + {"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}} + ) return if configGet("enabled", "features", "sponsorships") is True: - - if (kind == "sponsorship") or ((holo_user.sponsorship_state()[0] == "fill") and (holo_user.sponsorship_state()[1] is True)): - - tmp_sponsorship = col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"}) + if (kind == "sponsorship") or ( + (holo_user.sponsorship_state()[0] == "fill") + and (holo_user.sponsorship_state()[1] is True) + ): + tmp_sponsorship = col_tmp.find_one( + {"user": holo_user.id, "type": "sponsorship"} + ) if tmp_sponsorship is None: logWrite(f"Sponsorship of {holo_user.id} is nowhere to be found.") @@ -109,58 +176,116 @@ async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "s if tmp_sponsorship["sent"] is True: return - await msg.reply_text(locale("sponsorship_sent", "message"), reply_markup=ReplyKeyboardRemove()) + await msg.reply_text( + locale("sponsorship_sent", "message"), + reply_markup=ReplyKeyboardRemove(), + ) sponsorship_content = [] - for question in tmp_sponsorship['sponsorship']: - + for question in tmp_sponsorship["sponsorship"]: if question == "expires": - sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question].strftime('%d.%m.%Y')}") + sponsorship_content.append( + f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question].strftime('%d.%m.%Y')}" + ) elif question == "proof": continue else: - sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}") - - await app.send_cached_media(configGet("admin", "groups"), tmp_sponsorship["sponsorship"]["proof"], caption=(locale("sponsor_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.username, "\n".join(sponsorship_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup( + sponsorship_content.append( + f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}" + ) + + await app.send_cached_media( + configGet("admin", "groups"), + tmp_sponsorship["sponsorship"]["proof"], + caption=(locale("sponsor_got", "message")).format( + str(holo_user.id), + msg.from_user.first_name, + msg.from_user.username, + "\n".join(sponsorship_content), + ), + parse_mode=ParseMode.MARKDOWN, + reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(text=str(locale("sponsor_yes", "button")), callback_data=f"sponsor_yes_{holo_user.id}") + InlineKeyboardButton( + text=str(locale("sponsor_yes", "button")), + callback_data=f"sponsor_yes_{holo_user.id}", + ) ], [ - InlineKeyboardButton(text=str(locale("sponsor_no", "button")), callback_data=f"sponsor_no_{holo_user.id}") - ] + InlineKeyboardButton( + text=str(locale("sponsor_no", "button")), + callback_data=f"sponsor_no_{holo_user.id}", + ) + ], ] - ) + ), ) # remove(f"tmp{sep}{filename}.jpg") - logWrite(f"User {holo_user.id} sent his sponsorship application and it will now be reviewed") + logWrite( + f"User {holo_user.id} sent his sponsorship application and it will now be reviewed" + ) - col_tmp.update_one({"user": holo_user.id, "type": "sponsorship"}, {"$set": {"sent": True}}) + col_tmp.update_one( + {"user": holo_user.id, "type": "sponsorship"}, {"$set": {"sent": True}} + ) return + confirmation_2 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_2.append(pattern[1][0]) -@app.on_message((custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled & filters.private & filters.command(confirmation_2, prefixes=[""]) & ~custom_filters.banned) -async def confirm_no(app: Client, msg: Message, kind: Literal["application", "sponsorship", "unknown"] = "unknown"): + +@app.on_message( + (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) + & ~filters.scheduled + & filters.private + & filters.command(confirmation_2, prefixes=[""]) + & ~custom_filters.banned +) +async def confirm_no( + app: Client, + msg: Message, + kind: Literal["application", "sponsorship", "unknown"] = "unknown", +): holo_user = HoloUser(msg.from_user) if configGet("enabled", "features", "applications") is True: - if (kind == "application") or ((holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True)): + if (kind == "application") or ( + (holo_user.application_state()[0] == "fill") + and (holo_user.application_state()[1] is True) + ): holo_user.application_restart() await welcome_pass(app, msg, once_again=True) - logWrite(f"User {msg.from_user.id} restarted the application due to typo in it") + logWrite( + f"User {msg.from_user.id} restarted the application due to typo in it" + ) return if configGet("enabled", "features", "sponsorships") is True: - if (kind == "sponsorship") or ((holo_user.sponsorship_state()[0] == "fill") and (holo_user.sponsorship_state()[1] is True)): + if (kind == "sponsorship") or ( + (holo_user.sponsorship_state()[0] == "fill") + and (holo_user.sponsorship_state()[1] is True) + ): holo_user.sponsorship_restart() - await app.send_message(holo_user.id, locale(f"sponsor1", "message", locale=holo_user.locale), reply_markup=ForceReply(placeholder=str(locale(f"sponsor1", "force_reply", locale=holo_user.locale)))) - logWrite(f"User {msg.from_user.id} restarted the sponsorship application due to typo in it") + await app.send_message( + holo_user.id, + locale(f"sponsor1", "message", locale=holo_user.locale), + reply_markup=ForceReply( + placeholder=str( + locale(f"sponsor1", "force_reply", locale=holo_user.locale) + ) + ), + ) + logWrite( + f"User {msg.from_user.id} restarted the sponsorship application due to typo in it" + ) return -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/handlers/contact.py b/modules/handlers/contact.py index 1a75fef..8cb5d5c 100644 --- a/modules/handlers/contact.py +++ b/modules/handlers/contact.py @@ -9,46 +9,79 @@ from modules.database import col_applications from classes.holo_user import HoloUser from modules import custom_filters -# Contact getting ============================================================================================================== -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.contact & filters.private & (custom_filters.allowed | custom_filters.admin) & ~custom_filters.banned) -async def get_contact(app: Client, msg: Message): +# Contact getting ============================================================================================================== +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.contact + & filters.private + & (custom_filters.allowed | custom_filters.admin) + & ~custom_filters.banned +) +async def get_contact(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) if msg.contact.user_id != None: - application = col_applications.find_one({"user": msg.contact.user_id}) if application is None: - logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists") - await msg.reply_text(locale("contact_invalid", "message", locale=holo_user.locale)) + logWrite( + f"User {holo_user.id} requested application of {msg.contact.user_id} but user does not exists" + ) + await msg.reply_text( + locale("contact_invalid", "message", locale=holo_user.locale) + ) return application_content = [] i = 1 - for question in application['application']: - + for question in application["application"]: if i == 2: - age = relativedelta(datetime.now(), application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta(datetime.now(), application["application"]["2"]) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']}") + if application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application'][question]}" + ) + i += 1 - application_status = locale("application_status_accepted", "message", locale=holo_user.locale).format((await app.get_users(application["admin"])).first_name, application["date"].strftime("%d.%m.%Y, %H:%M")) + application_status = locale( + "application_status_accepted", "message", locale=holo_user.locale + ).format( + (await app.get_users(application["admin"])).first_name, + application["date"].strftime("%d.%m.%Y, %H:%M"), + ) logWrite(f"User {holo_user.id} requested application of {msg.contact.user_id}") - await msg.reply_text(locale("contact", "message", locale=holo_user.locale).format(str(msg.contact.user_id), "\n".join(application_content), application_status)) - + await msg.reply_text( + locale("contact", "message", locale=holo_user.locale).format( + str(msg.contact.user_id), + "\n".join(application_content), + application_status, + ) + ) else: - logWrite(f"User {holo_user.id} requested application of someone but user is not telegram user") - await msg.reply_text(locale("contact_not_member", "message", locale=holo_user.locale)) -# ============================================================================================================================== \ No newline at end of file + logWrite( + f"User {holo_user.id} requested application of someone but user is not telegram user" + ) + await msg.reply_text( + locale("contact_not_member", "message", locale=holo_user.locale) + ) + + +# ============================================================================================================================== diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index 9cc5f0c..65c9f03 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -3,35 +3,55 @@ from app import app, isAnAdmin import asyncio from ftfy import fix_text from pyrogram import filters -from pyrogram.types import Message, ForceReply, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove +from pyrogram.types import ( + Message, + ForceReply, + InlineKeyboardMarkup, + InlineKeyboardButton, + ReplyKeyboardRemove, +) from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import configGet, logWrite, locale, all_locales from modules.database import col_messages, col_spoilers from modules import custom_filters + async def message_involved(msg: Message) -> bool: - message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id}) + message = col_messages.find_one( + { + "destination.id": msg.reply_to_message.id, + "destination.chat": msg.reply_to_message.chat.id, + } + ) if message is not None: return True return False + async def message_context(msg: Message) -> tuple: - message = col_messages.find_one({"destination.id": msg.reply_to_message.id, "destination.chat": msg.reply_to_message.chat.id}) + message = col_messages.find_one( + { + "destination.id": msg.reply_to_message.id, + "destination.chat": msg.reply_to_message.chat.id, + } + ) if message is not None: return message["origin"]["chat"], message["origin"]["id"] return 0, 0 + # Any other input ============================================================================================================== -@app.on_message(~ filters.scheduled & (filters.private | filters.chat(configGet("admin", "groups"))) & ~custom_filters.banned) +@app.on_message( + ~filters.scheduled + & (filters.private | filters.chat(configGet("admin", "groups"))) + & ~custom_filters.banned +) async def any_stage(app: Client, msg: Message): - if msg.via_bot is None: - holo_user = HoloUser(msg.from_user) if (msg.reply_to_message is not None) and (await message_involved(msg)): - context = await message_context(msg) context_message = await app.get_messages(context[0], context[1]) @@ -51,7 +71,7 @@ async def any_stage(app: Client, msg: Message): animation=msg.animation, voice=msg.voice, adm_origin=await isAnAdmin(context_message.from_user.id), - adm_context=await isAnAdmin(msg.from_user.id) + adm_context=await isAnAdmin(msg.from_user.id), ) return @@ -60,29 +80,30 @@ async def any_stage(app: Client, msg: Message): return if msg.text is not None: - if configGet("enabled", "features", "applications") is True: await holo_user.application_next(str(msg.text), msg=msg) - + if configGet("enabled", "features", "sponsorships") is True: - await holo_user.sponsorship_next(str(msg.text), msg) if msg.photo is not None: await holo_user.sponsorship_next(str(msg.text), msg=msg, photo=msg.photo) - - if holo_user.application_state()[0] != "fill" and holo_user.sponsorship_state()[0] != "fill": + if ( + holo_user.application_state()[0] != "fill" + and holo_user.sponsorship_state()[0] != "fill" + ): if configGet("enabled", "features", "spoilers") is False: return - spoiler = col_spoilers.find_one( {"user": msg.from_user.id, "completed": False} ) + spoiler = col_spoilers.find_one( + {"user": msg.from_user.id, "completed": False} + ) if spoiler is None: return if spoiler["category"] is None: - found = False # Find category in all locales @@ -93,86 +114,226 @@ async def any_stage(app: Client, msg: Message): category = key if found is False: - await msg.reply_text(locale("spoiler_incorrect_category", "message", locale=msg.from_user)) + await msg.reply_text( + locale( + "spoiler_incorrect_category", + "message", + locale=msg.from_user, + ) + ) return - col_spoilers.find_one_and_update( {"_id": spoiler["_id"]}, {"$set": {"category": category}} ) - await msg.reply_text(locale("spoiler_send_description", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user))) + col_spoilers.find_one_and_update( + {"_id": spoiler["_id"]}, {"$set": {"category": category}} + ) + await msg.reply_text( + locale("spoiler_send_description", "message", locale=msg.from_user), + reply_markup=ForceReply( + placeholder=locale( + "spoiler_description", "force_reply", locale=msg.from_user + ) + ), + ) return - if spoiler["description"] is None and (spoiler["photo"] is None and spoiler["video"] is None and spoiler["audio"] is None and spoiler["animation"] is None and spoiler["text"] is None): - + if spoiler["description"] is None and ( + spoiler["photo"] is None + and spoiler["video"] is None + and spoiler["audio"] is None + and spoiler["animation"] is None + and spoiler["text"] is None + ): # for lc in all_locales("spoiler_description", "keyboard"): # if msg.text == lc[-1][0]: # await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user))) # return - if str(msg.text) != "-": msg.text = fix_text(str(msg.text)) if len(str(msg.text)) > 1024: - await msg.reply_text(locale("spoiler_description_too_long", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user))) + await msg.reply_text( + locale( + "spoiler_description_too_long", + "message", + locale=msg.from_user, + ), + reply_markup=ForceReply( + placeholder=locale( + "spoiler_description", + "force_reply", + locale=msg.from_user, + ) + ), + ) return - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": msg.text}} ) + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + {"$set": {"description": msg.text}}, + ) else: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"description": ""}} ) + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + {"$set": {"description": ""}}, + ) - logWrite(f"Adding description '{str(msg.text)}' to {msg.from_user.id}'s spoiler") - await msg.reply_text(locale("spoiler_using_description", "message", locale=msg.from_user).format(msg.text), reply_markup=ForceReply(placeholder=locale("spoiler_content", "force_reply", locale=msg.from_user))) + logWrite( + f"Adding description '{str(msg.text)}' to {msg.from_user.id}'s spoiler" + ) + await msg.reply_text( + locale( + "spoiler_using_description", "message", locale=msg.from_user + ).format(msg.text), + reply_markup=ForceReply( + placeholder=locale( + "spoiler_content", "force_reply", locale=msg.from_user + ) + ), + ) return ready = False if msg.photo is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"photo": msg.photo.file_id, "caption": msg.caption, "completed": True}} ) - logWrite(f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + { + "$set": { + "photo": msg.photo.file_id, + "caption": msg.caption, + "completed": True, + } + }, + ) + logWrite( + f"Adding photo with id {msg.photo.file_id} to {msg.from_user.id}'s spoiler" + ) ready = True if msg.video is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"video": msg.video.file_id, "caption": msg.caption, "completed": True}} ) - logWrite(f"Adding audio with id {msg.video.file_id} to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + { + "$set": { + "video": msg.video.file_id, + "caption": msg.caption, + "completed": True, + } + }, + ) + logWrite( + f"Adding audio with id {msg.video.file_id} to {msg.from_user.id}'s spoiler" + ) ready = True if msg.audio is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"audio": msg.audio.file_id, "caption": msg.caption, "completed": True}} ) - logWrite(f"Adding video with id {msg.audio.file_id} to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + { + "$set": { + "audio": msg.audio.file_id, + "caption": msg.caption, + "completed": True, + } + }, + ) + logWrite( + f"Adding video with id {msg.audio.file_id} to {msg.from_user.id}'s spoiler" + ) ready = True if msg.animation is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"animation": msg.animation.file_id, "caption": msg.caption, "completed": True}} ) - logWrite(f"Adding animation with id {msg.animation.file_id} to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + { + "$set": { + "animation": msg.animation.file_id, + "caption": msg.caption, + "completed": True, + } + }, + ) + logWrite( + f"Adding animation with id {msg.animation.file_id} to {msg.from_user.id}'s spoiler" + ) ready = True if msg.document is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"document": msg.document.file_id, "caption": msg.caption, "completed": True}} ) - logWrite(f"Adding document with id {msg.document.file_id} to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + { + "$set": { + "document": msg.document.file_id, + "caption": msg.caption, + "completed": True, + } + }, + ) + logWrite( + f"Adding document with id {msg.document.file_id} to {msg.from_user.id}'s spoiler" + ) ready = True - if spoiler["photo"] is None and spoiler["video"] is None and spoiler["audio"] is None and spoiler["animation"] is None and spoiler["document"] is None and spoiler["text"] is None: + if ( + spoiler["photo"] is None + and spoiler["video"] is None + and spoiler["audio"] is None + and spoiler["animation"] is None + and spoiler["document"] is None + and spoiler["text"] is None + ): if msg.text is not None: - col_spoilers.find_one_and_update( {"user": msg.from_user.id, "completed": False}, {"$set": {"text": str(msg.text), "completed": True}} ) - logWrite(f"Adding text '{str(msg.text)}' to {msg.from_user.id}'s spoiler") + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + {"$set": {"text": str(msg.text), "completed": True}}, + ) + logWrite( + f"Adding text '{str(msg.text)}' to {msg.from_user.id}'s spoiler" + ) ready = True if ready is True: - await msg.reply_text(locale("spoiler_ready", "message", locale=msg.from_user), reply_markup=ReplyKeyboardRemove()) + await msg.reply_text( + locale("spoiler_ready", "message", locale=msg.from_user), + reply_markup=ReplyKeyboardRemove(), + ) if configGet("allow_external", "features", "spoilers") is True: await msg.reply_text( locale("spoiler_send", "message", locale=msg.from_user), reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(locale("spoiler_preview", "button", locale=msg.from_user), callback_data=f"sid_{spoiler['_id'].__str__()}") + InlineKeyboardButton( + locale( + "spoiler_preview", + "button", + locale=msg.from_user, + ), + callback_data=f"sid_{spoiler['_id'].__str__()}", + ) ], [ - InlineKeyboardButton(locale("spoiler_send_chat", "button", locale=msg.from_user), callback_data=f"shc_{spoiler['_id'].__str__()}") + InlineKeyboardButton( + locale( + "spoiler_send_chat", + "button", + locale=msg.from_user, + ), + callback_data=f"shc_{spoiler['_id'].__str__()}", + ) ], [ - InlineKeyboardButton(locale("spoiler_send_other", "button", locale=msg.from_user), switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}") - ] + InlineKeyboardButton( + locale( + "spoiler_send_other", + "button", + locale=msg.from_user, + ), + switch_inline_query=f"spoiler:{spoiler['_id'].__str__()}", + ) + ], ] - ) + ), ) else: await msg.reply_text( @@ -180,33 +341,65 @@ async def any_stage(app: Client, msg: Message): reply_markup=InlineKeyboardMarkup( [ [ - InlineKeyboardButton(locale("spoiler_preview", "button", locale=msg.from_user), callback_data=f"sid_{spoiler['_id'].__str__()}") + InlineKeyboardButton( + locale( + "spoiler_preview", + "button", + locale=msg.from_user, + ), + callback_data=f"sid_{spoiler['_id'].__str__()}", + ) ], [ - InlineKeyboardButton(locale("spoiler_send_chat", "button", locale=msg.from_user), callback_data=f"shc_{spoiler['_id'].__str__()}") - ] + InlineKeyboardButton( + locale( + "spoiler_send_chat", + "button", + locale=msg.from_user, + ), + callback_data=f"shc_{spoiler['_id'].__str__()}", + ) + ], ] - ) + ), ) else: - await msg.reply_text(locale("spoiler_incorrect_content", "message", locale=msg.from_user)) + await msg.reply_text( + locale("spoiler_incorrect_content", "message", locale=msg.from_user) + ) -@app.on_message(~ filters.scheduled & filters.group) +@app.on_message(~filters.scheduled & filters.group) async def message_in_group(app: Client, msg: Message): if (msg.chat is not None) and (msg.via_bot is not None): - if (msg.via_bot.id == (await app.get_me()).id) and (msg.chat.id == configGet("users", "groups")): - if str(msg.text).startswith(locale("spoiler_described", "message").split()[0]) or str(msg.text).startswith(locale("spoiler_empty", "message").split()[0]): + if (msg.via_bot.id == (await app.get_me()).id) and ( + msg.chat.id == configGet("users", "groups") + ): + if str(msg.text).startswith( + locale("spoiler_described", "message").split()[0] + ) or str(msg.text).startswith( + locale("spoiler_empty", "message").split()[0] + ): logWrite(f"User {msg.from_user.id} sent spoiler to user's group") try: logWrite("Forwarding spoiler to admin's group") - await msg.copy(configGet("admin", "groups"), disable_notification=True) + await msg.copy( + configGet("admin", "groups"), disable_notification=True + ) except Exception as exp: - logWrite(f"Could not forward spoiler to admin's group due to '{exp}': {print_exc()}") + logWrite( + f"Could not forward spoiler to admin's group due to '{exp}': {print_exc()}" + ) return if configGet("remove_application_time") > 0: - logWrite(f"User {msg.from_user.id} requested application in destination group, removing in {configGet('remove_application_time')} minutes") - await asyncio.sleep(configGet("remove_application_time")*60) + logWrite( + f"User {msg.from_user.id} requested application in destination group, removing in {configGet('remove_application_time')} minutes" + ) + await asyncio.sleep(configGet("remove_application_time") * 60) await msg.delete() - logWrite(f"Removed application requested by {msg.from_user.id} in destination group") -# ============================================================================================================================== \ No newline at end of file + logWrite( + f"Removed application requested by {msg.from_user.id} in destination group" + ) + + +# ============================================================================================================================== diff --git a/modules/handlers/group_join.py b/modules/handlers/group_join.py index 5786b4b..70647eb 100644 --- a/modules/handlers/group_join.py +++ b/modules/handlers/group_join.py @@ -1,6 +1,11 @@ from datetime import datetime from app import app, isAnAdmin -from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton, ChatMemberUpdated +from pyrogram.types import ( + ChatPermissions, + InlineKeyboardMarkup, + InlineKeyboardButton, + ChatMemberUpdated, +) from pyrogram.client import Client from modules.utils import configGet, locale from modules import custom_filters @@ -9,45 +14,64 @@ from modules.database import col_applications from classes.holo_user import HoloUser from dateutil.relativedelta import relativedelta + # Filter users on join ========================================================================================================= -@app.on_chat_member_updated(custom_filters.enabled_invites_check, group=configGet("users", "groups")) -#@app.on_message(filters.new_chat_members, group=configGet("users", "groups")) +@app.on_chat_member_updated( + custom_filters.enabled_invites_check, group=configGet("users", "groups") +) +# @app.on_message(filters.new_chat_members, group=configGet("users", "groups")) async def filter_join(app: Client, member: ChatMemberUpdated): - if member.invite_link != None: - holo_user = HoloUser(member.from_user) - if (holo_user.link is not None) and (holo_user.link == member.invite_link.invite_link): - - logWrite(f"User {holo_user.id} joined destination group with correct link {holo_user.link}") + if (holo_user.link is not None) and ( + holo_user.link == member.invite_link.invite_link + ): + logWrite( + f"User {holo_user.id} joined destination group with correct link {holo_user.link}" + ) application = col_applications.find_one({"user": holo_user.id}) application_content = [] i = 1 - for question in application['application']: - + for question in application["application"]: if i == 2: - age = relativedelta(datetime.now(), application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta(datetime.now(), application["application"]["2"]) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}") + if application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}" + ) + i += 1 - await app.send_message(configGet("users", "groups"), locale("joined_application", "message").format(member.from_user.first_name, member.from_user.username, "\n".join(application_content))) + await app.send_message( + configGet("users", "groups"), + locale("joined_application", "message").format( + member.from_user.first_name, + member.from_user.username, + "\n".join(application_content), + ), + ) return - + if await isAnAdmin(member.invite_link.creator.id): - - logWrite(f"User {holo_user.id} joined destination group with link {holo_user.link} of an admin {member.invite_link.creator.id}") + logWrite( + f"User {holo_user.id} joined destination group with link {holo_user.link} of an admin {member.invite_link.creator.id}" + ) application = col_applications.find_one({"user": holo_user.id}) @@ -57,42 +81,75 @@ async def filter_join(app: Client, member: ChatMemberUpdated): application_content = [] i = 1 - for question in application['application']: - + for question in application["application"]: if i == 2: - age = relativedelta(datetime.now(), application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta(datetime.now(), application["application"]["2"]) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}") + if application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles')} {application['application'][question]}" + ) + i += 1 - await app.send_message(configGet("users", "groups"), locale("joined_application", "message").format(member.from_user.first_name, member.from_user.username, "\n".join(application_content))) + await app.send_message( + configGet("users", "groups"), + locale("joined_application", "message").format( + member.from_user.first_name, + member.from_user.username, + "\n".join(application_content), + ), + ) return - logWrite(f"User {holo_user.id} joined destination group with stolen/unapproved link {holo_user.link}") + logWrite( + f"User {holo_user.id} joined destination group with stolen/unapproved link {holo_user.link}" + ) - await app.send_message(configGet("admin", "groups"), locale("joined_false_link", "message").format(member.from_user.first_name, member.from_user.id), reply_markup=InlineKeyboardMarkup( - [ + await app.send_message( + configGet("admin", "groups"), + locale("joined_false_link", "message").format( + member.from_user.first_name, member.from_user.id + ), + reply_markup=InlineKeyboardMarkup( [ - InlineKeyboardButton(text=str(locale("sus_allow", "button")), callback_data=f"sus_allow_{member.from_user.id}") - ], - [ - InlineKeyboardButton(text=str(locale("sus_reject", "button")), callback_data=f"sus_reject_{member.from_user.id}") + [ + InlineKeyboardButton( + text=str(locale("sus_allow", "button")), + callback_data=f"sus_allow_{member.from_user.id}", + ) + ], + [ + InlineKeyboardButton( + text=str(locale("sus_reject", "button")), + callback_data=f"sus_reject_{member.from_user.id}", + ) + ], ] - ] - )) - await app.restrict_chat_member(member.chat.id, member.from_user.id, permissions=ChatPermissions( + ), + ) + await app.restrict_chat_member( + member.chat.id, + member.from_user.id, + permissions=ChatPermissions( can_send_messages=False, can_send_media_messages=False, can_send_other_messages=False, - can_send_polls=False - ) + can_send_polls=False, + ), ) -# ============================================================================================================================== \ No newline at end of file + + +# ============================================================================================================================== diff --git a/modules/handlers/voice.py b/modules/handlers/voice.py index abdb4ac..d1f0fc0 100644 --- a/modules/handlers/voice.py +++ b/modules/handlers/voice.py @@ -7,7 +7,13 @@ from modules.logging import logWrite from modules.utils import configGet, locale from modules import custom_filters -@app.on_message(custom_filters.enabled_dinovoice & ~filters.scheduled & filters.voice & filters.chat(configGet("users", "groups"))) + +@app.on_message( + custom_filters.enabled_dinovoice + & ~filters.scheduled + & filters.voice + & filters.chat(configGet("users", "groups")) +) async def voice_message(app: Client, msg: Message): logWrite(f"User {msg.from_user.id} sent voice message in destination group") - await msg.reply_text(choice(locale("voice_message", "message"))) \ No newline at end of file + await msg.reply_text(choice(locale("voice_message", "message"))) diff --git a/modules/handlers/welcome.py b/modules/handlers/welcome.py index 5b139d2..38347d0 100644 --- a/modules/handlers/welcome.py +++ b/modules/handlers/welcome.py @@ -12,15 +12,23 @@ for pattern in all_locales("welcome", "keyboard"): welcome_1.append(pattern[0][0]) for pattern in all_locales("return", "keyboard"): welcome_1.append(pattern[0][0]) -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(welcome_1, prefixes=[""]) & ~custom_filters.banned) + + +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.private + & filters.command(welcome_1, prefixes=[""]) + & ~custom_filters.banned +) async def welcome_pass(app: Client, msg: Message, once_again: bool = False) -> None: """Set user's stage to 1 and start a fresh application ### Args: - * app (app): Pyrogram Client to use + * app (app): Pyrogram Client to use * msg (Message): Message with .from_user.id attribute equal to the end-user ID whose application will be started * once_again (bool, optional): Set to False if it's the first time as user applies. Defaults to True. - """ + """ if not once_again: await msg.reply_text(locale("privacy_notice", "message")) @@ -29,19 +37,41 @@ async def welcome_pass(app: Client, msg: Message, once_again: bool = False) -> N if once_again is False: holo_user.application_restart() - + if once_again is True: logWrite(f"User {msg.from_user.id} confirmed starting the application") else: - logWrite(f"User {msg.from_user.id} confirmed starting the application once again") - await msg.reply_text(locale("question1", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("question1", "force_reply", locale=msg.from_user))) + logWrite( + f"User {msg.from_user.id} confirmed starting the application once again" + ) + await msg.reply_text( + locale("question1", "message", locale=msg.from_user), + reply_markup=ForceReply( + placeholder=locale("question1", "force_reply", locale=msg.from_user) + ), + ) + welcome_2 = [] for pattern in all_locales("welcome", "keyboard"): welcome_2.append(pattern[1][0]) -@app.on_message(custom_filters.enabled_applications & ~filters.scheduled & filters.private & filters.command(welcome_2, prefixes=[""]) & ~custom_filters.banned) -async def welcome_reject(app: Client, msg: Message): + +@app.on_message( + custom_filters.enabled_applications + & ~filters.scheduled + & filters.private + & filters.command(welcome_2, prefixes=[""]) + & ~custom_filters.banned +) +async def welcome_reject(app: Client, msg: Message): logWrite(f"User {msg.from_user.id} rejected to start the application") - await msg.reply_text(locale("goodbye", "message", locale=msg.from_user), reply_markup=ReplyKeyboardMarkup(locale("return", "keyboard", locale=msg.from_user), resize_keyboard=True)) -# ============================================================================================================================== \ No newline at end of file + await msg.reply_text( + locale("goodbye", "message", locale=msg.from_user), + reply_markup=ReplyKeyboardMarkup( + locale("return", "keyboard", locale=msg.from_user), resize_keyboard=True + ), + ) + + +# ============================================================================================================================== diff --git a/modules/inline.py b/modules/inline.py index c8ba27a..d06a798 100644 --- a/modules/inline.py +++ b/modules/inline.py @@ -4,7 +4,13 @@ all inline queries that bot receives""" from datetime import datetime from os import path, sep from app import app, isAnAdmin -from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent, InlineQuery, InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import ( + InlineQueryResultArticle, + InputTextMessageContent, + InlineQuery, + InlineKeyboardMarkup, + InlineKeyboardButton, +) from pyrogram.client import Client from pyrogram.enums.chat_type import ChatType from pyrogram.enums.chat_members_filter import ChatMembersFilter @@ -17,51 +23,95 @@ from modules.database import col_applications, col_spoilers from bson.objectid import ObjectId from bson.errors import InvalidId + @app.on_inline_query() async def inline_answer(client: Client, inline_query: InlineQuery): - results = [] if configGet("allow_external", "features", "spoilers") is True: - if inline_query.query.startswith("spoiler:"): - try: - - spoil = col_spoilers.find_one( {"_id": ObjectId(inline_query.query.removeprefix("spoiler:"))} ) + spoil = col_spoilers.find_one( + {"_id": ObjectId(inline_query.query.removeprefix("spoiler:"))} + ) if spoil is not None: - - desc = locale("spoiler_empty", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories")) if spoil["description"] == "" else locale("spoiler_described", "message", locale=inline_query.from_user).format(locale(spoil["category"], "message", "spoiler_categories"), spoil["description"]) + desc = ( + locale( + "spoiler_empty", "message", locale=inline_query.from_user + ).format( + locale(spoil["category"], "message", "spoiler_categories") + ) + if spoil["description"] == "" + else locale( + "spoiler_described", + "message", + locale=inline_query.from_user, + ).format( + locale(spoil["category"], "message", "spoiler_categories"), + spoil["description"], + ) + ) results = [ InlineQueryResultArticle( - title=locale("title", "inline", "spoiler", locale=inline_query.from_user), - description=locale("description", "inline", "spoiler", locale=inline_query.from_user), - input_message_content=InputTextMessageContent(desc, disable_web_page_preview=True), - reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(locale("spoiler_view", "button", locale=inline_query.from_user), callback_data=f'sid_{inline_query.query.removeprefix("spoiler:")}')]]) + title=locale( + "title", + "inline", + "spoiler", + locale=inline_query.from_user, + ), + description=locale( + "description", + "inline", + "spoiler", + locale=inline_query.from_user, + ), + input_message_content=InputTextMessageContent( + desc, disable_web_page_preview=True + ), + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + locale( + "spoiler_view", + "button", + locale=inline_query.from_user, + ), + callback_data=f'sid_{inline_query.query.removeprefix("spoiler:")}', + ) + ] + ] + ), ) ] except InvalidId: results = [] - - await inline_query.answer( - results=results - ) + await inline_query.answer(results=results) return if inline_query.chat_type in [ChatType.CHANNEL]: await inline_query.answer( - results=[ - InlineQueryResultArticle( - title=locale("title", "inline", "not_pm", locale=inline_query.from_user), - input_message_content=InputTextMessageContent( - locale("message_content", "inline", "not_pm", locale=inline_query.from_user) - ), - description=locale("description", "inline", "not_pm", locale=inline_query.from_user) + results=[ + InlineQueryResultArticle( + title=locale( + "title", "inline", "not_pm", locale=inline_query.from_user + ), + input_message_content=InputTextMessageContent( + locale( + "message_content", + "inline", + "not_pm", + locale=inline_query.from_user, + ) + ), + description=locale( + "description", "inline", "not_pm", locale=inline_query.from_user + ), ) ] ) @@ -71,39 +121,59 @@ async def inline_answer(client: Client, inline_query: InlineQuery): InlineQueryResultArticle( title=locale("title", "inline", "forbidden", locale=inline_query.from_user), input_message_content=InputTextMessageContent( - locale("message_content", "inline", "forbidden", locale=inline_query.from_user) + locale( + "message_content", + "inline", + "forbidden", + locale=inline_query.from_user, + ) + ), + description=locale( + "description", "inline", "forbidden", locale=inline_query.from_user ), - description=locale("description", "inline", "forbidden", locale=inline_query.from_user) ) ] try: holo_user = HoloUser(inline_query.from_user) except (UserNotFoundError, UserInvalidError): - logWrite(f"Could not find application of {inline_query.from_user.id}, ignoring inline query", debug=True) - await inline_query.answer( - results=results_forbidden + logWrite( + f"Could not find application of {inline_query.from_user.id}, ignoring inline query", + debug=True, ) + await inline_query.answer(results=results_forbidden) return - if path.exists(path.join(configGet("cache", "locations"), "group_members")) and (inline_query.from_user.id not in jsonLoad(path.join(configGet("cache", "locations"), "group_members"))): - if path.exists(path.join(configGet("cache", "locations"), "admins")) and (inline_query.from_user.id not in jsonLoad(path.join(configGet("cache", "locations"), "admins"))): - logWrite(f"{inline_query.from_user.id} is not an admin and not in members group, ignoring inline query", debug=True) - await inline_query.answer( - results=results_forbidden + if path.exists(path.join(configGet("cache", "locations"), "group_members")) and ( + inline_query.from_user.id + not in jsonLoad(path.join(configGet("cache", "locations"), "group_members")) + ): + if path.exists(path.join(configGet("cache", "locations"), "admins")) and ( + inline_query.from_user.id + not in jsonLoad(path.join(configGet("cache", "locations"), "admins")) + ): + logWrite( + f"{inline_query.from_user.id} is not an admin and not in members group, ignoring inline query", + debug=True, ) + await inline_query.answer(results=results_forbidden) return if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True): - - max_results = configGet("inline_preview_count") if inline_query.query != "" else 200 + max_results = ( + configGet("inline_preview_count") if inline_query.query != "" else 200 + ) list_of_users = [] - async for m in app.get_chat_members(configGet("users", "groups"), limit=max_results, filter=ChatMembersFilter.SEARCH, query=inline_query.query): + async for m in app.get_chat_members( + configGet("users", "groups"), + limit=max_results, + filter=ChatMembersFilter.SEARCH, + query=inline_query.query, + ): list_of_users.append(m) for match in list_of_users: - application = col_applications.find_one({"user": match.user.id}) if application is None: @@ -112,34 +182,63 @@ async def inline_answer(client: Client, inline_query: InlineQuery): application_content = [] i = 1 - for question in application['application']: - + for question in application["application"]: if i == 2: - age = relativedelta(datetime.now(), application['application']['2']) - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + age = relativedelta(datetime.now(), application["application"]["2"]) + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)" + ) elif i == 3: - if application['application']['3']['countryCode'] == "UA": - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']}") + if application["application"]["3"]["countryCode"] == "UA": + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']}" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})") + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application']['3']['name']} ({application['application']['3']['adminName1']}, {application['application']['3']['countryName']})" + ) else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application'][question]}") - + application_content.append( + f"{locale(f'question{i}', 'message', 'question_titles', locale=inline_query.from_user)} {application['application'][question]}" + ) + i += 1 if match.user.photo != None: try: - if not path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}'): - print(f'Downloaded avatar {match.user.photo.big_file_id} of {match.user.id} and uploaded to {configGet("api")}/?avatar_id={match.user.photo.big_file_id}', flush=True) - await app.download_media(match.user.photo.big_file_id, file_name=f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}') + if not path.exists( + f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}' + ): + print( + f'Downloaded avatar {match.user.photo.big_file_id} of {match.user.id} and uploaded to {configGet("api")}/?avatar_id={match.user.photo.big_file_id}', + flush=True, + ) + await app.download_media( + match.user.photo.big_file_id, + file_name=f'{configGet("cache", "locations")}{sep}avatars{sep}{match.user.photo.big_file_id}', + ) results.append( InlineQueryResultArticle( title=str(match.user.first_name), input_message_content=InputTextMessageContent( - locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content)) + locale( + "message_content", + "inline", + "user", + locale=inline_query.from_user, + ).format( + match.user.first_name, + match.user.username, + "\n".join(application_content), + ) ), - description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username), - thumb_url=f'{configGet("api")}/?avatar_id={match.user.photo.big_file_id}' + description=locale( + "description", + "inline", + "user", + locale=inline_query.from_user, + ).format(match.user.first_name, match.user.username), + thumb_url=f'{configGet("api")}/?avatar_id={match.user.photo.big_file_id}', ) ) except ValueError: @@ -147,9 +246,23 @@ async def inline_answer(client: Client, inline_query: InlineQuery): InlineQueryResultArticle( title=str(match.user.first_name), input_message_content=InputTextMessageContent( - locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content)) + locale( + "message_content", + "inline", + "user", + locale=inline_query.from_user, + ).format( + match.user.first_name, + match.user.username, + "\n".join(application_content), + ) ), - description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username) + description=locale( + "description", + "inline", + "user", + locale=inline_query.from_user, + ).format(match.user.first_name, match.user.username), ) ) except FileNotFoundError: @@ -157,9 +270,23 @@ async def inline_answer(client: Client, inline_query: InlineQuery): InlineQueryResultArticle( title=str(match.user.first_name), input_message_content=InputTextMessageContent( - locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content)) + locale( + "message_content", + "inline", + "user", + locale=inline_query.from_user, + ).format( + match.user.first_name, + match.user.username, + "\n".join(application_content), + ) ), - description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username) + description=locale( + "description", + "inline", + "user", + locale=inline_query.from_user, + ).format(match.user.first_name, match.user.username), ) ) else: @@ -167,14 +294,24 @@ async def inline_answer(client: Client, inline_query: InlineQuery): InlineQueryResultArticle( title=str(match.user.first_name), input_message_content=InputTextMessageContent( - locale("message_content", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username, "\n".join(application_content)) + locale( + "message_content", + "inline", + "user", + locale=inline_query.from_user, + ).format( + match.user.first_name, + match.user.username, + "\n".join(application_content), + ) ), - description=locale("description", "inline", "user", locale=inline_query.from_user).format(match.user.first_name, match.user.username) + description=locale( + "description", + "inline", + "user", + locale=inline_query.from_user, + ).format(match.user.first_name, match.user.username), ) ) - await inline_query.answer( - results=results, - cache_time=10, - is_personal=True - ) \ No newline at end of file + await inline_query.answer(results=results, cache_time=10, is_personal=True) diff --git a/modules/logging.py b/modules/logging.py index 9314727..030bca2 100644 --- a/modules/logging.py +++ b/modules/logging.py @@ -5,19 +5,20 @@ from shutil import copyfileobj from datetime import datetime -with open(getcwd()+path.sep+"config.json", "r", encoding='utf8') as file: +with open(getcwd() + path.sep + "config.json", "r", encoding="utf8") as file: json_contents = loads(file.read()) log_size = json_contents["logging"]["size"] log_folder = json_contents["logging"]["location"] file.close() + # Check latest log size def checkSize(debug=False): """Check size of latest.log file and rotate it if needed ### Args: * debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`. - """ + """ global log_folder @@ -30,15 +31,24 @@ def checkSize(debug=False): makedirs(log_folder, exist_ok=True) log = stat(path.join(log_folder, log_file)) if (log.st_size / 1024) > log_size: - with open(path.join(log_folder, log_file), 'rb') as f_in: - with gzipopen(path.join(log_folder, f'{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.log.gz'), 'wb') as f_out: + with open(path.join(log_folder, log_file), "rb") as f_in: + with gzipopen( + path.join( + log_folder, + f'{datetime.now().strftime("%d.%m.%Y_%H:%M:%S")}.log.gz', + ), + "wb", + ) as f_out: copyfileobj(f_in, f_out) - print(f'Copied {path.join(log_folder, datetime.now().strftime("%d.%m.%Y_%H:%M:%S"))}.log.gz') - open(path.join(log_folder, log_file), 'w').close() + print( + f'Copied {path.join(log_folder, datetime.now().strftime("%d.%m.%Y_%H:%M:%S"))}.log.gz' + ) + open(path.join(log_folder, log_file), "w").close() except FileNotFoundError: - print(f'Log file {path.join(log_folder, log_file)} does not exist') + print(f"Log file {path.join(log_folder, log_file)} does not exist") pass + # Append string to log def logAppend(message: str, debug=False): """Write message to log file @@ -46,7 +56,7 @@ def logAppend(message: str, debug=False): ### Args: * message (`str`): Message to write * debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`. - """ + """ global log_folder @@ -58,10 +68,11 @@ def logAppend(message: str, debug=False): else: log_file = "latest.log" - log = open(path.join(log_folder, log_file), 'a') - log.write(f'{message_formatted}\n') + log = open(path.join(log_folder, log_file), "a") + log.write(f"{message_formatted}\n") log.close() + # Print to stdout and then to log def logWrite(message: str, debug=False): """Write message to stdout and log file @@ -69,7 +80,7 @@ def logWrite(message: str, debug=False): ### Args: * message (`str`): Message to print and write * debug (`bool`, *optional*): Whether this is a debug log. Defaults to `False`. - """ + """ # save to log file and rotation is to be done - logAppend(f'{message}', debug=debug) - print(f"{message}", flush=True) \ No newline at end of file + logAppend(f"{message}", debug=debug) + print(f"{message}", flush=True) diff --git a/modules/scheduled.py b/modules/scheduled.py index c3f5706..29a34a2 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -8,7 +8,11 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler from datetime import datetime, timedelta from ujson import dumps from app import app -from pyrogram.types import BotCommand, BotCommandScopeChat, BotCommandScopeChatAdministrators +from pyrogram.types import ( + BotCommand, + BotCommandScopeChat, + BotCommandScopeChatAdministrators, +) from pyrogram.errors import bad_request_400 from pyrogram.enums.chat_members_filter import ChatMembersFilter from classes.holo_user import HoloUser @@ -21,18 +25,27 @@ from requests import get scheduler = AsyncIOScheduler() if configGet("enabled", "scheduler", "cache_members"): - @scheduler.scheduled_job(trigger="interval", seconds=configGet("interval", "scheduler", "cache_members")) + + @scheduler.scheduled_job( + trigger="interval", seconds=configGet("interval", "scheduler", "cache_members") + ) async def cache_group_members(): list_of_users = [] async for member in app.get_chat_members(configGet("users", "groups")): list_of_users.append(member.user.id) makedirs(configGet("cache", "locations"), exist_ok=True) - jsonSave(list_of_users, path.join(configGet("cache", "locations"), "group_members")) + jsonSave( + list_of_users, path.join(configGet("cache", "locations"), "group_members") + ) if configGet("debug") is True: logWrite("User group caching performed", debug=True) + if configGet("enabled", "scheduler", "cache_admins"): - @scheduler.scheduled_job(trigger="interval", seconds=configGet("interval", "scheduler", "cache_admins")) + + @scheduler.scheduled_job( + trigger="interval", seconds=configGet("interval", "scheduler", "cache_admins") + ) async def cache_admins(): list_of_users = [] async for member in app.get_chat_members(configGet("admin", "groups")): @@ -42,37 +55,66 @@ if configGet("enabled", "scheduler", "cache_admins"): if configGet("debug") is True: logWrite("Admin group caching performed", debug=True) + # Cache the avatars of group members if configGet("enabled", "scheduler", "cache_avatars"): - @scheduler.scheduled_job(trigger="date", run_date=datetime.now()+timedelta(seconds=15)) - @scheduler.scheduled_job(trigger="interval", hours=configGet("interval", "scheduler", "cache_avatars")) + + @scheduler.scheduled_job( + trigger="date", run_date=datetime.now() + timedelta(seconds=15) + ) + @scheduler.scheduled_job( + trigger="interval", hours=configGet("interval", "scheduler", "cache_avatars") + ) async def cache_avatars(): list_of_users = [] - async for member in app.get_chat_members(configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query=""): + async for member in app.get_chat_members( + configGet("users", "groups"), filter=ChatMembersFilter.SEARCH, query="" + ): list_of_users.append(member.user) for user in list_of_users: if user.photo != None: - if not path.exists(f'{configGet("cache", "locations")}{sep}avatars{sep}{user.photo.big_file_id}'): - print(f'Pre-cached avatar {user.photo.big_file_id} of {user.id}', flush=True) - await app.download_media(user.photo.big_file_id, file_name=path.join(configGet("cache", "locations"), "avatars", user.photo.big_file_id)) + if not path.exists( + f'{configGet("cache", "locations")}{sep}avatars{sep}{user.photo.big_file_id}' + ): + print( + f"Pre-cached avatar {user.photo.big_file_id} of {user.id}", + flush=True, + ) + await app.download_media( + user.photo.big_file_id, + file_name=path.join( + configGet("cache", "locations"), + "avatars", + user.photo.big_file_id, + ), + ) logWrite("Avatars caching performed") # Check for birthdays if configGet("enabled", "features", "applications") is True: if configGet("enabled", "scheduler", "birthdays") is True: - @scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "birthdays")) + + @scheduler.scheduled_job( + trigger="cron", hour=configGet("time", "scheduler", "birthdays") + ) async def check_birthdays(): for entry in col_applications.find(): - if entry["application"]["2"].strftime("%d.%m") == datetime.now().strftime("%d.%m"): + if entry["application"]["2"].strftime( + "%d.%m" + ) == datetime.now().strftime("%d.%m"): try: - if entry["user"] not in jsonLoad(path.join(configGet("cache", "locations"), "group_members")): + if entry["user"] not in jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ): continue tg_user = await app.get_users(entry["user"]) - await app.send_message( configGet("admin", "groups"), locale("birthday", "message").format(str(tg_user.first_name), str(tg_user.username), str(relativedelta(datetime.now(), entry["application"]["2"], '%d.%m.%Y').years)) ) # type: ignore + await app.send_message(configGet("admin", "groups"), locale("birthday", "message").format(str(tg_user.first_name), str(tg_user.username), str(relativedelta(datetime.now(), entry["application"]["2"], "%d.%m.%Y").years))) # type: ignore logWrite(f"Notified admins about {entry['user']}'s birthday") except Exception as exp: - logWrite(f"Could not find user {entry['user']} to send a message about birthday due to '{exp}'") + logWrite( + f"Could not find user {entry['user']} to send a message about birthday due to '{exp}'" + ) continue logWrite("Birthdays check performed") @@ -80,42 +122,71 @@ if configGet("enabled", "features", "applications") is True: # Check for expired sponsorships if configGet("enabled", "features", "sponsorships") is True: if configGet("enabled", "scheduler", "sponsorships") is True: - @scheduler.scheduled_job(trigger="cron", hour=configGet("time", "scheduler", "sponsorships")) + + @scheduler.scheduled_job( + trigger="cron", hour=configGet("time", "scheduler", "sponsorships") + ) async def check_sponsors(): - for entry in col_sponsorships.find({"sponsorship.expires": {"$lt": datetime.now()+timedelta(days=2)}}): + for entry in col_sponsorships.find( + {"sponsorship.expires": {"$lt": datetime.now() + timedelta(days=2)}} + ): try: - if entry["user"] not in jsonLoad(path.join(configGet("cache", "locations"), "group_members")): + if entry["user"] not in jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ): continue tg_user = await app.get_users(entry["user"]) - until_expiry = abs(relativedelta(datetime.now(), entry["sponsorship"]["expires"]).days)+1 - await app.send_message( tg_user.id, locale("sponsorships_expires", "message").format(until_expiry) ) # type: ignore - logWrite(f"Notified user {entry['user']} that sponsorship expires in {until_expiry} days") + until_expiry = ( + abs( + relativedelta( + datetime.now(), entry["sponsorship"]["expires"] + ).days + ) + + 1 + ) + await app.send_message(tg_user.id, locale("sponsorships_expires", "message").format(until_expiry)) # type: ignore + logWrite( + f"Notified user {entry['user']} that sponsorship expires in {until_expiry} days" + ) except Exception as exp: - logWrite(f"Could not find user {entry['user']} notify about sponsorship expiry due to '{exp}'") + logWrite( + f"Could not find user {entry['user']} notify about sponsorship expiry due to '{exp}'" + ) continue - for entry in col_sponsorships.find({"sponsorship.expires": {"$lt": datetime.now()-timedelta(days=1)}}): + for entry in col_sponsorships.find( + {"sponsorship.expires": {"$lt": datetime.now() - timedelta(days=1)}} + ): try: holo_user = HoloUser(entry["user"]) col_sponsorships.find_one_and_delete({"user": holo_user.id}) - if entry["user"] not in jsonLoad(path.join(configGet("cache", "locations"), "group_members")): + if entry["user"] not in jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ): continue - await app.send_message( entry["user"], locale("sponsorships_expired", "message") ) # type: ignore + await app.send_message(entry["user"], locale("sponsorships_expired", "message")) # type: ignore await holo_user.label_reset(configGet("users", "groups")) try: tg_user = await app.get_users(entry["user"]) - logWrite(f"Notified user {entry['user']} that sponsorship expired") + logWrite( + f"Notified user {entry['user']} that sponsorship expired" + ) except Exception as exp: - logWrite(f"Could not find user {entry['user']} notify about sponsorship expired due to '{exp}'") + logWrite( + f"Could not find user {entry['user']} notify about sponsorship expired due to '{exp}'" + ) except Exception as exp: - logWrite(f"Could not reset label of user {entry['user']} due to '{exp}'") + logWrite( + f"Could not reset label of user {entry['user']} due to '{exp}'" + ) continue logWrite("Sponsorships check performed") # Register all bot commands -@scheduler.scheduled_job(trigger="date", run_date=datetime.now()+timedelta(seconds=10)) +@scheduler.scheduled_job( + trigger="date", run_date=datetime.now() + timedelta(seconds=10) +) async def commands_register(): - commands = { "users": [], "admins": [], @@ -123,7 +194,7 @@ async def commands_register(): "group_users": [], "group_admins": [], "group_users_admins": [], - "locales": {} + "locales": {}, } commands_raw = { @@ -133,7 +204,7 @@ async def commands_register(): "group_users": [], "group_admins": [], "group_users_admins": [], - "locales": {} + "locales": {}, } valid_locales = [] @@ -148,7 +219,7 @@ async def commands_register(): "owner": [], "group_users": [], "group_admins": [], - "group_users_admins": [] + "group_users_admins": [], } if configGet("debug") is True: commands_raw["locales"][".".join(entry.split(".")[:-1])] = { @@ -157,15 +228,13 @@ async def commands_register(): "owner": [], "group_users": [], "group_admins": [], - "group_users_admins": [] + "group_users_admins": [], } config_modules = configGet("features") config_commands = configGet("commands") - for command in config_commands: - enabled = False for module in config_commands[command]["modules"]: @@ -177,22 +246,27 @@ async def commands_register(): continue for permission in config_commands[command]["permissions"]: - - commands[permission].append(BotCommand(command, locale("commands")[command])) + commands[permission].append( + BotCommand(command, locale("commands")[command]) + ) if configGet("debug") is True: - commands_raw[permission].append({f"{command}": locale("commands")[command]}) + commands_raw[permission].append( + {f"{command}": locale("commands")[command]} + ) logWrite(f"Registering {command} for {permission}") for lc in valid_locales: - - commands["locales"][lc][permission].append(BotCommand(command, locale("commands", locale=lc)[command])) + commands["locales"][lc][permission].append( + BotCommand(command, locale("commands", locale=lc)[command]) + ) if configGet("debug") is True: - commands_raw["locales"][lc][permission].append({f"{command}": locale("commands", locale=lc)[command]}) + commands_raw["locales"][lc][permission].append( + {f"{command}": locale("commands", locale=lc)[command]} + ) logWrite(f"Registering {command} for {permission} [{lc}]") - # Registering user commands await app.set_bot_commands(commands["users"]) logWrite("Registered user commands for default locale") @@ -205,55 +279,94 @@ async def commands_register(): # Registering admin commands for admin in configGet("admins"): try: - await app.set_bot_commands(commands["admins"]+commands["users"], scope=BotCommandScopeChat(chat_id=admin)) + await app.set_bot_commands( + commands["admins"] + commands["users"], + scope=BotCommandScopeChat(chat_id=admin), + ) logWrite(f"Registered admin commands for admin {admin}") except bad_request_400.PeerIdInvalid: pass # Registering owner commands try: - await app.set_bot_commands(commands["admins"]+commands["owner"]+commands["users"], scope=BotCommandScopeChat(chat_id=configGet("owner"))) + await app.set_bot_commands( + commands["admins"] + commands["owner"] + commands["users"], + scope=BotCommandScopeChat(chat_id=configGet("owner")), + ) for lc in valid_locales: - await app.set_bot_commands(commands["locales"][lc]["admins"]+commands["locales"][lc]["owner"]+commands["locales"][lc]["users"], scope=BotCommandScopeChat(chat_id=configGet("owner"))) + await app.set_bot_commands( + commands["locales"][lc]["admins"] + + commands["locales"][lc]["owner"] + + commands["locales"][lc]["users"], + scope=BotCommandScopeChat(chat_id=configGet("owner")), + ) logWrite(f"Registered admin commands for owner {configGet('owner')}") except bad_request_400.PeerIdInvalid: pass # Registering admin group commands try: - await app.set_bot_commands(commands["group_admins"], scope=BotCommandScopeChat(chat_id=configGet("admin", "groups"))) + await app.set_bot_commands( + commands["group_admins"], + scope=BotCommandScopeChat(chat_id=configGet("admin", "groups")), + ) logWrite("Registered admin group commands for default locale") except bad_request_400.ChannelInvalid: - logWrite(f"Could not register commands for admin group. Bot is likely not in the group.") + logWrite( + f"Could not register commands for admin group. Bot is likely not in the group." + ) # Registering destination group commands try: - await app.set_bot_commands(commands["group_users"], scope=BotCommandScopeChat(chat_id=configGet("users", "groups"))) + await app.set_bot_commands( + commands["group_users"], + scope=BotCommandScopeChat(chat_id=configGet("users", "groups")), + ) logWrite("Registered destination group commands") except bad_request_400.ChannelInvalid: - logWrite(f"Could not register commands for destination group. Bot is likely not in the group.") + logWrite( + f"Could not register commands for destination group. Bot is likely not in the group." + ) # Registering destination group admin commands try: - await app.set_bot_commands(commands["group_users_admins"], scope=BotCommandScopeChatAdministrators(chat_id=configGet("users", "groups"))) + await app.set_bot_commands( + commands["group_users_admins"], + scope=BotCommandScopeChatAdministrators( + chat_id=configGet("users", "groups") + ), + ) logWrite("Registered destination group admin commands") except bad_request_400.ChannelInvalid: - logWrite(f"Could not register admin commands for destination group. Bot is likely not in the group.") + logWrite( + f"Could not register admin commands for destination group. Bot is likely not in the group." + ) - if configGet("debug") is True: print(commands, flush=True) - logWrite(f"Complete commands registration:\n{dumps(commands_raw, indent=4, ensure_ascii=False, encode_html_chars=False)}", debug=True) + logWrite( + f"Complete commands registration:\n{dumps(commands_raw, indent=4, ensure_ascii=False, encode_html_chars=False)}", + debug=True, + ) if configGet("enabled", "scheduler", "channels_monitor"): - @scheduler.scheduled_job(trigger="interval", minutes=configGet("interval", "scheduler", "channels_monitor")) + + @scheduler.scheduled_job( + trigger="interval", + minutes=configGet("interval", "scheduler", "channels_monitor"), + ) async def channels_monitor(): for channel in configGet("channels", "scheduler", "channels_monitor"): if configGet("debug") is True: - logWrite(f'Processing videos of {channel["name"]} ({channel["id"]})', debug=True) + logWrite( + f'Processing videos of {channel["name"]} ({channel["id"]})', + debug=True, + ) try: - req = get(f'https://www.youtube.com/feeds/videos.xml?channel_id={channel["id"]}') + req = get( + f'https://www.youtube.com/feeds/videos.xml?channel_id={channel["id"]}' + ) parsed = parse(req.content) if "feed" not in parsed: continue @@ -262,11 +375,33 @@ if configGet("enabled", "scheduler", "channels_monitor"): for entry in parsed["feed"]["entry"]: if "yt:videoId" not in entry: continue - if col_youtube.find_one( {"channel": channel["id"], "video": entry["yt:videoId"]} ) is None: - col_youtube.insert_one( {"channel": channel["id"], "video": entry["yt:videoId"], "date": datetime.fromisoformat(entry["published"])} ) - await app.send_message(configGet("users", "groups"), locale("youtube_video", "message").format(channel["name"], channel["link"], entry["title"], entry["link"]["@href"]), disable_web_page_preview=False) + if ( + col_youtube.find_one( + {"channel": channel["id"], "video": entry["yt:videoId"]} + ) + is None + ): + col_youtube.insert_one( + { + "channel": channel["id"], + "video": entry["yt:videoId"], + "date": datetime.fromisoformat(entry["published"]), + } + ) + await app.send_message( + configGet("users", "groups"), + locale("youtube_video", "message").format( + channel["name"], + channel["link"], + entry["title"], + entry["link"]["@href"], + ), + disable_web_page_preview=False, + ) await sleep(2) except Exception as exp: - logWrite(f'Could not get last videos of {channel["name"]} ({channel["id"]}) due to {exp}: {format_exc()}') + logWrite( + f'Could not get last videos of {channel["name"]} ({channel["id"]}) due to {exp}: {format_exc()}' + ) if configGet("debug") is True: - logWrite("Admin group caching performed", debug=True) \ No newline at end of file + logWrite("Admin group caching performed", debug=True) diff --git a/modules/utils.py b/modules/utils.py index cad4af5..154f52e 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -16,23 +16,29 @@ from classes.errors.geo import PlaceNotFoundError from modules.logging import logWrite + def jsonLoad(filename): """Loads arg1 as json and returns its contents""" - with open(filename, "r", encoding='utf8') as file: + with open(filename, "r", encoding="utf8") as file: try: output = loads(file.read()) except JSONDecodeError: - logWrite(f"Could not load json file {filename}: file seems to be incorrect!\n{print_exc()}") + logWrite( + f"Could not load json file {filename}: file seems to be incorrect!\n{print_exc()}" + ) raise except FileNotFoundError: - logWrite(f"Could not load json file {filename}: file does not seem to exist!\n{print_exc()}") + logWrite( + f"Could not load json file {filename}: file does not seem to exist!\n{print_exc()}" + ) raise return output + def jsonSave(contents, filename): """Dumps dict/list arg1 to file arg2""" try: - with open(filename, "w", encoding='utf8') as file: + with open(filename, "w", encoding="utf8") as file: file.write(dumps(contents, ensure_ascii=False, indent=4)) except Exception as exp: logWrite(f"Could not save json file {filename}: {exp}\n{print_exc()}") @@ -52,6 +58,7 @@ def nested_set(dic, keys, value, create_missing=True): d[keys[-1]] = value return dic + def configSet(keys: list, value: Any, file: str = "config", create_missing=True): """Set config's value to provided one @@ -60,7 +67,7 @@ def configSet(keys: list, value: Any, file: str = "config", create_missing=True) * value (`Any`): Needed value * file (`str`, optional): File (if not config). Defaults to "config". * create_missing (`bool`, optional): Create missing items on the way. Defaults to True. - """ + """ if file == "config": filepath = "" this_dict = jsonLoad(f"{filepath}{file}.json") @@ -69,15 +76,19 @@ def configSet(keys: list, value: Any, file: str = "config", create_missing=True) this_dict = jsonLoad("config_debug.json") file = "config_debug" except FileNotFoundError: - print("Debug mode is set but config_debug.json is not there! Falling back to config.json", flush=True) + 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 = nested_set(this_dict, keys, value, create_missing=create_missing) jsonSave(this_dict, f"{filepath}{file}.json") return + def configGet(key: str, *args: str, file: str = "config"): """Get value of the config key ### Args: @@ -86,18 +97,24 @@ def configGet(key: str, *args: str, file: str = "config"): * file (`str`): User ID to load. Loads config if not provided. Defaults to "config". ### Returns: * any: Value of provided key - """ + """ if file == "config": try: this_dict = jsonLoad("config.json") except FileNotFoundError: - print("Config file not found! Copy config_example.json to config.json, configure it and rerun the bot!", flush=True) + 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"] is True: try: this_dict = jsonLoad("config_debug.json") except FileNotFoundError: - print("Debug mode is set but config_debug.json is not there! Falling back to config.json", flush=True) + print( + "Debug mode is set but config_debug.json is not there! Falling back to config.json", + flush=True, + ) else: this_dict = jsonLoad(f"data{sep}users{sep}{file}.json") this_key = this_dict @@ -105,6 +122,7 @@ def configGet(key: str, *args: str, file: str = "config"): this_key = this_key[dict_key] return this_key[key] + def locale(key: str, *args: str, locale: Union[str, User] = configGet("locale")) -> Any: """Get value of locale string ### Args: @@ -113,32 +131,35 @@ def locale(key: str, *args: str, locale: Union[str, User] = configGet("locale")) * locale (`Union[str, User, HoloUser]`): Locale to looked up in. Provide User to get his `.language_code`. Defaults to config's locale value. ### Returns: * any: Value of provided locale key. In normal case must be `str`, `dict` or `list`. - """ + """ if isinstance(locale, User): locale = locale.language_code elif hasattr(locale, "locale"): locale = locale.locale - + if locale is None: locale = configGet("locale") - + try: this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{locale}.json') except FileNotFoundError: try: - this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json') + this_dict = jsonLoad( + f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json' + ) except FileNotFoundError: return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' this_key = this_dict for dict_key in args: this_key = this_key[dict_key] - + try: return this_key[key] except KeyError: return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' + def all_locales(key: str, *args: str) -> list: """Get value of the provided key and path in all available locales @@ -148,7 +169,7 @@ def all_locales(key: str, *args: str) -> list: ### Returns: * `list`: List of all values in all locales - """ + """ output = [] valid_locales = [] @@ -156,7 +177,7 @@ def all_locales(key: str, *args: str) -> list: files_locales = listdir(f'{configGet("locale", "locations")}') for entry in files_locales: valid_locales.append(".".join(entry.split(".")[:-1])) - + for lc in valid_locales: try: this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{lc}.json') @@ -166,7 +187,7 @@ def all_locales(key: str, *args: str) -> list: this_key = this_dict for dict_key in args: this_key = this_key[dict_key] - + try: output.append(this_key[key]) except KeyError: @@ -174,6 +195,7 @@ def all_locales(key: str, *args: str) -> list: return output + def find_location(query: str) -> dict: """Find location on geonames.org by query. Search is made with feature classes A and P. @@ -185,14 +207,22 @@ def find_location(query: str) -> dict: ### Returns: * `dict`: One instance of geonames response - """ + """ try: - result = (get(f"http://api.geonames.org/searchJSON?q={query}&maxRows=1&countryBias=UA&lang=uk&orderby=relevance&featureClass=P&featureClass=A&username={configGet('username', 'geocoding')}")).json() + result = ( + get( + f"http://api.geonames.org/searchJSON?q={query}&maxRows=1&countryBias=UA&lang=uk&orderby=relevance&featureClass=P&featureClass=A&username={configGet('username', 'geocoding')}" + ) + ).json() return result["geonames"][0] except (ValueError, KeyError, IndexError): raise PlaceNotFoundError(query) -def create_tmp(bytedata: Union[bytes, bytearray], kind: Union[Literal["image", "video"], None] = None) -> str: + +def create_tmp( + bytedata: Union[bytes, bytearray], + kind: Union[Literal["image", "video"], None] = None, +) -> str: """Create temporary file to help uploading it ### Args: @@ -201,7 +231,7 @@ def create_tmp(bytedata: Union[bytes, bytearray], kind: Union[Literal["image", " ### Returns: * `str`: Path to temporary file - """ + """ filename = str(uuid1()) if kind == "image": filename += ".jpg" @@ -212,6 +242,7 @@ def create_tmp(bytedata: Union[bytes, bytearray], kind: Union[Literal["image", " file.write(bytedata) return path.join("tmp", filename) + async def download_tmp(app: Client, file_id: str) -> Tuple[str, bytes]: """Download file by its ID and return its bytes @@ -221,7 +252,7 @@ async def download_tmp(app: Client, file_id: str) -> Tuple[str, bytes]: ### Returns: * `Tuple[str, bytes]`: First is a filepath and the second is file's bytes - """ + """ filename = str(uuid1()) makedirs("tmp", exist_ok=True) await app.download_media(file_id, path.join("tmp", filename)) @@ -229,24 +260,31 @@ async def download_tmp(app: Client, file_id: str) -> Tuple[str, bytes]: bytedata = f.read() return path.join("tmp", filename), bytedata + try: from psutil import Process except ModuleNotFoundError: # print(locale("deps_missing", "console", locale=configGet("locale")), flush=True) - print("Missing dependencies! Please install all needed dependencies and run the bot again!") + print( + "Missing dependencies! Please install all needed dependencies and run the bot again!" + ) exit() + def killProc(pid): if osname == "posix": from signal import SIGKILL + kill(pid, SIGKILL) else: p = Process(pid) p.kill() + def should_quote(msg): return True if msg.chat.type is not ChatType.PRIVATE else False + async def find_user(app: Client, query: Union[str, int]): try: result = await app.get_users(int(query)) @@ -261,4 +299,4 @@ async def find_user(app: Client, query: Union[str, int]): return None except bad_request_400.PeerIdInvalid: return None - return result \ No newline at end of file + return result -- 2.39.2 From de984c2b78829ffeda1c2cbe60e7ab9bf7577efb Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 9 Mar 2023 16:31:39 +0100 Subject: [PATCH 12/29] Removed useless shit --- modules/callbacks/nothing.py | 4 ---- modules/callbacks/reapply.py | 4 ---- modules/callbacks/rules.py | 4 ---- modules/callbacks/spoiler.py | 8 -------- modules/callbacks/sponsorship.py | 1 - modules/callbacks/sub.py | 4 ---- modules/callbacks/sus.py | 4 ---- modules/commands/application.py | 4 ---- modules/commands/applications.py | 4 ---- modules/commands/cancel.py | 4 ---- modules/commands/identify.py | 4 ---- modules/commands/issue.py | 8 +------- modules/commands/label.py | 4 ---- modules/commands/message.py | 4 ---- modules/commands/nearby.py | 4 ---- modules/commands/reapply.py | 4 ---- modules/commands/reboot.py | 4 ---- modules/commands/resetcommands.py | 4 ---- modules/commands/rules.py | 4 ---- modules/commands/spoiler.py | 4 ---- modules/commands/sponsorship.py | 4 ---- modules/commands/start.py | 4 ---- modules/commands/warn.py | 4 ---- modules/commands/warnings.py | 4 ---- modules/handlers/confirmation.py | 5 +---- modules/handlers/contact.py | 4 ---- modules/handlers/everything.py | 4 ---- modules/handlers/group_join.py | 4 ---- modules/handlers/welcome.py | 4 ---- 29 files changed, 2 insertions(+), 120 deletions(-) diff --git a/modules/callbacks/nothing.py b/modules/callbacks/nothing.py index 1550f55..b893acf 100644 --- a/modules/callbacks/nothing.py +++ b/modules/callbacks/nothing.py @@ -5,10 +5,6 @@ from pyrogram.client import Client from modules.utils import locale -# Callback empty =============================================================================================================== @app.on_callback_query(filters.regex("nothing")) async def callback_query_nothing(app: Client, clb: CallbackQuery): await clb.answer(text=locale("nothing", "callback", locale=clb.from_user)) - - -# ============================================================================================================================== diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index 82798f5..9d41dd3 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -15,7 +15,6 @@ from modules.handlers.welcome import welcome_pass from modules.database import col_tmp, col_applications -# Callbacks reapply ============================================================================================================ @app.on_callback_query(filters.regex("reapply_yes_[\s\S]*")) async def callback_reapply_query_accept(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") @@ -285,6 +284,3 @@ async def callback_query_reapply_stop(app: Client, clb: CallbackQuery): locale("reapply_restarted", "message", locale=holo_user), reply_markup=ReplyKeyboardRemove(), ) - - -# ============================================================================================================================== diff --git a/modules/callbacks/rules.py b/modules/callbacks/rules.py index ce33eca..8a05668 100644 --- a/modules/callbacks/rules.py +++ b/modules/callbacks/rules.py @@ -7,7 +7,6 @@ from modules.utils import locale, logWrite from modules.commands.rules import DefaultRulesMarkup -# Callback rule ================================================================================================================ @app.on_callback_query(filters.regex("rule_[\s\S]*")) async def callback_query_rule(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") @@ -100,6 +99,3 @@ async def callback_query_rules_additional(app: Client, clb: CallbackQuery): pass await clb.answer(text=locale("rules_additional", "callback", locale=clb.from_user)) - - -# ============================================================================================================================== diff --git a/modules/callbacks/spoiler.py b/modules/callbacks/spoiler.py index 5a48755..fd79e08 100644 --- a/modules/callbacks/spoiler.py +++ b/modules/callbacks/spoiler.py @@ -9,7 +9,6 @@ from bson.objectid import ObjectId from modules.utils import configGet, jsonLoad, locale -# Callback sid ================================================================================================================= @app.on_callback_query(filters.regex("sid_[\s\S]*")) async def callback_query_sid(app: Client, clb: CallbackQuery): await clb.answer( @@ -17,10 +16,6 @@ async def callback_query_sid(app: Client, clb: CallbackQuery): ) -# ============================================================================================================================== - - -# Callback shc ================================================================================================================= @app.on_callback_query(filters.regex("shc_[\s\S]*")) async def callback_query_shc(app: Client, clb: CallbackQuery): if clb.from_user.id not in jsonLoad( @@ -80,6 +75,3 @@ async def callback_query_shc(app: Client, clb: CallbackQuery): await clb.answer( locale("spoiler_sent", "callback", locale=clb.from_user), show_alert=True ) - - -# ============================================================================================================================== diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 05732e0..016be60 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -14,7 +14,6 @@ from modules.utils import configGet, locale, logWrite, should_quote from modules.database import col_tmp, col_sponsorships -# Callbacks sponsorship ======================================================================================================== @app.on_callback_query(filters.regex("sponsor_apply_[\s\S]*")) async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") diff --git a/modules/callbacks/sub.py b/modules/callbacks/sub.py index ef6954c..970a722 100644 --- a/modules/callbacks/sub.py +++ b/modules/callbacks/sub.py @@ -9,7 +9,6 @@ from modules.database import col_tmp, col_applications from modules.commands.rules import DefaultRulesMarkup -# Callbacks application ======================================================================================================== @app.on_callback_query(filters.regex("sub_yes_[\s\S]*")) async def callback_query_accept(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") @@ -188,6 +187,3 @@ async def callback_query_reject_russian(app: Client, clb: CallbackQuery): ), show_alert=True, ) - - -# ============================================================================================================================== diff --git a/modules/callbacks/sus.py b/modules/callbacks/sus.py index 4c51471..4085021 100644 --- a/modules/callbacks/sus.py +++ b/modules/callbacks/sus.py @@ -12,7 +12,6 @@ from modules.utils import configGet, locale, logWrite from modules.database import col_tmp -# Callbacks sus users ========================================================================================================== @app.on_callback_query(filters.regex("sus_allow_[\s\S]*")) async def callback_query_sus_allow(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") @@ -99,6 +98,3 @@ async def callback_query_sus_reject(app: Client, clb: CallbackQuery): {"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "rejected", "sent": False}}, ) - - -# ============================================================================================================================== diff --git a/modules/commands/application.py b/modules/commands/application.py index f68f5e6..6e79fdd 100644 --- a/modules/commands/application.py +++ b/modules/commands/application.py @@ -13,7 +13,6 @@ from modules.database import col_applications from modules import custom_filters -# Application command ========================================================================================================== @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -98,6 +97,3 @@ async def cmd_application(app: Client, msg: Message): locale("application_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg), ) - - -# ============================================================================================================================== diff --git a/modules/commands/applications.py b/modules/commands/applications.py index bdb4a6d..7e2edbf 100644 --- a/modules/commands/applications.py +++ b/modules/commands/applications.py @@ -11,7 +11,6 @@ from modules.database import col_applications from modules import custom_filters -# Applications command ========================================================================================================= @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -38,6 +37,3 @@ async def cmd_applications(app: Client, msg: Message): quote=should_quote(msg), ) remove(f"tmp{sep}{filename}.json") - - -# ============================================================================================================================== diff --git a/modules/commands/cancel.py b/modules/commands/cancel.py index 7d32276..c5e9b02 100644 --- a/modules/commands/cancel.py +++ b/modules/commands/cancel.py @@ -7,7 +7,6 @@ from modules.database import col_tmp, col_spoilers, col_applications from modules import custom_filters -# Cancel command =============================================================================================================== @app.on_message( (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled @@ -30,6 +29,3 @@ async def command_cancel(app: Client, msg: Message): reply_markup=ReplyKeyboardRemove(), ) logWrite(f"Cancelling all ongoing tmp operations for {msg.from_user.id}") - - -# ============================================================================================================================== diff --git a/modules/commands/identify.py b/modules/commands/identify.py index 167177a..86322e8 100644 --- a/modules/commands/identify.py +++ b/modules/commands/identify.py @@ -19,7 +19,6 @@ from modules.utils import ( from modules import custom_filters -# Identify command ============================================================================================================= @app.on_message( (custom_filters.enabled_applications | custom_filters.enabled_sponsorships) & ~filters.scheduled @@ -104,6 +103,3 @@ async def cmd_identify(app: Client, msg: Message): await msg.reply_text(output, quote=should_quote(msg)) logWrite(f"User {msg.from_user.id} identified user {holo_user.id}") - - -# ============================================================================================================================== diff --git a/modules/commands/issue.py b/modules/commands/issue.py index 70610f6..2ada581 100644 --- a/modules/commands/issue.py +++ b/modules/commands/issue.py @@ -1,14 +1,11 @@ -from typing import Union from app import app from pyrogram import filters -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, User, Message +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message from pyrogram.client import Client from modules.utils import configGet, locale from modules import custom_filters -from classes.holo_user import HoloUser -# Issue command ================================================================================================================ @app.on_message( custom_filters.enabled_general & ~filters.scheduled @@ -31,6 +28,3 @@ async def cmd_issue(app: Client, msg: Message): ] ), ) - - -# ============================================================================================================================== diff --git a/modules/commands/label.py b/modules/commands/label.py index b9eaf70..451e409 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -8,7 +8,6 @@ from classes.holo_user import HoloUser from modules import custom_filters -# Label command ================================================================================================================ @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -53,6 +52,3 @@ async def cmd_label(app: Client, msg: Message): else: await msg.reply_text(f"User not found") - - -# ============================================================================================================================== diff --git a/modules/commands/message.py b/modules/commands/message.py index cca0490..f9fc877 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -8,7 +8,6 @@ from modules.utils import logWrite, locale, should_quote, find_user from modules import custom_filters -# Message command ============================================================================================================== @app.on_message( custom_filters.enabled_general & ~filters.scheduled @@ -71,6 +70,3 @@ async def cmd_message(app: Client, msg: Message): quote=should_quote(msg), ) logWrite(f"Admin {msg.from_user.id} tried to send message but 'ValueError'") - - -# ============================================================================================================================== diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index 563d809..a7d748b 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -12,7 +12,6 @@ from modules.database import col_applications, col_users from classes.errors.geo import PlaceNotFoundError -# Nearby command =============================================================================================================== @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -116,6 +115,3 @@ async def cmd_nearby(app: Client, msg: Message): await msg.reply_text( locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg) ) - - -# ============================================================================================================================== diff --git a/modules/commands/reapply.py b/modules/commands/reapply.py index 2ba8468..31014d7 100644 --- a/modules/commands/reapply.py +++ b/modules/commands/reapply.py @@ -10,7 +10,6 @@ from modules.database import col_tmp, col_applications from modules import custom_filters -# Reapply command ============================================================================================================== @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -168,6 +167,3 @@ async def cmd_reapply(app: Client, msg: Message): ] ), ) - - -# ============================================================================================================================== diff --git a/modules/commands/reboot.py b/modules/commands/reboot.py index fedb312..a0d1f34 100644 --- a/modules/commands/reboot.py +++ b/modules/commands/reboot.py @@ -12,7 +12,6 @@ from modules import custom_filters pid = getpid() -# Reboot command =============================================================================================================== @app.on_message( custom_filters.enabled_general & ~filters.scheduled @@ -33,6 +32,3 @@ async def cmd_kill(app: Client, msg: Message): path.join(configGet("cache", "locations"), "shutdown_time"), ) exit() - - -# ============================================================================================================================== diff --git a/modules/commands/resetcommands.py b/modules/commands/resetcommands.py index b5a962d..b2fd468 100644 --- a/modules/commands/resetcommands.py +++ b/modules/commands/resetcommands.py @@ -10,7 +10,6 @@ from modules import custom_filters pid = getpid() -# Reset commands command ======================================================================================================= @app.on_message( custom_filters.enabled_general & ~filters.scheduled @@ -110,6 +109,3 @@ async def cmd_resetcommands(app: Client, msg: Message): ), debug=True, ) - - -# ============================================================================================================================== diff --git a/modules/commands/rules.py b/modules/commands/rules.py index a7fe6fd..50879cd 100644 --- a/modules/commands/rules.py +++ b/modules/commands/rules.py @@ -42,7 +42,6 @@ class DefaultRulesMarkup(list): ) -# Rules command ============================================================================================================= @app.on_message( custom_filters.enabled_general & ~filters.scheduled @@ -56,6 +55,3 @@ async def cmd_rules(app: Client, msg: Message): disable_web_page_preview=True, reply_markup=DefaultRulesMarkup(msg.from_user).keyboard, ) - - -# ============================================================================================================================== diff --git a/modules/commands/spoiler.py b/modules/commands/spoiler.py index 24d40ee..4c9eb10 100644 --- a/modules/commands/spoiler.py +++ b/modules/commands/spoiler.py @@ -10,7 +10,6 @@ from modules.database import col_spoilers, col_applications from modules import custom_filters -# Spoiler command ============================================================================================================== @app.on_message( custom_filters.enabled_spoilers & ~filters.scheduled @@ -63,6 +62,3 @@ async def cmd_spoiler(app: Client, msg: Message): await msg.reply_text( locale("spoiler_unfinished", "message", locale=msg.from_user) ) - - -# ============================================================================================================================== diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index 3856c39..3b3dd67 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -8,7 +8,6 @@ from modules.utils import locale, should_quote from modules.database import col_applications -# Sponsorship command ========================================================================================================== @app.on_message( custom_filters.enabled_sponsorships & ~filters.scheduled @@ -45,6 +44,3 @@ async def cmd_sponsorship(app: Client, msg: Message): ) # else: # await msg.reply_text(locale("sponsorship_application_empty", "message")) - - -# ============================================================================================================================== diff --git a/modules/commands/start.py b/modules/commands/start.py index 6e9ea9d..73699d6 100644 --- a/modules/commands/start.py +++ b/modules/commands/start.py @@ -9,7 +9,6 @@ from bson.objectid import ObjectId from bson.errors import InvalidId -# Start command ================================================================================================================ @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -69,6 +68,3 @@ async def cmd_start(app: Client, msg: Message): await msg.reply_text(spoiler["text"]) except InvalidId: await msg.reply_text(f"Got an invalid ID {msg.command[1]}") - - -# ============================================================================================================================== diff --git a/modules/commands/warn.py b/modules/commands/warn.py index 0c61908..a0b3761 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -8,7 +8,6 @@ from modules.database import col_warnings from modules import custom_filters -# Warn command ================================================================================================================= @app.on_message( custom_filters.enabled_warnings & ~filters.scheduled @@ -42,6 +41,3 @@ async def cmd_warn(app: Client, msg: Message): message, ) ) - - -# ============================================================================================================================== diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 24d357c..0f12ba2 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -8,7 +8,6 @@ from modules.database import col_users, col_warnings from modules import custom_filters -# Warnings command ============================================================================================================= @app.on_message( custom_filters.enabled_warnings & ~filters.scheduled @@ -72,6 +71,3 @@ async def cmd_warnings(app: Client, msg: Message): ), quote=should_quote(msg), ) - - -# ============================================================================================================================== diff --git a/modules/handlers/confirmation.py b/modules/handlers/confirmation.py index 8448123..10f4001 100644 --- a/modules/handlers/confirmation.py +++ b/modules/handlers/confirmation.py @@ -18,7 +18,7 @@ from modules.handlers.welcome import welcome_pass from modules.database import col_tmp, col_applications from modules import custom_filters -# Confirmation ================================================================================================================= + confirmation_1 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_1.append(pattern[0][0]) @@ -286,6 +286,3 @@ async def confirm_no( f"User {msg.from_user.id} restarted the sponsorship application due to typo in it" ) return - - -# ============================================================================================================================== diff --git a/modules/handlers/contact.py b/modules/handlers/contact.py index 8cb5d5c..6ab6f8b 100644 --- a/modules/handlers/contact.py +++ b/modules/handlers/contact.py @@ -10,7 +10,6 @@ from classes.holo_user import HoloUser from modules import custom_filters -# Contact getting ============================================================================================================== @app.on_message( custom_filters.enabled_applications & ~filters.scheduled @@ -82,6 +81,3 @@ async def get_contact(app: Client, msg: Message): await msg.reply_text( locale("contact_not_member", "message", locale=holo_user.locale) ) - - -# ============================================================================================================================== diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index 65c9f03..2ed37a4 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -41,7 +41,6 @@ async def message_context(msg: Message) -> tuple: return 0, 0 -# Any other input ============================================================================================================== @app.on_message( ~filters.scheduled & (filters.private | filters.chat(configGet("admin", "groups"))) @@ -400,6 +399,3 @@ async def message_in_group(app: Client, msg: Message): logWrite( f"Removed application requested by {msg.from_user.id} in destination group" ) - - -# ============================================================================================================================== diff --git a/modules/handlers/group_join.py b/modules/handlers/group_join.py index 70647eb..62741b3 100644 --- a/modules/handlers/group_join.py +++ b/modules/handlers/group_join.py @@ -15,7 +15,6 @@ from classes.holo_user import HoloUser from dateutil.relativedelta import relativedelta -# Filter users on join ========================================================================================================= @app.on_chat_member_updated( custom_filters.enabled_invites_check, group=configGet("users", "groups") ) @@ -150,6 +149,3 @@ async def filter_join(app: Client, member: ChatMemberUpdated): can_send_polls=False, ), ) - - -# ============================================================================================================================== diff --git a/modules/handlers/welcome.py b/modules/handlers/welcome.py index 38347d0..d6000ae 100644 --- a/modules/handlers/welcome.py +++ b/modules/handlers/welcome.py @@ -6,7 +6,6 @@ from classes.holo_user import HoloUser from modules.utils import all_locales, locale, logWrite from modules import custom_filters -# Welcome check ================================================================================================================ welcome_1 = [] for pattern in all_locales("welcome", "keyboard"): welcome_1.append(pattern[0][0]) @@ -72,6 +71,3 @@ async def welcome_reject(app: Client, msg: Message): locale("return", "keyboard", locale=msg.from_user), resize_keyboard=True ), ) - - -# ============================================================================================================================== -- 2.39.2 From cb3a97530381f9dd3e0d73efa8e7540c7ac7e1c7 Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 9 Mar 2023 16:35:51 +0100 Subject: [PATCH 13/29] Removed default config string and added badges --- README.md | 243 ++---------------------------------------------------- 1 file changed, 7 insertions(+), 236 deletions(-) diff --git a/README.md b/README.md index 4db0f86..711faed 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ -# HoloCheckerBot +

HoloCheckerBot

-Small Telegram bot made on Pyrogram +

Small Telegram bot made on Pyrogram

+ +

+License: GPL +Code style: black +

## What can this bot do? @@ -25,240 +30,6 @@ Small Telegram bot made on Pyrogram So bot has its "config_example.json" and it needs to be changed. Copy this file to "config.json" and open it with any text editor. -You can see config file with all the comments below: - -```json -{ - "locale": "uk", - "debug": false, - "owner": 0, - "age_allowed": 0, - "age_maximum": 70, - "api": "http://example.com", - "issues": "https://github.com/example/test/issues/new", - "inline_preview_count": 7, - "remove_application_time": -1, - "search_radius": 50, - "admins": [], - "groups": { - "admin": 0, - "users": 0 - }, - "bot": { - "api_id": 0, - "api_hash": "", - "bot_token": "" - }, - "database": { - "user": null, - "password": null, - "host": "127.0.0.1", - "port": 27017, - "name": "holochecker" - }, - "geocoding": { - "username": "demo" - }, - "logging": { - "size": 512, - "location": "logs" - }, - "features": { - "general": { - "enabled": true - }, - "applications": { - "enabled": true - }, - "sponsorships": { - "enabled": true - }, - "warnings": { - "enabled": true - }, - "invites_check": { - "enabled": true - }, - "dinovoice": { - "enabled": false - }, - "spoilers": { - "enabled": true, - "allow_external": true - } - }, - "scheduler": { - "birthdays": { - "time": 9, - "enabled": true - }, - "sponsorships": { - "time": 9, - "enabled": true - }, - "cache_avatars": { - "interval": 6, - "enabled": true - }, - "cache_members": { - "interval": 30, - "enabled": true - }, - "cache_admins": { - "interval": 120, - "enabled": true - }, - "channels_monitor": { - "interval": 5, - "enabled": true, - "channels": [] - } - }, - "locations": { - "cache": "cache", - "locale": "locale" - }, - "commands": { - "rules": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "general" - ] - }, - "spoiler": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "spoilers" - ] - }, - "cancel": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "spoilers", - "applications", - "sponsorships" - ] - }, - "nearby": { - "permissions": [ - "users", - "admins", - "group_admins" - ], - "modules": [ - "applications" - ] - }, - "warn": { - "permissions": [ - "group_users_admins" - ], - "modules": [ - "warnings" - ] - }, - "reapply": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "applications" - ] - }, - "sponsorship": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "sponsorships" - ] - }, - "reboot": { - "permissions": [ - "owner" - ], - "modules": [ - "general" - ] - }, - "label": { - "permissions": [ - "admins", - "group_admins" - ], - "modules": [ - "applications" - ] - }, - "message": { - "permissions": [ - "admins", - "group_admins" - ], - "modules": [ - "general" - ] - }, - "identify": { - "permissions": [ - "admins", - "group_admins" - ], - "modules": [ - "applications", - "sponsorships" - ] - }, - "issue": { - "permissions": [ - "users", - "admins" - ], - "modules": [ - "general" - ] - }, - "application": { - "permissions": [ - "admins", - "group_admins" - ], - "modules": [ - "applications" - ] - }, - "applications": { - "permissions": [ - "admins", - "group_admins" - ], - "modules": [ - "applications" - ] - }, - "resetcommands": { - "permissions": [ - "owner" - ], - "modules": [ - "general" - ] - } - } -} -``` - After all of that you're good to go! Happy using :) ## To-Do -- 2.39.2 From 2dc6a5429943577176fb8da5ff02201ca57c5f72 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 12 Mar 2023 20:02:49 +0100 Subject: [PATCH 14/29] Spoiler can't be empty now --- locale/uk.json | 4 +-- modules/callbacks/spoiler.py | 20 ++++++--------- modules/handlers/everything.py | 46 ++++++++++++++-------------------- modules/inline.py | 22 ++++++---------- 4 files changed, 34 insertions(+), 58 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index d1e23ac..b812b8c 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -109,14 +109,12 @@ "spoiler_started": "Розпочато створення спойлера. Будь ласка, оберіть категорію спойлера за допомогою клавіатури бота.", "spoiler_unfinished": "У вас ще є незавершений спойлер. Надішліть /cancel щоб зупинити його створення", "spoiler_cancel": "Створення спойлера було припинено", - "spoiler_empty": "Спойлер категорії \"{0}\" без опису", - "spoiler_empty_named": "Спойлер категорії \"{0}\" без опису від **{1}**", "spoiler_described": "Спойлер категорії \"{0}\": {1}", "spoiler_described_named": "Спойлер категорії \"{0}\" від **{1}**: {2}", "spoiler_description_enter": "Добре, введіть бажаний опис спойлера", "spoiler_description_too_long": "Текст занадто довгий. Будь ласка, умісти опис у 1024 символи.", "spoiler_using_description": "Встановлено опис спойлера: {0}\n\nЗалишилось додати вміст самого спойлера. Бот приймає текстове повідомлення, фото, відео, файл а також гіф зображення (1 шт.)", - "spoiler_send_description": "Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати. Надішли мінус (-) щоб пропустити цей крок.", + "spoiler_send_description": "Тепер треба надіслати коротенький опис спойлера, щоб люди розуміли що під ним варто очкувати.", "spoiler_ready": "Успіх! Спойлер створено", "spoiler_send": "Користуйтесь кнопкою нижче щоб надіслати його.", "spoiler_incorrect_content": "Бот не підтримує такий контент. Будь ласка, надішли текст, фото, відео, файл або анімацію (гіф).", diff --git a/modules/callbacks/spoiler.py b/modules/callbacks/spoiler.py index fd79e08..7dc26f0 100644 --- a/modules/callbacks/spoiler.py +++ b/modules/callbacks/spoiler.py @@ -29,19 +29,13 @@ async def callback_query_shc(app: Client, clb: CallbackQuery): spoil = col_spoilers.find_one({"_id": ObjectId(clb.data.split("_")[1])}) - if spoil["description"] == "": - desc = locale("spoiler_empty_named", "message", locale=clb.from_user).format( - locale(spoil["category"], "message", "spoiler_categories"), - clb.from_user.first_name, - ) - else: - desc = locale( - "spoiler_described_named", "message", locale=clb.from_user - ).format( - locale(spoil["category"], "message", "spoiler_categories"), - clb.from_user.first_name, - spoil["description"], - ) + desc = locale( + "spoiler_described_named", "message", locale=clb.from_user + ).format( + locale(spoil["category"], "message", "spoiler_categories"), + clb.from_user.first_name, + spoil["description"], + ) await app.send_message( configGet("users", "groups"), diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index 2ed37a4..a1dd3fd 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -147,33 +147,27 @@ async def any_stage(app: Client, msg: Message): # await msg.reply_text(locale("spoiler_description_enter", "message", locale=msg.from_user), reply_markup=ForceReply(placeholder=locale("spoiler_description", "force_reply", locale=msg.from_user))) # return - if str(msg.text) != "-": - msg.text = fix_text(str(msg.text)) - if len(str(msg.text)) > 1024: - await msg.reply_text( - locale( - "spoiler_description_too_long", - "message", + msg.text = fix_text(str(msg.text)) + if len(str(msg.text)) > 1024: + await msg.reply_text( + locale( + "spoiler_description_too_long", + "message", + locale=msg.from_user, + ), + reply_markup=ForceReply( + placeholder=locale( + "spoiler_description", + "force_reply", locale=msg.from_user, - ), - reply_markup=ForceReply( - placeholder=locale( - "spoiler_description", - "force_reply", - locale=msg.from_user, - ) - ), - ) - return - col_spoilers.find_one_and_update( - {"user": msg.from_user.id, "completed": False}, - {"$set": {"description": msg.text}}, - ) - else: - col_spoilers.find_one_and_update( - {"user": msg.from_user.id, "completed": False}, - {"$set": {"description": ""}}, + ) + ), ) + return + col_spoilers.find_one_and_update( + {"user": msg.from_user.id, "completed": False}, + {"$set": {"description": msg.text}}, + ) logWrite( f"Adding description '{str(msg.text)}' to {msg.from_user.id}'s spoiler" @@ -376,8 +370,6 @@ async def message_in_group(app: Client, msg: Message): ): if str(msg.text).startswith( locale("spoiler_described", "message").split()[0] - ) or str(msg.text).startswith( - locale("spoiler_empty", "message").split()[0] ): logWrite(f"User {msg.from_user.id} sent spoiler to user's group") try: diff --git a/modules/inline.py b/modules/inline.py index d06a798..5173851 100644 --- a/modules/inline.py +++ b/modules/inline.py @@ -36,21 +36,13 @@ async def inline_answer(client: Client, inline_query: InlineQuery): ) if spoil is not None: - desc = ( - locale( - "spoiler_empty", "message", locale=inline_query.from_user - ).format( - locale(spoil["category"], "message", "spoiler_categories") - ) - if spoil["description"] == "" - else locale( - "spoiler_described", - "message", - locale=inline_query.from_user, - ).format( - locale(spoil["category"], "message", "spoiler_categories"), - spoil["description"], - ) + desc = locale( + "spoiler_described", + "message", + locale=inline_query.from_user, + ).format( + locale(spoil["category"], "message", "spoiler_categories"), + spoil["description"], ) results = [ -- 2.39.2 From a4faae5b454e74fb66c5b8b86839592fb8775fac Mon Sep 17 00:00:00 2001 From: profitroll Date: Sat, 18 Mar 2023 17:13:00 +0100 Subject: [PATCH 15/29] Fixed messages --- locale/uk.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index b812b8c..7679604 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -34,8 +34,8 @@ "sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.", "confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?", "sponsor_confirm": "**Дані форми:**\nСтрімер: {0}\nПідписка до: {1}\nХочу роль: {2}\n\nПеревір чи все правильно та жмакни кнопку на клавіатурі щоб продовжити.", - "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується :)", - "sponsorship_sent": "Дякуємо! Ми надіслали форму на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення :)", + "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення, як тільки її перевірять та приймуть рішення.. До тих пір від тебе більше нічого не потребується :)", + "sponsorship_sent": "Дякуємо! Ми надіслали форму на перевірку. Ти отримаєш повідомлення, як тільки її перевірять та приймуть рішення. :)", "application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}", "reapply_got": "Отримано оновлення анкети від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}", "sponsor_got": "Отримано форму на спонсорство від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані форми:**\n{3}", -- 2.39.2 From cea53387061f27722ee98d0ff10f7296b56f28d7 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sat, 18 Mar 2023 19:59:44 +0100 Subject: [PATCH 16/29] Bump Pyrogram and APScheduler versions --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index fde04be..3758ac3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -APScheduler==3.10.0 +APScheduler==3.10.1 fastapi~=0.88.0 psutil==5.9.4 pymongo==4.3.3 -Pyrogram~=2.0.100 +Pyrogram~=2.0.102 requests==2.28.2 tgcrypto==1.2.5 python_dateutil==2.8.2 -- 2.39.2 From fd992e89e790732748affd13e3ed53b699e0e679 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 26 Mar 2023 19:09:45 +0200 Subject: [PATCH 17/29] Bump fastapi to 0.95.0 and starlette to 0.26.1 --- requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 3758ac3..a85eb41 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,12 @@ -APScheduler==3.10.1 -fastapi~=0.88.0 +APScheduler~=3.10.1 +fastapi~=0.95.0 psutil==5.9.4 pymongo==4.3.3 Pyrogram~=2.0.102 requests==2.28.2 tgcrypto==1.2.5 python_dateutil==2.8.2 -starlette~=0.22.0 +starlette==0.26.1 ujson~=5.7.0 ftfy~=6.1.1 -xmltodict~=0.13.0 \ No newline at end of file +xmltodict==0.13.0 \ No newline at end of file -- 2.39.2 From 5c55af9e65f7a52ec30f60fa638bc3429b38dc29 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 26 Mar 2023 19:32:07 +0200 Subject: [PATCH 18/29] This commit closes #28 --- app.py | 3 ++ modules/commands/message.py | 97 +++++++++++++++++++++---------------- requirements.txt | 3 +- 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/app.py b/app.py index b30c147..e9ad9db 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,7 @@ from modules.logging import logWrite from modules.utils import configGet, jsonLoad from pyrogram.client import Client from pyrogram.errors import bad_request_400 +from convopyro import Conversation app = Client( "holochecker", @@ -12,6 +13,8 @@ app = Client( api_hash=configGet("api_hash", "bot"), ) +Conversation(app) + async def isAnAdmin(admin_id): # Check if user is mentioned in config diff --git a/modules/commands/message.py b/modules/commands/message.py index f9fc877..9910797 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -1,61 +1,74 @@ -from app import app +from app import app, isAnAdmin from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client +from convopyro import listen_message from classes.errors.holo_user import UserInvalidError from classes.holo_user import HoloUser -from modules.utils import logWrite, locale, should_quote, find_user +from modules.utils import configGet, logWrite, locale, should_quote, find_user from modules import custom_filters +from modules.database import col_messages @app.on_message( custom_filters.enabled_general & ~filters.scheduled & filters.command(["message"], prefixes=["/"]) - & custom_filters.admin + # & custom_filters.admin ) async def cmd_message(app: Client, msg: Message): try: - try: - destination = HoloUser(int(msg.command[1])) - except (ValueError, UserInvalidError): - destination = HoloUser(await find_user(app, query=msg.command[1])) - - if (msg.text is not None) and (len(str(msg.text).split()) > 2): - await destination.message( - context=msg, - text=" ".join(str(msg.text).split()[2:]), - caption=msg.caption, - photo=msg.photo, - video=msg.video, - file=msg.document, - voice=msg.voice, - animation=msg.animation, - adm_context=True, - ) - elif (msg.caption is not None) and (len(msg.caption.split()) > 2): - await destination.message( - context=msg, - text=str(msg.text), - caption=" ".join(msg.caption.split()[2:]), - photo=msg.photo, - video=msg.video, - file=msg.document, - voice=msg.voice, - animation=msg.animation, - adm_context=True, - ) + if await isAnAdmin(msg.from_user.id): + try: + destination = HoloUser(int(msg.command[1])) + except (ValueError, UserInvalidError): + destination = HoloUser(await find_user(app, query=msg.command[1])) + if (msg.text is not None) and (len(str(msg.text).split()) > 2): + await destination.message( + context=msg, + text=" ".join(str(msg.text).split()[2:]), + caption=msg.caption, + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) + elif (msg.caption is not None) and (len(msg.caption.split()) > 2): + await destination.message( + context=msg, + text=str(msg.text), + caption=" ".join(msg.caption.split()[2:]), + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) + else: + await destination.message( + context=msg, + text=None, + caption=None, + photo=msg.photo, + video=msg.video, + file=msg.document, + voice=msg.voice, + animation=msg.animation, + adm_context=True, + ) else: - await destination.message( - context=msg, - text=None, - caption=None, - photo=msg.photo, - video=msg.video, - file=msg.document, - voice=msg.voice, - animation=msg.animation, - adm_context=True, + message = await listen_message(app, msg.chat.id, timeout=None) + sent = await app.forward_messages( + configGet("admin", "groups"), msg.chat.id, message.id + ) + col_messages.insert_one( + { + "origin": {"chat": message.chat.id, "id": message.id}, + "destination": {"chat": sent.chat.id, "id": sent.id}, + } ) except IndexError: diff --git a/requirements.txt b/requirements.txt index a85eb41..5146bd7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ python_dateutil==2.8.2 starlette==0.26.1 ujson~=5.7.0 ftfy~=6.1.1 -xmltodict==0.13.0 \ No newline at end of file +xmltodict==0.13.0 +convopyro==0.5 \ No newline at end of file -- 2.39.2 From ddb59fdfd5eb75895abfe2ec07ea4d55ac966ea7 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 26 Mar 2023 19:38:59 +0200 Subject: [PATCH 19/29] Added additional locale string for /message --- locale/uk.json | 1 + modules/commands/message.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/locale/uk.json b/locale/uk.json index 7679604..b6aaecd 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -81,6 +81,7 @@ "no_warnings": "Користувач **{0}** (`{1}`) не має попереджень", "no_user_warnings": "Не знайдено користувачів за запитом **{0}**", "syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`", + "message_enter": "Надішліть повідомлення, яке треба переслати адмінам.\n\nЗверніть увагу, що повідомлення може містити лише одне медіа або файл.", "message_sent": "Повідомлення надіслано", "message_no_user": "⚠️ **Помилка надсилання**\nВказано невірний ID користувача, тому не вдалось надіслати йому повідомлення. Перевірте чи в якості ID надано те число, яке було показане в анкеті.", "message_invalid_syntax": "Неправильний синтаксис!\nТреба: `/message ID ПОВІДОМЛЕННЯ`", diff --git a/modules/commands/message.py b/modules/commands/message.py index 9910797..22231d2 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -60,6 +60,9 @@ async def cmd_message(app: Client, msg: Message): adm_context=True, ) else: + await msg.reply_text( + locale("message_enter", "message", locale=msg.from_user) + ) message = await listen_message(app, msg.chat.id, timeout=None) sent = await app.forward_messages( configGet("admin", "groups"), msg.chat.id, message.id @@ -70,6 +73,9 @@ async def cmd_message(app: Client, msg: Message): "destination": {"chat": sent.chat.id, "id": sent.id}, } ) + await message.reply_text( + locale("message_sent", "message", locale=message.from_user), quote=True + ) except IndexError: await msg.reply_text( -- 2.39.2 From 2a2ad9f96e080b7e4f0083db0efa870a2a668c4b Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 26 Mar 2023 19:39:33 +0200 Subject: [PATCH 20/29] Added permissions for users to use /message --- config_example.json | 1 + 1 file changed, 1 insertion(+) diff --git a/config_example.json b/config_example.json index f088ea0..1b4d791 100644 --- a/config_example.json +++ b/config_example.json @@ -182,6 +182,7 @@ }, "message": { "permissions": [ + "users", "admins", "group_admins" ], -- 2.39.2 From 43e71c95c4c988764cdc3f243361589a84b0fa5a Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 26 Mar 2023 19:50:10 +0200 Subject: [PATCH 21/29] Cancel should also cancel the message listener --- modules/commands/cancel.py | 4 ++++ modules/commands/message.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/modules/commands/cancel.py b/modules/commands/cancel.py index c5e9b02..86fbe6b 100644 --- a/modules/commands/cancel.py +++ b/modules/commands/cancel.py @@ -16,6 +16,10 @@ from modules import custom_filters async def command_cancel(app: Client, msg: Message): col_tmp.delete_many({"user": msg.from_user.id, "sent": False}) col_spoilers.delete_many({"user": msg.from_user.id, "completed": False}) + try: + await app.listen.Cancel(filters.user(msg.from_user.id)) + except: + pass if col_applications.find_one({"user": msg.from_user.id}) is None: await msg.reply_text( locale("cancel_reapply", "message", locale=msg.from_user), diff --git a/modules/commands/message.py b/modules/commands/message.py index 22231d2..d1ba84c 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -64,6 +64,8 @@ async def cmd_message(app: Client, msg: Message): locale("message_enter", "message", locale=msg.from_user) ) message = await listen_message(app, msg.chat.id, timeout=None) + if message.text is not None and message.text == "/cancel": + return sent = await app.forward_messages( configGet("admin", "groups"), msg.chat.id, message.id ) -- 2.39.2 From 972827d6c278bba93b44711420e2c21b9eeb3134 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 16:44:46 +0200 Subject: [PATCH 22/29] Does some tasks from #34 --- config_example.json | 4 ++++ modules/commands/warn.py | 2 ++ modules/commands/warnings.py | 4 ++-- modules/scheduled.py | 46 +++++++++++++++++++++++++++++++++++- validation/warnings.json | 25 +++++++++++++++++--- 5 files changed, 75 insertions(+), 6 deletions(-) diff --git a/config_example.json b/config_example.json index 1b4d791..ba435f8 100644 --- a/config_example.json +++ b/config_example.json @@ -82,6 +82,10 @@ "interval": 5, "enabled": true, "channels": [] + }, + "warnings_revocation": { + "interval": 6, + "enabled": true } }, "locations": { diff --git a/modules/commands/warn.py b/modules/commands/warn.py index a0b3761..578bc93 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -24,6 +24,8 @@ async def cmd_warn(app: Client, msg: Message): "admin": msg.from_user.id, "date": datetime.now(), "reason": message, + "active": True, + "revoke_date": None, } ) if message == "": diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 0f12ba2..7d49250 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -23,7 +23,7 @@ async def cmd_warnings(app: Client, msg: Message): return try: - user_db = col_users.find_one({"user": int(msg.command[1])}) + user_db = col_users.find_one({"user": int(msg.command[1]), "active": True}) target_id = user_db["user"] target_name = user_db["tg_name"] except: @@ -47,7 +47,7 @@ async def cmd_warnings(app: Client, msg: Message): ) return - warns = col_warnings.count_documents({"user": target_id}) + warns = col_warnings.count_documents({"user": target_id, "active": True}) if warns == 0: await msg.reply_text( diff --git a/modules/scheduled.py b/modules/scheduled.py index 29a34a2..2cc2a81 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -18,7 +18,12 @@ from pyrogram.enums.chat_members_filter import ChatMembersFilter from classes.holo_user import HoloUser from modules.utils import configGet, jsonLoad, jsonSave, locale, logWrite from dateutil.relativedelta import relativedelta -from modules.database import col_applications, col_sponsorships, col_youtube +from modules.database import ( + col_applications, + col_sponsorships, + col_youtube, + col_warnings, +) from xmltodict import parse from requests import get @@ -182,6 +187,45 @@ if configGet("enabled", "features", "sponsorships") is True: logWrite("Sponsorships check performed") +# Revoke old warnings +if configGet("enabled", "features", "warnings") is True: + if configGet("enabled", "scheduler", "warnings_revocation") is True: + + @scheduler.scheduled_job( + trigger="date", run_date=datetime.now() + timedelta(seconds=10) + ) + @scheduler.scheduled_job( + trigger="interval", + hours=configGet("interval", "scheduler", "warnings_revocation"), + ) + async def revoke_warnings(): + for warning in list( + col_warnings.find( + { + "active": True, + "date": {"$lt": datetime.now() - timedelta(days=90)}, + } + ) + ): + if ( + col_warnings.count_documents( + { + "user": warning["user"], + "active": True, + "date": {"$gt": datetime.now() - timedelta(days=90)}, + } + ) + == 0 + ): + col_warnings.update_one( + {"_id": warning["_id"]}, + {"$set": {"active": False, "revoke_date": datetime.now()}}, + ) + logWrite( + f'Revoked warning {str(warning["_id"])} of user {warning["user"]} because no active warnings for the last 90 days found.' + ) + + # Register all bot commands @scheduler.scheduled_job( trigger="date", run_date=datetime.now() + timedelta(seconds=10) diff --git a/validation/warnings.json b/validation/warnings.json index 6712a4a..51694a8 100644 --- a/validation/warnings.json +++ b/validation/warnings.json @@ -4,15 +4,23 @@ "user", "admin", "date", - "reason" + "reason", + "active", + "revoke_date" ], "properties": { "user": { - "bsonType": ["int", "long"], + "bsonType": [ + "int", + "long" + ], "description": "Telegram ID of user" }, "admin": { - "bsonType": ["int", "long"], + "bsonType": [ + "int", + "long" + ], "description": "Telegram ID of admin" }, "date": { @@ -22,6 +30,17 @@ "reason": { "bsonType": "string", "description": "Broken rule or admin's comment" + }, + "active": { + "bsonType": "bool", + "description": "Whether warning is still present" + }, + "revoke_date": { + "bsonType": [ + "date", + "null" + ], + "description": "Date when warning got inactive" } } } -- 2.39.2 From bf8ec39584e45dd3f9bdae9cca19c98660a3ae16 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 18:42:03 +0200 Subject: [PATCH 23/29] Changed how export works (in context of #34) --- config_example.json | 6 +- holochecker.py | 2 +- locale/uk.json | 3 +- modules/commands/applications.py | 39 ------- modules/commands/export.py | 182 +++++++++++++++++++++++++++++++ requirements.txt | 4 +- 6 files changed, 191 insertions(+), 45 deletions(-) delete mode 100644 modules/commands/applications.py create mode 100644 modules/commands/export.py diff --git a/config_example.json b/config_example.json index ba435f8..0b3e093 100644 --- a/config_example.json +++ b/config_example.json @@ -213,16 +213,16 @@ "general" ] }, - "application": { + "export": { "permissions": [ "admins", "group_admins" ], "modules": [ - "applications" + "general" ] }, - "applications": { + "application": { "permissions": [ "admins", "group_admins" diff --git a/holochecker.py b/holochecker.py index c7b0ad0..c9c65e4 100644 --- a/holochecker.py +++ b/holochecker.py @@ -12,8 +12,8 @@ makedirs(f'{configGet("cache", "locations")}{sep}avatars', exist_ok=True) # Importing from modules.commands.application import * -from modules.commands.applications import * from modules.commands.cancel import * +from modules.commands.export import * from modules.commands.identify import * from modules.commands.issue import * from modules.commands.label import * diff --git a/locale/uk.json b/locale/uk.json index b6aaecd..9bdfcb5 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -81,6 +81,7 @@ "no_warnings": "Користувач **{0}** (`{1}`) не має попереджень", "no_user_warnings": "Не знайдено користувачів за запитом **{0}**", "syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`", + "syntax_export": "Неправильний синтаксис!\nТреба: `/export applications/warnings/sponsorships/bans`", "message_enter": "Надішліть повідомлення, яке треба переслати адмінам.\n\nЗверніть увагу, що повідомлення може містити лише одне медіа або файл.", "message_sent": "Повідомлення надіслано", "message_no_user": "⚠️ **Помилка надсилання**\nВказано невірний ID користувача, тому не вдалось надіслати йому повідомлення. Перевірте чи в якості ID надано те число, яке було показане в анкеті.", @@ -294,13 +295,13 @@ "rules_additional": "Додаткові правила, які несуть рекомендаційний характер та не мають явних покарань за порушення:\n1️⃣) У чаті немає заборони на російську мову. Ми поважаємо кожного українця і не бажаємо розпалювати мовні конфлікти.\n2️⃣) У чаті немає заборони на російський контент. Але майте на увазі, що учасники, здебільшого, не будуть зацікавлені у тому, щоб обговорювати його і він може бути проігнорованим.\n3️⃣) Не зловживайте матами. Намагайтесь спілкуватись чистою мовою.\n4️⃣) Поважайте авторські права контент-мейкерів. Якщо ви знаходите арт, анімацію, музику тощо на офіційних ресурсах (pixiv, twitter, deviantart тощо), відправляйте на нього посилання.\nЯкщо хтось із учасників відправив арт із не офіційного ресурсу і ви бажаєте дізнатись його автора, відправте у відповідь повідомлення із текстом /search на повідомлення із артом.\n5️⃣) В особливо критичних ситуаціях порушник може отримати бан або бути повністю видаленим із чату, без попереджень.\n6️⃣) Якщо з кимось із учасників у вас трапиться якесь непорозуміння і вам неприємно буде перебувати в чаті один з одним (навіть, якщо конфлікт стався з кимось із адміністраторів) - напишіть мені в особисті повідомлення @Chirkopol. Я, як засновник чату та головний адміністратор, найбільше зацікавлений у збереженні цілісності чату та розвитку нашого ком'юніті, і я зроблю все, що в моїх силах, щоб допомогти вирішити вашу ситуацію.", "commands": { "application": "Переглянути анкету користувача", - "applications": "Отримати всі анкети як JSON", "cancel": "Відмінити актуальну дію", "identify": "Дізнатись дані про користувача за айді", "issue": "Задачі для покращення бота", "label": "Встановити нікнейм користувачу", "message": "Надіслати користувачу повідомлення", "nearby": "Показати користувачів поблизу", + "export": "Експортувати дані як CSV та JSON", "reapply": "Повторно заповнити анкету", "reboot": "Перезапустити бота", "resetcommands": "Відреєструвати всі команди", diff --git a/modules/commands/applications.py b/modules/commands/applications.py deleted file mode 100644 index 7e2edbf..0000000 --- a/modules/commands/applications.py +++ /dev/null @@ -1,39 +0,0 @@ -from os import sep, makedirs, remove -from uuid import uuid1 -from app import app -from pyrogram import filters -from pyrogram.types import Message -from pyrogram.client import Client -from pyrogram.enums.chat_action import ChatAction -from modules.logging import logWrite -from modules.utils import should_quote, jsonSave -from modules.database import col_applications -from modules import custom_filters - - -@app.on_message( - custom_filters.enabled_applications - & ~filters.scheduled - & filters.command(["applications"], prefixes=["/"]) - & custom_filters.admin -) -async def cmd_applications(app: Client, msg: Message): - logWrite(f"Admin {msg.from_user.id} requested export of a database") - await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT) - filename = uuid1() - output = [] - for entry in col_applications.find(): - del entry["_id"] - entry["date"] = entry["date"].strftime("%d.%m.%Y, %H:%M") - entry["application"]["2"] = entry["application"]["2"].strftime( - "%d.%m.%Y, %H:%M" - ) - output.append(entry) - makedirs("tmp", exist_ok=True) - jsonSave(output, f"tmp{sep}{filename}.json") - await msg.reply_document( - document=f"tmp{sep}{filename}.json", - file_name="applications", - quote=should_quote(msg), - ) - remove(f"tmp{sep}{filename}.json") diff --git a/modules/commands/export.py b/modules/commands/export.py new file mode 100644 index 0000000..9037f2d --- /dev/null +++ b/modules/commands/export.py @@ -0,0 +1,182 @@ +from csv import QUOTE_ALL +from os import makedirs, path, remove +from uuid import uuid1 + +import aiofiles +from aiocsv.writers import AsyncDictWriter +from pyrogram import filters +from pyrogram.client import Client +from pyrogram.enums.chat_action import ChatAction +from pyrogram.types import Message +from ujson import dumps + +from app import app +from modules import custom_filters +from modules.database import col_applications, col_sponsorships, col_warnings +from modules.logging import logWrite +from modules.utils import locale, should_quote + + +@app.on_message( + custom_filters.enabled_general + & ~filters.scheduled + & filters.command(["export"], prefixes=["/"]) + & custom_filters.admin +) +async def cmd_export(app: Client, msg: Message): + if len(msg.command) <= 1: + await msg.reply_text( + locale("syntax_export", "message", locale=msg.from_user), + quote=should_quote(msg), + ) + return + + selection = msg.command[1].lower() + + if selection not in ["applications", "warnings", "sponsorships", "bans"]: + await msg.reply_text( + locale("syntax_export", "message", locale=msg.from_user), + quote=should_quote(msg), + ) + return + + logWrite(f"Admin {msg.from_user.id} requested export of {selection}") + + makedirs("tmp", exist_ok=True) + temp_file = path.join("tmp", str(uuid1())) + + await app.send_chat_action(msg.chat.id, ChatAction.TYPING) + + output_csv = [] + output_json = [] + + if selection == "applications": + header_csv = [ + "user", + "date", + "admin", + "question_1", + "question_2", + "question_3", + "question_4", + "question_5", + "question_6", + "question_7", + "question_8", + "question_9", + "question_10", + ] + + for entry in list(col_applications.find()): + del entry["_id"] + entry["date"] = entry["date"].isoformat() + entry["application"]["2"] = entry["application"]["2"].isoformat() + output_json.append(entry) + + for entry in list(col_applications.find()): + del entry["_id"] + entry["date"] = entry["date"].isoformat() + entry["application"]["2"] = entry["application"]["2"].isoformat() + for index, value in enumerate(entry["application"]): + entry[f"question_{index+1}"] = entry["application"][value] + entry[ + "question_3" + ] = f"{entry['application']['3']['name']} ({entry['application']['3']['adminName1']}, {entry['application']['3']['countryName']})" + del entry["application"] + output_csv.append(entry) + + elif selection == "warnings": + header_csv = [ + "id", + "user", + "admin", + "date", + "reason", + "active", + "revoke_date", + ] + + for entry in list(col_warnings.find()): + for k, v in list(entry.items()): + entry[{"_id": "id"}.get(k, k)] = entry.pop(k) + entry["id"] = str(entry["id"]) + entry["date"] = entry["date"].isoformat() + if entry["revoke_date"] is not None: + entry["revoke_date"] = entry["revoke_date"].isoformat() + output_json.append(entry) + output_csv.append(entry) + + elif selection == "sponsorships": + header_csv = [ + "user", + "date", + "admin", + "streamer", + "expires", + "proof", + "label", + ] + + for entry in list(col_sponsorships.find()): + del entry["_id"] + entry["date"] = entry["date"].isoformat() + entry["sponsorship"]["expires"] = entry["sponsorship"][ + "expires" + ].isoformat() + output_json.append(entry) + + for entry in list(col_sponsorships.find()): + del entry["_id"] + entry["date"] = entry["date"].isoformat() + entry["sponsorship"]["expires"] = entry["sponsorship"][ + "expires" + ].isoformat() + for index, value in enumerate(entry["sponsorship"]): + entry[value] = entry["sponsorship"][value] + del entry["sponsorship"] + output_csv.append(entry) + + elif selection == "bans": + header_csv = ["user", "admin", "date"] + + for entry in list(col_warnings.find()): + del entry["id"] + entry["date"] = entry["date"].isoformat() + output_json.append(entry) + output_csv.append(entry) + + # Saving CSV + async with aiofiles.open(temp_file + ".csv", mode="w", encoding="utf-8") as file: + writer = AsyncDictWriter(file, header_csv, restval="NULL", quoting=QUOTE_ALL) + await writer.writeheader() + await writer.writerows(output_csv) + + # Saving JSON + async with aiofiles.open(temp_file + ".json", mode="w", encoding="utf-8") as file: + await file.write( + dumps( + output_json, ensure_ascii=False, escape_forward_slashes=False, indent=4 + ) + ) + + # Sending CSV + await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT) + await msg.reply_document( + document=temp_file + ".csv", + file_name=f"{selection}.csv", + quote=should_quote(msg), + ) + + # Sending JSON + await app.send_chat_action(msg.chat.id, ChatAction.UPLOAD_DOCUMENT) + await msg.reply_document( + document=temp_file + ".json", + file_name=f"{selection}.json", + quote=should_quote(msg), + ) + + del output_csv, output_json + + # Removing temp files + remove(temp_file + ".csv") + remove(temp_file + ".json") diff --git a/requirements.txt b/requirements.txt index 5146bd7..7e6b1c2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,6 @@ starlette==0.26.1 ujson~=5.7.0 ftfy~=6.1.1 xmltodict==0.13.0 -convopyro==0.5 \ No newline at end of file +convopyro==0.5 +aiocsv==1.2.3 +aiofiles~=23.1.0 \ No newline at end of file -- 2.39.2 From e235fe0ed20c2884fa649b8a48d2bb6915a19f37 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 18:42:11 +0200 Subject: [PATCH 24/29] Improved bans --- modules/callbacks/ban.py | 5 ++++- validation/bans.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 validation/bans.json diff --git a/modules/callbacks/ban.py b/modules/callbacks/ban.py index a96602a..8b2dae3 100644 --- a/modules/callbacks/ban.py +++ b/modules/callbacks/ban.py @@ -1,3 +1,4 @@ +from datetime import datetime from app import app, isAnAdmin from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery from pyrogram import filters @@ -12,7 +13,9 @@ async def callback_query_reject(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") if not await isAnAdmin(int(fullclb[1])): - col_bans.insert_one({"user": int(fullclb[1])}) + col_bans.insert_one( + {"user": int(fullclb[1]), "admin": clb.from_user.id, "date": datetime.now()} + ) edited_markup = [ [ diff --git a/validation/bans.json b/validation/bans.json new file mode 100644 index 0000000..3bbc392 --- /dev/null +++ b/validation/bans.json @@ -0,0 +1,29 @@ +{ + "$jsonSchema": { + "required": [ + "user", + "admin", + "date" + ], + "properties": { + "user": { + "bsonType": [ + "int", + "long" + ], + "description": "Telegram ID of user" + }, + "admin": { + "bsonType": [ + "int", + "long" + ], + "description": "Telegram ID of admin" + }, + "date": { + "bsonType": "date", + "description": "Date and time of getting" + } + } + } +} \ No newline at end of file -- 2.39.2 From 74ae30d84197e2971d7b93cf27c41d527e106f30 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 18:48:35 +0200 Subject: [PATCH 25/29] Sorted imports --- requirements.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7e6b1c2..1d4868c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,15 @@ +aiocsv==1.2.3 +aiofiles~=23.1.0 APScheduler~=3.10.1 +convopyro==0.5 fastapi~=0.95.0 +ftfy~=6.1.1 psutil==5.9.4 pymongo==4.3.3 Pyrogram~=2.0.102 -requests==2.28.2 -tgcrypto==1.2.5 python_dateutil==2.8.2 +requests==2.28.2 starlette==0.26.1 +tgcrypto==1.2.5 ujson~=5.7.0 -ftfy~=6.1.1 -xmltodict==0.13.0 -convopyro==0.5 -aiocsv==1.2.3 -aiofiles~=23.1.0 \ No newline at end of file +xmltodict==0.13.0 \ No newline at end of file -- 2.39.2 From cb2f3358b2a6d9bc660fb1ebd9799b65d5f50cd0 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Sun, 2 Apr 2023 19:54:16 +0200 Subject: [PATCH 26/29] Typo fixed --- modules/commands/warnings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 7d49250..396e914 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -23,7 +23,7 @@ async def cmd_warnings(app: Client, msg: Message): return try: - user_db = col_users.find_one({"user": int(msg.command[1]), "active": True}) + user_db = col_users.find_one({"user": int(msg.command[1])}) target_id = user_db["user"] target_name = user_db["tg_name"] except: -- 2.39.2 From 1f45398de523411a8a96da260879bcf9adc2a0e2 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 21:31:45 +0200 Subject: [PATCH 27/29] /warnings can now show all warnings --- locale/uk.json | 2 ++ modules/commands/warnings.py | 27 ++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/locale/uk.json b/locale/uk.json index 9bdfcb5..50bb530 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -78,6 +78,8 @@ "warned_reason": "Попереджено **{0}** (`{1}`)\n\n**Причина:**\n{2}", "warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження", "warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень", + "warnings_all": "**Список попереджень**\n\n{0}\n\nДля перегляду попереджень окремо взятого користувача слід використовувати `/warnings ID/NAME/USERNAME`", + "warnings_entry": "• {0} (`{1}`)\n Попереджень: {2}", "no_warnings": "Користувач **{0}** (`{1}`) не має попереджень", "no_user_warnings": "Не знайдено користувачів за запитом **{0}**", "syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`", diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 396e914..f712ca6 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -15,7 +15,32 @@ from modules import custom_filters & custom_filters.admin ) async def cmd_warnings(app: Client, msg: Message): - if len(msg.command) <= 1: + if len(msg.command) == 1: + warnings = {} + warnings_output = [] + for warning in col_warnings.find({"active": True}): + if str(warning["user"]) not in warnings: + warnings[str(warning["user"])] = { + "name": (col_users.find_one({"user": warning["user"]}))["tg_name"], + "warns": 1, + } + else: + warnings[str(warning["user"])]["warns"] += 1 + for warning in warnings: + warnings_output.append( + locale("warnings_entry", "message", locale=msg.from_user).format( + warnings[warning]["name"], warning, warnings[warning]["warns"] + ), + ) + await msg.reply_text( + locale("warnings_all", "message", locale=msg.from_user).format( + "\n".join(warnings_output) + ), + quote=should_quote(msg), + ) + return + + if len(msg.command) > 2: await msg.reply_text( locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg), -- 2.39.2 From a3f75bec7c6b02a3b18a08131d31649f48669816 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 21:38:23 +0200 Subject: [PATCH 28/29] /warnings now also considers user membership --- modules/commands/warnings.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index f712ca6..b65cc4e 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -1,9 +1,10 @@ +from os import path from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client from pyrogram.enums.chat_members_filter import ChatMembersFilter -from modules.utils import configGet, locale, should_quote +from modules.utils import configGet, jsonLoad, locale, should_quote from modules.database import col_users, col_warnings from modules import custom_filters @@ -18,7 +19,12 @@ async def cmd_warnings(app: Client, msg: Message): if len(msg.command) == 1: warnings = {} warnings_output = [] + group_members = jsonLoad( + path.join(configGet("cache", "locations"), "group_members") + ) for warning in col_warnings.find({"active": True}): + if warning["user"] not in group_members: + continue if str(warning["user"]) not in warnings: warnings[str(warning["user"])] = { "name": (col_users.find_one({"user": warning["user"]}))["tg_name"], -- 2.39.2 From aef4dd091ded114498a8e1523ab235556c34ba10 Mon Sep 17 00:00:00 2001 From: profitroll Date: Sun, 2 Apr 2023 22:17:54 +0200 Subject: [PATCH 29/29] Warnings can now be revoked using /warnings --- holochecker.py | 1 + locale/uk.json | 10 +++++--- modules/callbacks/warnings.py | 27 ++++++++++++++++++++++ modules/commands/warnings.py | 43 +++++++++++++++++++++++++++++++---- requirements.txt | 1 + 5 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 modules/callbacks/warnings.py diff --git a/holochecker.py b/holochecker.py index c9c65e4..61fffcc 100644 --- a/holochecker.py +++ b/holochecker.py @@ -37,6 +37,7 @@ from modules.callbacks.spoiler import * from modules.callbacks.sponsorship import * from modules.callbacks.sub import * from modules.callbacks.sus import * +from modules.callbacks.warnings import * from modules.handlers.confirmation import * from modules.handlers.contact import * diff --git a/locale/uk.json b/locale/uk.json index 50bb530..c47c73d 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -76,10 +76,12 @@ "application_invalid_syntax": "Неправильний синтаксис!\nТреба: `/application ID/NAME/USERNAME`", "warned": "Попереджено **{0}** (`{1}`) про порушення правил", "warned_reason": "Попереджено **{0}** (`{1}`)\n\n**Причина:**\n{2}", - "warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження", - "warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень", + "warnings_1": "Користувач **{0}** (`{1}`) має **{2}** попередження\n\nОбрати та зняти попередження:\n`/warnings {3} revoke`", + "warnings_2": "Користувач **{0}** (`{1}`) має **{2}** попереджень\n\nОбрати та зняти попередження:\n`/warnings {3} revoke`", "warnings_all": "**Список попереджень**\n\n{0}\n\nДля перегляду попереджень окремо взятого користувача слід використовувати `/warnings ID/NAME/USERNAME`", "warnings_entry": "• {0} (`{1}`)\n Попереджень: {2}", + "warnings_empty": "Щось тут порожньо...\nЗ іншого боку, це добре!", + "warnings_revoke": "**Попередження {0}:**\n\n{1}\n\nБудь ласка, користуйтесь клавіатурою щоб зняти попередження з відповідним номером.", "no_warnings": "Користувач **{0}** (`{1}`) не має попереджень", "no_user_warnings": "Не знайдено користувачів за запитом **{0}**", "syntax_warnings": "Неправильний синтаксис!\nТреба: `/warnings ID/NAME/USERNAME`", @@ -259,7 +261,9 @@ "sponsor_accepted": "✅ Форму {0} схвалено", "sponsor_rejected": "❌ Форму {0} відхилено", "spoiler_sent": "✅ Повідомлення надіслано в холо-чат", - "spoiler_forbidden": "❌ Треба бути учасником чату" + "spoiler_forbidden": "❌ Треба бути учасником чату", + "warning_revoked": "✅ Попередження скасовано", + "warning_not_found": "❌ Попередження вже скасовано або не існує" }, "inline": { "forbidden": { diff --git a/modules/callbacks/warnings.py b/modules/callbacks/warnings.py new file mode 100644 index 0000000..975482c --- /dev/null +++ b/modules/callbacks/warnings.py @@ -0,0 +1,27 @@ +from datetime import datetime +from app import app +from pyrogram import filters +from pyrogram.types import CallbackQuery +from pyrogram.client import Client +from modules.utils import locale +from modules.database import col_warnings +from bson import ObjectId + + +@app.on_callback_query(filters.regex("w_rev_[\s\S]*")) +async def callback_query_warning_revoke(app: Client, clb: CallbackQuery): + warning = col_warnings.find_one({"_id": ObjectId(str(clb.data).split("_")[2])}) + if warning is None: + await clb.answer( + text=locale("warning_not_found", "callback", locale=clb.from_user), + show_alert=True, + ) + return + col_warnings.update_one( + {"_id": warning["_id"]}, + {"$set": {"active": False, "revoke_date": datetime.now()}}, + ) + await clb.answer( + text=locale("warning_revoked", "callback", locale=clb.from_user).format(), + show_alert=True, + ) diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index b65cc4e..f533ccd 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -7,6 +7,7 @@ from pyrogram.enums.chat_members_filter import ChatMembersFilter from modules.utils import configGet, jsonLoad, locale, should_quote from modules.database import col_users, col_warnings from modules import custom_filters +from pykeyboard import InlineKeyboard, InlineButton @app.on_message( @@ -38,15 +39,20 @@ async def cmd_warnings(app: Client, msg: Message): warnings[warning]["name"], warning, warnings[warning]["warns"] ), ) + warnings_output = ( + locale("warnings_empty", "message", locale=msg.from_user) + if len(warnings_output) == 0 + else "\n".join(warnings_output) + ) await msg.reply_text( locale("warnings_all", "message", locale=msg.from_user).format( - "\n".join(warnings_output) + warnings_output ), quote=should_quote(msg), ) return - if len(msg.command) > 2: + if len(msg.command) > 3: await msg.reply_text( locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg), @@ -78,6 +84,35 @@ async def cmd_warnings(app: Client, msg: Message): ) return + if len(msg.command) == 3 and msg.command[2].lower() == "revoke": + if col_warnings.count_documents({"user": target_id, "active": True}) == 0: + await msg.reply_text( + locale("no_warnings", "message", locale=msg.from_user).format( + target_name, target_id + ), + quote=should_quote(msg), + ) + return + keyboard = InlineKeyboard() + buttons = [] + warnings = [] + for index, warning in enumerate( + list(col_warnings.find({"user": target_id, "active": True})) + ): + warnings.append( + f'{index+1}. {warning["date"].strftime("%d.%m.%Y, %H:%M")}\n Адмін: {warning["admin"]}\n Причина: {warning["reason"]}' + ) + buttons.append(InlineButton(str(index + 1), f'w_rev_{str(warning["_id"])}')) + keyboard.add(*buttons) + await msg.reply_text( + locale("warnings_revoke", "message", locale=msg.from_user).format( + target_name, "\n".join(warnings) + ), + reply_markup=keyboard, + quote=should_quote(msg), + ) + return + warns = col_warnings.count_documents({"user": target_id, "active": True}) if warns == 0: @@ -91,14 +126,14 @@ async def cmd_warnings(app: Client, msg: Message): if warns <= 5: await msg.reply_text( locale("warnings_1", "message", locale=msg.from_user).format( - target_name, target_id, warns + target_name, target_id, warns, target_id ), quote=should_quote(msg), ) else: await msg.reply_text( locale("warnings_2", "message", locale=msg.from_user).format( - target_name, target_id, warns + target_name, target_id, warns, target_id ), quote=should_quote(msg), ) diff --git a/requirements.txt b/requirements.txt index 1d4868c..b10a4c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ psutil==5.9.4 pymongo==4.3.3 Pyrogram~=2.0.102 python_dateutil==2.8.2 +pykeyboard==0.1.5 requests==2.28.2 starlette==0.26.1 tgcrypto==1.2.5 -- 2.39.2