From d3945eea0cab8681f3bd53a86bf4c2d458b3e201 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 12:25:47 +0100 Subject: [PATCH 01/30] Started working on sponsorships --- locale/uk.json | 18 ++++++++++++--- modules/callbacks/sponsorship.py | 38 ++++++++++++++++++++++++++++++++ modules/commands/sponsorship.py | 7 ++++-- modules/handlers/sponsorship.py | 7 +++++- 4 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 modules/callbacks/sponsorship.py diff --git a/locale/uk.json b/locale/uk.json index 8076558..7ecc50d 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -20,6 +20,12 @@ "question3_found": "Використовую наступний результат:\n• {0} ({1})", "question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.", "question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```", + "sponsorship_apply": "ℹ️ Розпочато заповнення форми на отримання бонусів за платну підписку на холодівчат.", + "sponsor1": "На яку саме дівчину платна підписка?", + "sponsor2": "До якої дати (`ДД.ММ.РРРР`) підписка?", + "sponsor2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`", + "sponsor3": "Будь ласка, надішли одне фото для підтвердження дійсності підписки", + "sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.", "confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?", "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)", "application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`, `{2}`\nЮзернейм: @{3}\n\n**Дані анкети:**\n{4}", @@ -122,7 +128,10 @@ "question7": "П'ять японських холодівчат", "question8": "Так або ні", "question9": "Ім'я дівчини або дівчин", - "question10": "Трошки про себе" + "question10": "Трошки про себе", + "sponsor1": "Ім'я дівчини", + "sponsor2": "Дата до якої підписка", + "sponsor3": "Фото-підтвердження" }, "button": { "sub_yes": "✅ Прийняти", @@ -145,7 +154,9 @@ "rules_next": "Далі ➡️", "rules_prev": "⬅️ Назад", "applying_stop": "🛑 Перервати заповнення", - "done": "✅ Готово" + "done": "✅ Готово", + "sponsor_apply": "Заповнити форму", + "sponsor_started": "Форму розпочато" }, "callback": { "sub_accepted": "✅ Анкету {0} схвалено", @@ -158,7 +169,8 @@ "rules_page": "ℹ️ Показано правило {0}", "rules_home": "ℹ️ Показано головну правил", "rules_additional": "ℹ️ Показано додаткові правила", - "reapply_stopped": "ℹ️ Перервано заповнення анкети" + "reapply_stopped": "ℹ️ Перервано заповнення анкети", + "sponsor_started": "ℹ️ Заповнення форми розпочато" }, "inline": { "forbidden": { diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py new file mode 100644 index 0000000..c0e6a95 --- /dev/null +++ b/modules/callbacks/sponsorship.py @@ -0,0 +1,38 @@ +from datetime import datetime +from app import app +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram import filters +from classes.holo_user import HoloUser +from modules.utils import configGet, locale, logWrite +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, clb): + + fullclb = clb.data.split("_") + holo_user = HoloUser(int(fullclb[2])) + + logWrite(f"User {holo_user.id} applied for sponsorship") + + col_tmp.insert_one( + { + "user": holo_user.id, + "type": "sponsorship", + "complete": False, + "sent": False, + "state": "fill", + "stage": 1, + "sponsorship": { + "streamer": None, + "expires": datetime.fromtimestamp(0), + "proof": None, + "label": "" + } + } + ) + + edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]] + + await clb.message.edit(text=locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup(edited_markup)) + await clb.answer(text=locale("sponsor_started", "callback").format(holo_user.id), show_alert=False) \ No newline at end of file diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index d5234fb..7665dc7 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -1,14 +1,17 @@ from datetime import datetime from app import app, isAnAdmin from pyrogram import filters -from modules.utils import should_quote +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from modules.utils import locale, should_quote from modules.database import col_applications # Sponsorship command ========================================================================================================== @app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"])) async def cmd_sponsorship(app, msg): if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): - await msg.reply_text("Yes, I exist.", quote=should_quote(msg)) + await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg)) + else: + await msg.reply_text(locale("sponsorship_application_empty", "message")) # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): # jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") # sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") diff --git a/modules/handlers/sponsorship.py b/modules/handlers/sponsorship.py index e524e69..393405e 100644 --- a/modules/handlers/sponsorship.py +++ b/modules/handlers/sponsorship.py @@ -1 +1,6 @@ -from app import app \ No newline at end of file +from app import app +from pyrogram import filters + +@app.on_message(~ filters.scheduled & filters.photo & filters.private) +async def sponsor_proof(app, msg): + pass \ No newline at end of file -- 2.39.2 From be55f8a3b1a40033c23e0d61748abe0abaca8751 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 12:26:05 +0100 Subject: [PATCH 02/30] Added DB validation for warnings --- validation/warnings.json | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/validation/warnings.json b/validation/warnings.json index 026bd47..6712a4a 100644 --- a/validation/warnings.json +++ b/validation/warnings.json @@ -1,6 +1,28 @@ { "$jsonSchema": { - "required": [], - "properties": {} + "required": [ + "user", + "admin", + "date", + "reason" + ], + "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" + }, + "reason": { + "bsonType": "string", + "description": "Broken rule or admin's comment" + } + } } } \ No newline at end of file -- 2.39.2 From 1b6f429be932a3aedd2981b5b664cf0510e8f469 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 12:26:50 +0100 Subject: [PATCH 03/30] Updated to-do --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 23dce77..d462fee 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,9 @@ After all of that you're good to go! Happy using :) ## To-Do -* [x] Complete messenger between user and admins * [ ] Check sponsorship on Holo girls -* [ ] Get application by id and user_id \ No newline at end of file +* [ ] Stats and infographic +* [ ] /nearby command +* [ ] Check group members without completed application +* [x] Complete messenger between user and admins +* [x] Get application by id and user_id \ No newline at end of file -- 2.39.2 From bc54abcc973831be9d6e27fb5ecf7c65f3fde14e Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 12:51:39 +0100 Subject: [PATCH 04/30] Fixed imports --- holochecker.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/holochecker.py b/holochecker.py index 849b88c..73d4f23 100644 --- a/holochecker.py +++ b/holochecker.py @@ -26,12 +26,14 @@ from modules.commands.warnings import * from modules.callbacks.nothing import * from modules.callbacks.reapply import * from modules.callbacks.rules import * +from modules.callbacks.sponsorship import * from modules.callbacks.sub import * from modules.callbacks.sus import * from modules.handlers.confirmation import * from modules.handlers.contact import * from modules.handlers.group_join import * +from modules.handlers.sponsorship import * from modules.handlers.voice import * from modules.handlers.welcome import * from modules.handlers.everything import * -- 2.39.2 From a906c0a1cc9061f784550ceed641cb2b5f3b36b4 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 15:22:14 +0100 Subject: [PATCH 05/30] Trying to fix AttributeError() on init --- classes/holo_user.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 4c4c03c..7454141 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -100,17 +100,19 @@ class HoloUser(): self.locale = holo_user["tg_locale"] self.username = holo_user["tg_username"] - if isinstance(user, User) and ((self.name != user.first_name) and (user.first_name is not None)): - self.set("tg_name", user.first_name) + if isinstance(user, User): - if isinstance(user, User) and ((self.phone != user.phone_number) and (user.phone_number is not None)): - self.set("tg_phone", user.phone_number) + if (self.name != user.first_name) and hasattr(user, "first_name") and (user.first_name is not None): + self.set("tg_name", user.first_name) - if isinstance(user, User) and ((self.locale != user.language_code) and (user.language_code is not None)): - self.set("tg_locale", user.language_code) + if (self.phone != user.phone_number) and hasattr(user, "phone_number") and (user.phone_number is not None): + self.set("tg_phone", user.phone_number) - if isinstance(user, User) and (self.username != user.username): - self.set("tg_username", user.username) + if (self.locale != user.language_code) and hasattr(user, "language_code") and (user.language_code is not None): + self.set("tg_locale", user.language_code) + + if (self.username != user.username) and hasattr(user, "username") and (user.username is not None): + self.set("tg_username", user.username) def set(self, key: str, value: Any) -> None: """Set attribute data and save it into database @@ -389,4 +391,7 @@ class HoloUser(): 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") \ No newline at end of file + logWrite(f"User {self.id} completed stage {stage} of application") + + else: + return \ No newline at end of file -- 2.39.2 From 68742681545aafdc1a0387323800eada4a5cb057 Mon Sep 17 00:00:00 2001 From: profitroll Date: Wed, 21 Dec 2022 15:23:36 +0100 Subject: [PATCH 06/30] Added one more None check --- modules/handlers/everything.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index 47be800..b42ca19 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -50,7 +50,8 @@ async def any_stage(app, msg): return - await holo_user.application_next(msg.text, msg=msg) + if msg.text is not None: + await holo_user.application_next(msg.text, msg=msg) # user_stage = configGet("stage", file=str(msg.from_user.id)) -- 2.39.2 From 2db19acf6c28fcc95498371a27bbe2b8898d9c2c Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 22 Dec 2022 15:02:28 +0100 Subject: [PATCH 07/30] Disabled EN locale --- locale/en.json | 215 ------------------------------------------------- 1 file changed, 215 deletions(-) delete mode 100644 locale/en.json diff --git a/locale/en.json b/locale/en.json deleted file mode 100644 index 714d44b..0000000 --- a/locale/en.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "message": { - "start": "Hello and welcome! This bot was created to accept applications for joining our community. To continue, we are interested in the answer to one question:\n\nDo you want to join the Ukrainian community of Hololive fans?", - "goodbye": "Ok, thanks for your honesty! Sorry, but under such conditions we will not add you to the community. If you change your mind and want to join, just click the button.", - "privacy_notice": "We're glad to hear that!\n\nTo continue, you will need to fill out a short Application. Please take it seriously. We take personal data very seriously, so this Application will not be shared with any third parties, but will only be used for the community.", - "question1": "How can I contact you?", - "question2": "When is your birthday?", - "question3": "What city are you from or where do you live now?\n\n⚠️ Please do not provide exact addresses! \"Kyiv\" or \"Kyiv Oblast\" is a sufficient specification.\n\nExamples:\n- Kyiv\n- Odesa oblast\n- Makiivka (Luhansk oblast)", - "question4": "When did you first learn about Hololive?", - "question5": "What made you interested in Hololive?", - "question6": "Which girl's content do you like the most?", - "question7": "Name the content of at least five Japanese girls you like the most.", - "question8": "Do you watch streams of Hololive girls?", - "question9": "Whose songs from Hololive do you like the most?", - "question10": "And finally, tell us a little about yourself. About hobbies, what you like to do. In one message, please.", - "question2_underage": "Sorry, but you must be {0} years old to join us. These restrictions are in place to ensure that everyone in the community has fun with each other.", - "question2_invalid": "Please enter a date in the format `DD.MM.YYYY`.", - "question2_joke": "Joke, we get it. But please enter the real value.", - "question3_invalid": "City/population not found. Use the examples below to indicate where you live and try again:\n\n- Kyiv\n- Odesa region\n- Makiivka (Luhansk region).", - "question3_found": "Using the following result:\n- {0} ({1})", - "question3_error": "⚠️ **Error**\nCould not retrieve the geographic label. The developer has been notified of this error. Please try again.", - "question3_traceback": "⚠️ **Error occurred**\nError retrieving geocoding for `{0}`\nError: `{1}`\n\nTraceback:\n```\n{2}\n```", - "confirm": "Great, thanks!\n\nPlease check the data is correct:\n{0}\n\nEverything correct?", - "application_sent": "Thank you! We have sent your application for verification. You will receive a message as soon as it is checked and a decision is made. Until then, nothing more is required from you. Have a nice day :)", - "application_got": "Received an application from `{0}`\n\nName in tg: `{1}`, `{2}`\nUsername: @{3}\n\n**Application data:**\n{4}", - "reapply_got": "Received profile change from `{0}`\n\nUsername: `{1}`, `{2}`\nUsername: @{3}\n\n**Application data:**\n{4}", - "shutdown": "Shutting down the bot with PID `{0}`", - "startup": "Starting the bot with PID `{0}`", - "startup_downtime": "Starting bot with PID `{0}` (was down for {1})", - "approved": "Congratulations! Your application has been reviewed and your eligibility has been confirmed. Use the button below the notification to join our lamp community!", - "approved_joined": "Congratulations! Your application has been reviewed and confirmed as correct. Thank you for your time and have a nice day!", - "read_rules": "Please read these rules before clicking the button and joining the chat.", - "rejected.": "Oh dear! Your application has been reviewed but not confirmed as eligible to join the community. Better luck next time!\n\nYou can try to reapply with the /reapply command.", - "rejected_aggressive": "Oh dear! Your application has been reviewed, but not confirmed as eligible to join the community.", - "rejected_russian": "Russian warship, go fuck yourself!", - "approved_by": "✅ **Application approved**\nAdmin **{0}** has reviewed and approved application `{1}`.", - "rejected_by": "❌ **Form rejected**\nAdmin **{0}** has reviewed and rejected form `{1}`.", - "rejected_by_agr": "❌ **Application rejected**\nAdmin **{0}** has reviewed and rejected application `{1}`, banning you from the community", - "rejected_by_rus": "❌ **Application rejected**\nAdmin **{0}** has reviewed and rejected the profile `{1}`, banning you from the community", - "contact": "Application `{0}`\n\n**Application data:**\n{1}\n\n{2}", - "application_status_accepted": "Accepted `{0}` on {1}", - "application_status_rejected": "Rejected `{0}` from {1}", - "application_status_on_hold": "Application still under review", - "application_status_not_send": "The application has not been sent yet", - "contact_invalid": "The submitted contact does not have a completed application form.", - "contact_not_member": "The sent contact is not a Telegram member.", - "already_sent": "The Application has already been sent, just wait. You will be informed immediately what decision will be made.", - "sus_joined": "User **{0}** (`{1}`) has joined the group without a personal invitation.", - "sus_allowed_by": "✅ **Access Allowed**\nAdmin **{0}** has allowed `{1}` to join the community without being personally invited.", - "sus_rejected_by": "❌ **Access denied**\nAdmin **{0}** has banned `{1}` for not being allowed to join the community via a personal link.", - "reapply_forbidden": "❌ **Action not possible**\nYour past application has not been approved or rejected yet.", - "reapply_in_progress": "❌ **Action not possible**\nYou are already filling out an application right now. If there is an error, just click the button below to start filling it out again.", - "reapply_restarted": "🔁 **Restarted**\nStarted filling out the application form again.", - "reapply_left_chat": "⚠️ **Reminder**\nIt seems that you left the chat in the past, but your profile is still available for use. Would you like to request membership using your old profile?", - "birthday": "User **{0}** (@{1}) has a birthday today! Turned {2} years old", - "application_invalid_syntax": "Invalid syntax! `/application ID/NAME/USERNAME`", - "warned": "**{0}** (`{1}`) rule violation warned", - "warned_reason": "Warned **{0}** (`{1}`)\n\n**Cause:**\n{2}", - "warnings_1": "User **{0}** (`{1}`) has **{2}** warnings", - "warnings_2": "User **{0}** (`{1}`) has **{2}** warnings", - "no_warnings": "User **{0}** (`{1}`) has no warnings", - "no_user_warnings": "No users found for query **{0}**", - "syntax_warnings": "Invalid syntax! `/warnings ID/NAME/USERNAME`", - "message_sent": "Message sent", - "message_no_user": "⚠️ **Sending Error**\nThe user ID provided is incorrect, so it was not possible to send the message to the user. Check if the ID is the same as the number that was shown in the Application.", - "message_invalid_syntax": "Invalid syntax! `/message ID MESSAGE`", - "message_from": "Message from **{0}** (`{1}`):\n\n", - "message_reply_notice": "\n\n**To send a reply to this message, tag it.**", - "message_error": "⚠️ **Error occurred**\nYour message could not be sent. The developer has been notified of this error.", - "message_traceback": "⚠️ **Error occurred**\nMessage error: `{0}` -> `{1}`\nError: `{2}`\n\nTraceback:\n```\n{3}\n```", - "no_user_application": "No users found for the query **{0}**", - "user_invalid": "The submitted user does not have a completed application.", - "joined_false_link": "User **{0}** (`{1}`) did not join the group using their link.", - "question_titles": { - "question1": "Name:", - "question2": "Birthday:", - "question3": "Residence:", - "question4": "Learned about Hololive:", - "question5": "Found interesting about Holo:", - "question6": "Like the content of:", - "question7": "Japanese hololive girls:", - "question8": "Watching streams:", - "question9": "Like songs:", - "question10": "About me:" - } - }, - "keyboard": { - "welcome": [ - [ - "Yes, of course" - ], - [ - "No, thank you." - ] - ], - "return": [ - [ - "I changed my mind, I want to" - ] - ], - "confirm": [ - [ - "Yes, everything is correct" - ], - [ - "No, re-fill" - ] - ] - }, - "force_reply": { - "question1": "Name", - "question2": "Birthday", - "question3": "City or region", - "question4": "Approximate time", - "question5": "Reasons, features", - "question6": "Girl's name", - "question7": "Five Japanese Holo girls", - "question8": "Yes or no", - "question9": "Name of the girl or girls", - "question10": "A bit about yourself" - }, - "button": { - "sub_yes": "✅ Accept", - "sub_no": "❌ Reject", - "sub_aggressive": "🤡 Reject (Toxic)", - "sub_russian": "🇷🇺 Reject (Russian)", - "accepted": "✅ Accepted", - "declined": "❌ Rejected", - "join": "Join", - "sus_allow": "✅ Confirm permission", - "sus_reject": "❌ Permanently block", - "sus_allowed": "✅ Permission granted", - "sus_rejected": "❌ User blocked", - "reapply_yes": "✅ Accept", - "reapply_no": "❌ Reject", - "reapply_old_one": "✅ Send old one", - "reapply_new_one": "🔁 Fill in again", - "rules_home": "🏠 Home", - "rules_additional": "➕ Additional", - "rules_next": "Next ➡️", - "rules_prev": "⬅️ Back", - "applying_stop": "🛑 Interrupt filling", - "done": "✅ Done" - }, - "callback": { - "sub_accepted": "✅ Application {0} has been approved", - "sub_rejected": "❌ Application {0} rejected", - "sub_aggressive": "🤡 Application {0} rejected", - "sub_russian": "🇷🇺 Application {0} rejected", - "sus_allowed": "✅ Access {0} allowed", - "sus_rejected": "❌ Access {0} denied", - "nothing": "🔔 Action already performed", - "rules_page": "ℹ️ Rule {0} shown", - "rules_home": "ℹ️ Home rule shown", - "rules_additional": "ℹ️ Additional rules shown", - "reapply_stopped": "ℹ️ Application stopped." - }, - "inline": { - "forbidden": { - "title": "Action not available", - "description": "You do not have permission to view this", - "message_content": "No permission to view this." - }, - "not_pm": { - "title": "Action not available", - "description": "This command is not available in channels.", - "message_content": "Action not available in channels." - }, - "user": { - "title": "", - "description": "View {0}'s application (@{1})", - "message_content": "{0} (@{1})\n\n**Application Data:**\n{2}" - } - }, - "rules_msg": "📢The rules can be supplemented and changed, depending on the need. In this case, violations that were committed before the introduction (change) of the rule will not be considered violations. You will be informed about all changes in the rules by means of pinned messages. But they will not be pinned on a permanent basis, so, from time to time, check the relevance of the rules in the bot.\n\n🔔If you see how one of the participants has violated the rules, tag one of the admins in response to a message that you think is a violation. In the post to the tag, indicate on which point you saw the violation. Or send a message to any of the administrators in private messages, and briefly describe the situation.\nList of administrators: @Chirkopol @Za_NerZula @Denialvapr\nFor questions about the functioning of the bot, please contact @Profitroll2281337\n\n❗️Any prohibited content can be sent to the chat using the bot - https://t.me/spoilerobot with a full description of the content contained under the spoiler. For an incorrect or incorrect description, a warning may be issued.\n\n‼️ Deleted or modified messages are still messages on your behalf that could be seen by chat participants and can be tracked through the admin panel.\n\n🔨 For violations - you will receive a warning. If you have 3 warnings, you will be banned for a day. For repeated violations, you will be immediately punished, without additional warnings.", - "rules": [ - "1️⃣) \"HoloKyiv Chat\" and \"HoloUA (Hololive Ukraine) Chat\" are created exclusively for Ukrainians (13+). They can only contain people who: \n- Were born in Ukraine and currently reside in it.\n- Were born outside Ukraine but reside in it.\n- Were born in Ukraine but currently do not reside in it.\n\"HoloUA (Hololive Ukraine) Chat\" is open to all Ukrainians. To get into it, please fill in the form and wait for it to be approved by the administrators.\n\n\"HoloKyiv Chat\" can be accessed only in person if you live in Kyiv or are a close friend of one of the chat participants. To be added to the chat, write @Chirkopol in private messages.\n🔨 If in the process of communication it turns out that you are not Ukrainian, you will be removed from the chat until you become one. No offense. We are creating an exclusively Ukrainian community.", - "2️⃣) Distribution of NSFW content with direct or partially hidden pornographic content is prohibited. The content of \"erotic nature\" should be covered with \"questionable\" body parts.\nShock content with a large presence of blood and/or physical injuries is prohibited.", - "3️⃣) Anonymity of Hololive and Holostars participants is prohibited: \n- Photos\n- Names\n- Place of residence\n- Exact age (the word \"holohegs\" does not apply)\n- Details of personal life\n- Posts from rummage accounts or mentioning them with specific data (i.e. the phrase \"something happened on Kalli's irl channel\" is allowed, but \"something happened on *irl channel name*\" - no) \n- Details from the girls' past - only superficially and without specifics (i.e. \"was an office worker\" - ok, \"was in *company_name\" - no). \nExceptions - if the girls themselves mentioned it on the archive(!) streams.... This rule does not apply to those who are no longer in Hololive, or have never been part of it. But, please, treat the personal life of other vloggers with respect, and do not exaggerate with the deanons of their personalities.", - "4️⃣) Flooding with the same type of messages, emojis, emoticons, stickers, gifs, etc. is prohibited. The approximate number of messages that can receive a warning for this rule is 5. Each situation can be considered separately, but put all your thoughts in one message.", - "5️⃣) Video and audio messages that are not intended to convey what you have heard or seen are prohibited. If you want to tell us about how your day went, but do not have the opportunity to type a message, use the magical video-to-text converter - https://t.me/voicybot", - "6️⃣) Insults, threats, bullying, humiliation, trolling of participants, their family members, friends and other circle that is close to the chat participant are prohibited. Messages like: \"go to ... \" - are also insults. You can get a warning even if it was your friend. It will be removed if your friend confirms that he is not offended by you.\n🔨 If at the request of a member or administrator, you do not change the pace of communication and do not apologize, you will receive a warning.\nIf your behavior causes a member to leave the chat, the punishment may be more severe.", - "7️⃣) It is forbidden to provoke conflicts and incite hatred between chat participants.", - "8️⃣) Racism, sexism, homophobia and condemnation of political and (or) religious prejudice are prohibited. These topics can still be part of the dialogue if they do not contain direct condemnations, insults, etc.", - "9️⃣) Avatars, nicknames, roles that violate other rules are prohibited." - ], - "rules_additional": "Additional rules that are advisory in nature, and have no explicit penalties for violations:\n1️⃣) There is no ban on the Russian language in the chat. We respect every Ukrainian and do not want to incite language conflicts.\n2️↪Mn_e_20E3↩) There is no ban on Russian content in the chat. But, keep in mind that participants, for the most part, will not be interested in discussing it and it may be ignored.) Do not abuse swear words. Try to communicate in clean language.\n4️⃣) Respect the copyright of content makers. If you find art, animation, music, etc., on official resources (pixiv, twitter, deviantart, etc.), send a link to it.\nIf someone sent art from a non-official resource and you want to know its author, send a message with the text `/search` to the message with the art.", - "commands": { - "rules": "Check out the rules", - "nearby": "Show users near the area", - "reapply": "Resubmit the application", - "sponsorship": "Apply for sponsor role" - }, - "commands_admin": { - "reboot": "Restart the bot", - "message": "Send a message", - "label": "Set user's nickname", - "warnings": "Check user's warnings", - "application": "Check user's application", - "applications": "Retrieve all applications as a JSON" - }, - "commands_group_admin": { - "reboot": "Restart the bot", - "message": "Send a message", - "label": "Set user's nickname", - "nearby": "Show users near the area", - "warnings": "Check user's warnings", - "application": "Check user's application", - "applications": "Retrieve all applications as a JSON" - }, - "commands_group_destination": { - "warn": "Warn a user", - "nearby": "Show users near the area" - } -} \ No newline at end of file -- 2.39.2 From ac5a0d112fe4080e607f04d0c57912fc2a68939e Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 22 Dec 2022 15:05:07 +0100 Subject: [PATCH 08/30] Disabled EN locale --- locale/en.disabled | 215 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 locale/en.disabled diff --git a/locale/en.disabled b/locale/en.disabled new file mode 100644 index 0000000..a93f3b5 --- /dev/null +++ b/locale/en.disabled @@ -0,0 +1,215 @@ +{ + "message": { + "start": "Hello and welcome! This bot was created to accept applications for joining our community. To continue, we are interested in the answer to one question:\n\nDo you want to join the Ukrainian community of Hololive fans?", + "goodbye": "Ok, thanks for your honesty! Sorry, but under such conditions we will not add you to the community. If you change your mind and want to join, just click the button.", + "privacy_notice": "We're glad to hear that!\n\nTo continue, you will need to fill out a short Application. Please take it seriously. We take personal data very seriously, so this Application will not be shared with any third parties, but will only be used for the community.", + "question1": "How can I contact you?", + "question2": "When is your birthday?", + "question3": "What city are you from or where do you live now?\n\n⚠️ Please do not provide exact addresses! \"Kyiv\" or \"Kyiv Oblast\" is a sufficient specification.\n\nExamples:\n- Kyiv\n- Odesa oblast\n- Makiivka (Luhansk oblast)", + "question4": "When did you first learn about Hololive?", + "question5": "What made you interested in Hololive?", + "question6": "Which girl's content do you like the most?", + "question7": "Name the content of at least five Japanese girls you like the most.", + "question8": "Do you watch streams of Hololive girls?", + "question9": "Whose songs from Hololive do you like the most?", + "question10": "And finally, tell us a little about yourself. About hobbies, what you like to do. In one message, please.", + "question2_underage": "Sorry, but you must be {0} years old to join us. These restrictions are in place to ensure that everyone in the community has fun with each other.", + "question2_invalid": "Please enter a date in the format `DD.MM.YYYY`.", + "question2_joke": "Joke, we get it. But please enter the real value.", + "question3_invalid": "City/population not found. Use the examples below to indicate where you live and try again:\n\n- Kyiv\n- Odesa region\n- Makiivka (Luhansk region).", + "question3_found": "Using the following result:\n- {0} ({1})", + "question3_error": "⚠️ **Error**\nCould not retrieve the geographic label. The developer has been notified of this error. Please try again.", + "question3_traceback": "⚠️ **Error occurred**\nError retrieving geocoding for `{0}`\nError: `{1}`\n\nTraceback:\n```\n{2}\n```", + "confirm": "Great, thanks!\n\nPlease check the data is correct:\n{0}\n\nEverything correct?", + "application_sent": "Thank you! We have sent your application for verification. You will receive a message as soon as it is checked and a decision is made. Until then, nothing more is required from you. Have a nice day :)", + "application_got": "Received an application from `{0}`\n\nName in tg: `{1}`\nUsername: @{2}\n\n**Application data:**\n{3}", + "reapply_got": "Received application change from `{0}`\n\nUsername: `{1}`\nUsername: @{2}\n\n**Application data:**\n{3}", + "shutdown": "Shutting down the bot with PID `{0}`", + "startup": "Starting the bot with PID `{0}`", + "startup_downtime": "Starting bot with PID `{0}` (was down for {1})", + "approved": "Congratulations! Your application has been reviewed and your eligibility has been confirmed. Use the button below the notification to join our lamp community!", + "approved_joined": "Congratulations! Your application has been reviewed and confirmed as correct. Thank you for your time and have a nice day!", + "read_rules": "Please read these rules before clicking the button and joining the chat.", + "rejected.": "Oh dear! Your application has been reviewed but not confirmed as eligible to join the community. Better luck next time!\n\nYou can try to reapply with the /reapply command.", + "rejected_aggressive": "Oh dear! Your application has been reviewed, but not confirmed as eligible to join the community.", + "rejected_russian": "Russian warship, go fuck yourself!", + "approved_by": "✅ **Application approved**\nAdmin **{0}** has reviewed and approved application `{1}`.", + "rejected_by": "❌ **Form rejected**\nAdmin **{0}** has reviewed and rejected form `{1}`.", + "rejected_by_agr": "❌ **Application rejected**\nAdmin **{0}** has reviewed and rejected application `{1}`, banning you from the community", + "rejected_by_rus": "❌ **Application rejected**\nAdmin **{0}** has reviewed and rejected the profile `{1}`, banning you from the community", + "contact": "Application `{0}`\n\n**Application data:**\n{1}\n\n{2}", + "application_status_accepted": "Accepted `{0}` on {1}", + "application_status_rejected": "Rejected `{0}` from {1}", + "application_status_on_hold": "Application still under review", + "application_status_not_send": "The application has not been sent yet", + "contact_invalid": "The submitted contact does not have a completed application form.", + "contact_not_member": "The sent contact is not a Telegram member.", + "already_sent": "The Application has already been sent, just wait. You will be informed immediately what decision will be made.", + "sus_joined": "User **{0}** (`{1}`) has joined the group without a personal invitation.", + "sus_allowed_by": "✅ **Access Allowed**\nAdmin **{0}** has allowed `{1}` to join the community without being personally invited.", + "sus_rejected_by": "❌ **Access denied**\nAdmin **{0}** has banned `{1}` for not being allowed to join the community via a personal link.", + "reapply_forbidden": "❌ **Action not possible**\nYour past application has not been approved or rejected yet.", + "reapply_in_progress": "❌ **Action not possible**\nYou are already filling out an application right now. If there is an error, just click the button below to start filling it out again.", + "reapply_restarted": "🔁 **Restarted**\nStarted filling out the application form again.", + "reapply_left_chat": "⚠️ **Reminder**\nIt seems that you left the chat in the past, but your profile is still available for use. Would you like to request membership using your old profile?", + "birthday": "User **{0}** (@{1}) has a birthday today! Turned {2} years old", + "application_invalid_syntax": "Invalid syntax! `/application ID/NAME/USERNAME`", + "warned": "**{0}** (`{1}`) rule violation warned", + "warned_reason": "Warned **{0}** (`{1}`)\n\n**Cause:**\n{2}", + "warnings_1": "User **{0}** (`{1}`) has **{2}** warnings", + "warnings_2": "User **{0}** (`{1}`) has **{2}** warnings", + "no_warnings": "User **{0}** (`{1}`) has no warnings", + "no_user_warnings": "No users found for query **{0}**", + "syntax_warnings": "Invalid syntax! `/warnings ID/NAME/USERNAME`", + "message_sent": "Message sent", + "message_no_user": "⚠️ **Sending Error**\nThe user ID provided is incorrect, so it was not possible to send the message to the user. Check if the ID is the same as the number that was shown in the Application.", + "message_invalid_syntax": "Invalid syntax! `/message ID MESSAGE`", + "message_from": "Message from **{0}** (`{1}`):\n\n", + "message_reply_notice": "\n\n**To send a reply to this message, tag it.**", + "message_error": "⚠️ **Error occurred**\nYour message could not be sent. The developer has been notified of this error.", + "message_traceback": "⚠️ **Error occurred**\nMessage error: `{0}` -> `{1}`\nError: `{2}`\n\nTraceback:\n```\n{3}\n```", + "no_user_application": "No users found for the query **{0}**", + "user_invalid": "The submitted user does not have a completed application.", + "joined_false_link": "User **{0}** (`{1}`) did not join the group using their link.", + "question_titles": { + "question1": "Name:", + "question2": "Birthday:", + "question3": "Residence:", + "question4": "Learned about Hololive:", + "question5": "Found interesting about Holo:", + "question6": "Like the content of:", + "question7": "Japanese hololive girls:", + "question8": "Watching streams:", + "question9": "Like songs:", + "question10": "About me:" + } + }, + "keyboard": { + "welcome": [ + [ + "Yes, of course" + ], + [ + "No, thank you." + ] + ], + "return": [ + [ + "I changed my mind, I want to" + ] + ], + "confirm": [ + [ + "Yes, everything is correct" + ], + [ + "No, re-fill" + ] + ] + }, + "force_reply": { + "question1": "Name", + "question2": "Birthday", + "question3": "City or region", + "question4": "Approximate time", + "question5": "Reasons, features", + "question6": "Girl's name", + "question7": "Five Japanese Holo girls", + "question8": "Yes or no", + "question9": "Name of the girl or girls", + "question10": "A bit about yourself" + }, + "button": { + "sub_yes": "✅ Accept", + "sub_no": "❌ Reject", + "sub_aggressive": "🤡 Reject (Toxic)", + "sub_russian": "🇷🇺 Reject (Russian)", + "accepted": "✅ Accepted", + "declined": "❌ Rejected", + "join": "Join", + "sus_allow": "✅ Confirm permission", + "sus_reject": "❌ Permanently block", + "sus_allowed": "✅ Permission granted", + "sus_rejected": "❌ User blocked", + "reapply_yes": "✅ Accept", + "reapply_no": "❌ Reject", + "reapply_old_one": "✅ Send old one", + "reapply_new_one": "🔁 Fill in again", + "rules_home": "🏠 Home", + "rules_additional": "➕ Additional", + "rules_next": "Next ➡️", + "rules_prev": "⬅️ Back", + "applying_stop": "🛑 Interrupt filling", + "done": "✅ Done" + }, + "callback": { + "sub_accepted": "✅ Application {0} has been approved", + "sub_rejected": "❌ Application {0} rejected", + "sub_aggressive": "🤡 Application {0} rejected", + "sub_russian": "🇷🇺 Application {0} rejected", + "sus_allowed": "✅ Access {0} allowed", + "sus_rejected": "❌ Access {0} denied", + "nothing": "🔔 Action already performed", + "rules_page": "ℹ️ Rule {0} shown", + "rules_home": "ℹ️ Home rule shown", + "rules_additional": "ℹ️ Additional rules shown", + "reapply_stopped": "ℹ️ Application stopped." + }, + "inline": { + "forbidden": { + "title": "Action not available", + "description": "You do not have permission to view this", + "message_content": "No permission to view this." + }, + "not_pm": { + "title": "Action not available", + "description": "This command is not available in channels.", + "message_content": "Action not available in channels." + }, + "user": { + "title": "", + "description": "View {0}'s application (@{1})", + "message_content": "{0} (@{1})\n\n**Application Data:**\n{2}" + } + }, + "rules_msg": "📢The rules can be supplemented and changed, depending on the need. In this case, violations that were committed before the introduction (change) of the rule will not be considered violations. You will be informed about all changes in the rules by means of pinned messages. But they will not be pinned on a permanent basis, so, from time to time, check the relevance of the rules in the bot.\n\n🔔If you see how one of the participants has violated the rules, tag one of the admins in response to a message that you think is a violation. In the post to the tag, indicate on which point you saw the violation. Or send a message to any of the administrators in private messages, and briefly describe the situation.\nList of administrators: @Chirkopol @Za_NerZula @Denialvapr\nFor questions about the functioning of the bot, please contact @Profitroll2281337\n\n❗️Any prohibited content can be sent to the chat using the bot - https://t.me/spoilerobot with a full description of the content contained under the spoiler. For an incorrect or incorrect description, a warning may be issued.\n\n‼️ Deleted or modified messages are still messages on your behalf that could be seen by chat participants and can be tracked through the admin panel.\n\n🔨 For violations - you will receive a warning. If you have 3 warnings, you will be banned for a day. For repeated violations, you will be immediately punished, without additional warnings.", + "rules": [ + "1️⃣) \"HoloKyiv Chat\" and \"HoloUA (Hololive Ukraine) Chat\" are created exclusively for Ukrainians (13+). They can only contain people who: \n- Were born in Ukraine and currently reside in it.\n- Were born outside Ukraine but reside in it.\n- Were born in Ukraine but currently do not reside in it.\n\"HoloUA (Hololive Ukraine) Chat\" is open to all Ukrainians. To get into it, please fill in the form and wait for it to be approved by the administrators.\n\n\"HoloKyiv Chat\" can be accessed only in person if you live in Kyiv or are a close friend of one of the chat participants. To be added to the chat, write @Chirkopol in private messages.\n🔨 If in the process of communication it turns out that you are not Ukrainian, you will be removed from the chat until you become one. No offense. We are creating an exclusively Ukrainian community.", + "2️⃣) Distribution of NSFW content with direct or partially hidden pornographic content is prohibited. The content of \"erotic nature\" should be covered with \"questionable\" body parts.\nShock content with a large presence of blood and/or physical injuries is prohibited.", + "3️⃣) Anonymity of Hololive and Holostars participants is prohibited: \n- Photos\n- Names\n- Place of residence\n- Exact age (the word \"holohegs\" does not apply)\n- Details of personal life\n- Posts from rummage accounts or mentioning them with specific data (i.e. the phrase \"something happened on Kalli's irl channel\" is allowed, but \"something happened on *irl channel name*\" - no) \n- Details from the girls' past - only superficially and without specifics (i.e. \"was an office worker\" - ok, \"was in *company_name\" - no). \nExceptions - if the girls themselves mentioned it on the archive(!) streams.... This rule does not apply to those who are no longer in Hololive, or have never been part of it. But, please, treat the personal life of other vloggers with respect, and do not exaggerate with the deanons of their personalities.", + "4️⃣) Flooding with the same type of messages, emojis, emoticons, stickers, gifs, etc. is prohibited. The approximate number of messages that can receive a warning for this rule is 5. Each situation can be considered separately, but put all your thoughts in one message.", + "5️⃣) Video and audio messages that are not intended to convey what you have heard or seen are prohibited. If you want to tell us about how your day went, but do not have the opportunity to type a message, use the magical video-to-text converter - https://t.me/voicybot", + "6️⃣) Insults, threats, bullying, humiliation, trolling of participants, their family members, friends and other circle that is close to the chat participant are prohibited. Messages like: \"go to ... \" - are also insults. You can get a warning even if it was your friend. It will be removed if your friend confirms that he is not offended by you.\n🔨 If at the request of a member or administrator, you do not change the pace of communication and do not apologize, you will receive a warning.\nIf your behavior causes a member to leave the chat, the punishment may be more severe.", + "7️⃣) It is forbidden to provoke conflicts and incite hatred between chat participants.", + "8️⃣) Racism, sexism, homophobia and condemnation of political and (or) religious prejudice are prohibited. These topics can still be part of the dialogue if they do not contain direct condemnations, insults, etc.", + "9️⃣) Avatars, nicknames, roles that violate other rules are prohibited." + ], + "rules_additional": "Additional rules that are advisory in nature, and have no explicit penalties for violations:\n1️⃣) There is no ban on the Russian language in the chat. We respect every Ukrainian and do not want to incite language conflicts.\n2️↪Mn_e_20E3↩) There is no ban on Russian content in the chat. But, keep in mind that participants, for the most part, will not be interested in discussing it and it may be ignored.) Do not abuse swear words. Try to communicate in clean language.\n4️⃣) Respect the copyright of content makers. If you find art, animation, music, etc., on official resources (pixiv, twitter, deviantart, etc.), send a link to it.\nIf someone sent art from a non-official resource and you want to know its author, send a message with the text `/search` to the message with the art.", + "commands": { + "rules": "Check out the rules", + "nearby": "Show users near the area", + "reapply": "Resubmit the application", + "sponsorship": "Apply for sponsor role" + }, + "commands_admin": { + "reboot": "Restart the bot", + "message": "Send a message", + "label": "Set user's nickname", + "warnings": "Check user's warnings", + "application": "Check user's application", + "applications": "Retrieve all applications as a JSON" + }, + "commands_group_admin": { + "reboot": "Restart the bot", + "message": "Send a message", + "label": "Set user's nickname", + "nearby": "Show users near the area", + "warnings": "Check user's warnings", + "application": "Check user's application", + "applications": "Retrieve all applications as a JSON" + }, + "commands_group_destination": { + "warn": "Warn a user", + "nearby": "Show users near the area" + } +} \ No newline at end of file -- 2.39.2 From 95e9fdf4609475131411df2513a4e484c64fcaeb Mon Sep 17 00:00:00 2001 From: profitroll Date: Thu, 22 Dec 2022 15:05:27 +0100 Subject: [PATCH 09/30] Added sponsorship support --- classes/holo_user.py | 132 ++++++++++++++++++++++++++++--- locale/uk.json | 24 +++++- modules/callbacks/reapply.py | 2 +- modules/callbacks/sponsorship.py | 65 ++++++++++----- modules/handlers/confirmation.py | 79 +++++++++++++++--- modules/handlers/everything.py | 1 + modules/handlers/sponsorship.py | 9 ++- modules/scheduled.py | 25 +++++- 8 files changed, 294 insertions(+), 43 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 7454141..eeba107 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -1,4 +1,6 @@ from datetime import datetime +from os import sep +from uuid import uuid1 from requests import get from traceback import print_exc from app import app, isAnAdmin @@ -35,6 +37,24 @@ class DefaultApplicationTemp(dict): } } +class DefaultSponsorshipTemp(dict): + def __init__(self, user: int): + super().__init__({}) + self.dict = { + "user": user, + "type": "sponsorship", + "complete": False, + "sent": False, + "state": "fill", + "stage": 1, + "sponsorship": { + "streamer": None, + "expires": datetime.fromtimestamp(0), + "proof": None, + "label": "" + } + } + class UserNotFoundError(Exception): """HoloUser could not find user with such an ID in database""" def __init__(self, user, user_id): @@ -103,18 +123,18 @@ class HoloUser(): if isinstance(user, User): if (self.name != user.first_name) and hasattr(user, "first_name") and (user.first_name is not None): - self.set("tg_name", user.first_name) + self.set("name", user.first_name, db_key="tg_name") - if (self.phone != user.phone_number) and hasattr(user, "phone_number") and (user.phone_number is not None): - self.set("tg_phone", user.phone_number) + 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, "language_code") and (user.language_code is not None): - self.set("tg_locale", user.language_code) + 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): - self.set("tg_username", user.username) + self.set("username", user.username, db_key="tg_username") - def set(self, key: str, value: Any) -> None: + def set(self, key: str, value: Any, db_key: Union[str, None] = None) -> None: """Set attribute data and save it into database ### Args: @@ -124,7 +144,8 @@ class HoloUser(): if not hasattr(self, key): raise AttributeError() setattr(self, key, value) - col_users.update_one(filter={"_id": self.db_id}, update={ "$set": { key: value } }, upsert=True) + 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) logWrite(f"Set attribute {key} of user {self.id} to {value}") async def message(self, @@ -394,4 +415,97 @@ class HoloUser(): logWrite(f"User {self.id} completed stage {stage} of application") else: - return \ No newline at end of file + return + + 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 + else: + return tmp_sponsorship["state"], tmp_sponsorship["complete"] + + def sponsorship_valid(self) -> bool: + """Check whether user has a valid sponsorship + + ### 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 + + def sponsorship_restart(self) -> None: + """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: + """Move on filling sponsorship of user + + ### Args: + * query (`str`): Some kind of input + * msg (`Message`): Message that should receive replies + """ + + if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is not None: + + progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) + stage = progress["stage"] + + if progress["state"] == "fill": + + if stage == 1: + + 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)))) + + 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)))) + 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)))) + 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)))) + + elif stage == 3: + + if photo is not None: + filename = uuid1() + await app.download_media(photo.file_id, f"tmp{sep}{filename}") + with open(f"tmp{sep}{filename}", "rb") as f: + photo_bytes = f.read() + progress["sponsorship"]["proof"] = photo_bytes + 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: + progress["sponsorship"]["label"] = query + col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}}) + await msg.reply_text("Sponsorship application is filled. Want to send it?", reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) + + else: + return + + logWrite(f"User {self.id} completed stage {stage} of sponsorship") + + else: + return \ No newline at end of file diff --git a/locale/uk.json b/locale/uk.json index 7ecc50d..1a4e63c 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -24,12 +24,16 @@ "sponsor1": "На яку саме дівчину платна підписка?", "sponsor2": "До якої дати (`ДД.ММ.РРРР`) підписка?", "sponsor2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`", + "sponsor2_past": "Вказана дата знаходиться в минулому. Будь ласка, вкажіть правильний термін дії підписки", "sponsor3": "Будь ласка, надішли одне фото для підтвердження дійсності підписки", + "sponsor4": "Яку роль ти бажаєш отримати?", "sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.", "confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?", "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)", - "application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`, `{2}`\nЮзернейм: @{3}\n\n**Дані анкети:**\n{4}", - "reapply_got": "Отримано змінити анкети від `{0}`\n\nІм'я тг: `{1}`, `{2}`\nЮзернейм: @{3}\n\n**Дані анкети:**\n{4}", + "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}", "shutdown": "Вимкнення бота з підом `{0}`", "startup": "Запуск бота з підом `{0}`", "startup_downtime": "Запуск бота з підом `{0}` (лежав {1})", @@ -43,6 +47,10 @@ "rejected_by": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`.", "rejected_by_agr": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: агресивна/токсична анкета.", "rejected_by_rus": "❌ **Анкету відхилено**\nАдмін **{0}** переглянув та відхилив анкету `{1}`, заборонивши вступ до спільноти.\nПричина: русня.", + "sponsor_approved": "Вітаємо! Твою форму переглянули та підтвердили її правильність. Коли термін дії наданої підписки буде добігати кінця - ми нагадаємо, що треба оновити дані аби й надалі отримувати плюшки в боті. Гарного дня!", + "sponsor_rejected": "Ой лишенько! Твою форму переглянули, однак не підтвердили її. Можливо, щось не так з датами, або ж бажана роль не може бути надана.\n\nТи можеш спробувати повторно заповнити форму командою /sponsorship", + "sponsor_approved_by": "✅ **Підписку схвалено**\nАдмін **{0}** переглянув та схвалив форму `{1}`.", + "sponsor_rejected_by": "❌ **Підписку відхилено**\nАдмін **{0}** переглянув та відхилив форму `{1}`.", "contact": "Анкета `{0}`\n\n**Дані анкети:**\n{1}\n\n{2}", "application_status_accepted": "Прийнята `{0}` від {1}", "application_status_rejected": "Відхилена `{0}` від {1}", @@ -77,6 +85,8 @@ "no_user_application": "Не знайдено користувачів за запитом **{0}**", "user_invalid": "Надісланий користувач не має завершеної анкети.", "joined_false_link": "Користувач **{0}** (`{1}`) приєднався до групи не за своїм посиланням", + "sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!", + "sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.", "voice_message": [ "why are u gae", "руки відірвало? пиши як людина", @@ -93,6 +103,11 @@ "question8": "Дивлюсь стріми:", "question9": "Подобаються пісні:", "question10": "Про себе:" + }, + "sponsor_titles": { + "question_streamer": "Стрімер:", + "question_expires": "Підписка до:", + "question_label": "Хоче роль:" } }, "keyboard": { @@ -131,13 +146,16 @@ "question10": "Трошки про себе", "sponsor1": "Ім'я дівчини", "sponsor2": "Дата до якої підписка", - "sponsor3": "Фото-підтвердження" + "sponsor3": "Фото-підтвердження", + "sponsor4": "Бажана роль" }, "button": { "sub_yes": "✅ Прийняти", "sub_no": "❌ Відхилити", "sub_aggressive": "🤡 Відхилити (Токс)", "sub_russian": "🇷🇺 Відхилити (Русак)", + "sponsor_yes": "✅ Прийняти", + "sponsor_no": "❌ Відхилити", "accepted": "✅ Прийнято", "declined": "❌ Відхилено", "join": "Приєднатись", diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index fe693ac..9d0f53c 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -77,7 +77,7 @@ async def callback_query_reapply_reject(app, clb): async def callback_query_reapply_old(app, clb): fullclb = clb.data.split("_") message = await app.get_messages(clb.from_user.id, int(fullclb[2])) - await confirm_yes(app, message) + 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")]])) # Start a new application when user reapplies after leaving the chat diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index c0e6a95..ad52f1f 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -1,10 +1,10 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply from pyrogram import filters from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite -from modules.database import col_tmp,col_sponsorships +from modules.database import col_tmp, col_sponsorships # Callbacks sponsorship ======================================================================================================== @app.on_callback_query(filters.regex("sponsor_apply_[\s\S]*")) @@ -15,24 +15,51 @@ async def callback_query_sponsor_apply(app, clb): logWrite(f"User {holo_user.id} applied for sponsorship") - col_tmp.insert_one( - { - "user": holo_user.id, - "type": "sponsorship", - "complete": False, - "sent": False, - "state": "fill", - "stage": 1, - "sponsorship": { - "streamer": None, - "expires": datetime.fromtimestamp(0), - "proof": None, - "label": "" - } - } - ) + holo_user.sponsorship_restart() edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]] await clb.message.edit(text=locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup(edited_markup)) - await clb.answer(text=locale("sponsor_started", "callback").format(holo_user.id), show_alert=False) \ No newline at end of file + 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)))) + await clb.answer(text=locale("sponsor_started", "callback").format(holo_user.id), show_alert=False) + +@app.on_callback_query(filters.regex("sponsor_yes_[\s\S]*")) +async def callback_query_sponsor_yes(app, clb): + + fullclb = clb.data.split("_") + holo_user = HoloUser(int(fullclb[2])) + + await app.send_message(configGet("admin_group"), 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 approved by {clb.from_user.id}") + + if col_sponsorships.find_one({"user": holo_user.id}) is not None: + col_sponsorships.update_one({"date": {"$eq": datetime.now()}, "admin": {"$eq": clb.from_user.id}, "sponsorship": {"$eq": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}}) + else: + col_sponsorships.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "sponsorship": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}) + + col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"state": "approved", "sent": False}}) + + await holo_user.set_label(configGet("destination_group"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"]) + + 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=f"✅ Confirmed {fullclb[2]}", show_alert=False) + +@app.on_callback_query(filters.regex("sponsor_no_[\s\S]*")) +async def callback_query_sponsor_no(app, clb): + + fullclb = clb.data.split("_") + holo_user = HoloUser(int(fullclb[2])) + + await app.send_message(configGet("admin_group"), 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 rejected by {clb.from_user.id}") + + col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"state": "rejected", "sent": False}}) + + 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=f"❌ Rejected {fullclb[2]}", show_alert=False) \ No newline at end of file diff --git a/modules/handlers/confirmation.py b/modules/handlers/confirmation.py index 207c6be..4cbdf55 100644 --- a/modules/handlers/confirmation.py +++ b/modules/handlers/confirmation.py @@ -1,8 +1,11 @@ +from os import remove, sep +from typing import Literal +from uuid import uuid1 from dateutil.relativedelta import relativedelta from datetime import datetime from app import app from pyrogram import filters -from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton, ForceReply from pyrogram.enums.parse_mode import ParseMode from classes.holo_user import HoloUser from modules.utils import all_locales, configGet, locale, logWrite @@ -14,13 +17,11 @@ confirmation_1 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_1.append(pattern[0][0]) @app.on_message(~ filters.scheduled & filters.private & filters.command(confirmation_1, prefixes=[""])) -async def confirm_yes(app, msg): +async def confirm_yes(app, msg, kind: Literal["application", "sponsorship"] = "unknown"): holo_user = HoloUser(msg.from_user) - if (holo_user.application_state()[0] == "fill") and (holo_user.application_state()[1] is True): - - await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove()) + 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"}) @@ -28,6 +29,11 @@ async def confirm_yes(app, msg): logWrite(f"Application of {holo_user.id} is nowhere to be found.") return + if tmp_application["sent"] is True: + return + + await msg.reply_text(locale("application_sent", "message"), reply_markup=ReplyKeyboardRemove()) + application_content = [] i = 1 @@ -47,7 +53,7 @@ async def confirm_yes(app, msg): i += 1 if tmp_application["reapply"]: - await app.send_message(chat_id=configGet("admin_group"), text=(locale("reapply_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup( + await app.send_message(chat_id=configGet("admin_group"), 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}") @@ -59,7 +65,7 @@ async def confirm_yes(app, msg): ) ) else: - await app.send_message(chat_id=configGet("admin_group"), text=(locale("application_got", "message")).format(str(holo_user.id), msg.from_user.first_name, msg.from_user.last_name, msg.from_user.username, "\n".join(application_content)), parse_mode=ParseMode.MARKDOWN, reply_markup=InlineKeyboardMarkup( + await app.send_message(chat_id=configGet("admin_group"), 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}") @@ -81,19 +87,74 @@ async def confirm_yes(app, msg): col_tmp.update_one({"user": holo_user.id, "type": "application"}, {"$set": {"sent": True}}) + return + # configSet(["sent"], True, file=str(holo_user.id)) # configSet(["confirmed"], True, file=str(holo_user.id)) + 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.") + return + + if tmp_sponsorship["sent"] is True: + return + + await msg.reply_text(locale("sponsorship_sent", "message"), reply_markup=ReplyKeyboardRemove()) + + sponsorship_content = [] + + 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')}") + elif question == "proof": + filename = uuid1() + with open(f"tmp{sep}{filename}.jpg", "wb") as f: + f.write(tmp_sponsorship['sponsorship']['proof']) + else: + sponsorship_content.append(f"{locale(f'question_{question}', 'message', 'sponsor_titles')} {tmp_sponsorship['sponsorship'][question]}") + + await app.send_photo(chat_id=configGet("admin_group"), photo=f"tmp{sep}{filename}.jpg", 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_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") + + 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(~ filters.scheduled & filters.private & filters.command(confirmation_2, prefixes=[""])) -async def confirm_no(app, msg): +async def confirm_no(app, msg, kind: Literal["application", "sponsorship"] = "unknown"): holo_user = HoloUser(msg.from_user) - if (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") + return + + 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") + return # ============================================================================================================================== \ No newline at end of file diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index b42ca19..5a37c89 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -52,6 +52,7 @@ async def any_stage(app, msg): if msg.text is not None: await holo_user.application_next(msg.text, msg=msg) + await holo_user.sponsorship_next(msg.text, msg=msg) # user_stage = configGet("stage", file=str(msg.from_user.id)) diff --git a/modules/handlers/sponsorship.py b/modules/handlers/sponsorship.py index 393405e..1fb1adb 100644 --- a/modules/handlers/sponsorship.py +++ b/modules/handlers/sponsorship.py @@ -1,6 +1,13 @@ from app import app from pyrogram import filters +from classes.holo_user import HoloUser + @app.on_message(~ filters.scheduled & filters.photo & filters.private) async def sponsor_proof(app, msg): - pass \ No newline at end of file + + if msg.via_bot is None: + + holo_user = HoloUser(msg.from_user) + + await holo_user.sponsorship_next(msg.text, msg=msg, photo=msg.photo) \ No newline at end of file diff --git a/modules/scheduled.py b/modules/scheduled.py index 81c5ce6..8eb63ec 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -5,9 +5,10 @@ from app import app from pyrogram.types import BotCommand, BotCommandScopeChat from pyrogram.errors import bad_request_400 from pyrogram.enums.chat_members_filter import ChatMembersFilter +from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite from dateutil.relativedelta import relativedelta -from modules.database import col_applications +from modules.database import col_applications, col_sponsorships scheduler = AsyncIOScheduler() @@ -47,6 +48,28 @@ if configGet("enabled", "scheduler", "birthdays"): if configGet("enabled", "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)}}): + try: + tg_user = await app.get_users(entry["user"]) + until_expiry = relativedelta(datetime.now(), entry["sponsorship"]["expires"]).days + await app.send_message( tg_user, locale("sponsorships_expires", "message").format(until_expiry) ) # type: ignore + logWrite(f"Notified 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}'") + continue + for entry in col_sponsorships.find({"sponsorship.expires": {"$lt": datetime.now()}}): + try: + holo_user = HoloUser(entry["user"]) + await app.send_message( entry["user"], locale("sponsorships_expired", "message") ) # type: ignore + await holo_user.reset_label(configGet("destination_group")) + try: + tg_user = await app.get_users(entry["user"]) + logWrite(f"Notified user that sponsorship expires in {until_expiry} days") + except Exception as 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}'") + continue logWrite("Sponsorships check performed") -- 2.39.2 From 7db8c9ac5c134cf2bf733203e07244a5cdfa261e Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:11:15 +0100 Subject: [PATCH 10/30] Fixed label length on set --- classes/holo_user.py | 3 +++ locale/uk.json | 1 + modules/callbacks/sponsorship.py | 2 +- modules/commands/label.py | 5 ++++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index eeba107..7e423dd 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -498,6 +498,9 @@ class HoloUser(): 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")) + return progress["sponsorship"]["label"] = query col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}}) await msg.reply_text("Sponsorship application is filled. Want to send it?", reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) diff --git a/locale/uk.json b/locale/uk.json index 1a4e63c..292964f 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -87,6 +87,7 @@ "joined_false_link": "Користувач **{0}** (`{1}`) приєднався до групи не за своїм посиланням", "sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!", "sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.", + "label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів", "voice_message": [ "why are u gae", "руки відірвало? пиши як людина", diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index ad52f1f..43e6cca 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -34,7 +34,7 @@ async def callback_query_sponsor_yes(app, clb): logWrite(f"User {holo_user.id} got approved by {clb.from_user.id}") if col_sponsorships.find_one({"user": holo_user.id}) is not None: - col_sponsorships.update_one({"date": {"$eq": datetime.now()}, "admin": {"$eq": clb.from_user.id}, "sponsorship": {"$eq": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}}) + col_sponsorships.update_one({"user": holo_user.id}, {"date": {"$eq": datetime.now()}, "admin": {"$eq": clb.from_user.id}, "sponsorship": {"$eq": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}}) else: col_sponsorships.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "sponsorship": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}) diff --git a/modules/commands/label.py b/modules/commands/label.py index 5a3edcd..d871b47 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -1,6 +1,6 @@ from app import app, isAnAdmin from pyrogram import filters -from modules.utils import should_quote, find_user +from modules.utils import locale, should_quote, find_user from classes.holo_user import HoloUser @app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"])) @@ -25,6 +25,9 @@ async def cmd_label(app, msg): await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg)) else: + if len(label) > 16: + await msg.reply_text(locale("label_too_long", "message")) + return await target.set_label(msg.chat, label) await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg)) -- 2.39.2 From 12da1b2376e450156b8fe2b1a8d7af11bff21761 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:11:36 +0100 Subject: [PATCH 11/30] Added LabelTooLongError() and changed names --- classes/holo_user.py | 11 +++++++++-- modules/callbacks/sponsorship.py | 2 +- modules/commands/label.py | 4 ++-- modules/scheduled.py | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 7e423dd..b75d5e4 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -68,6 +68,11 @@ class UserInvalidError(Exception): self.user = user 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)") + 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, @@ -270,20 +275,22 @@ class HoloUser(): 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 set_label(self, chat: Chat, label: str) -> None: + async def label_set(self, chat: Chat, label: str) -> None: """Set label in destination group ### Args: * chat (`Chat`): Telegram chat * label (`str`): Label you want to set """ + if len(label) > 16: + raise LabelTooLongError(label) self.label = label self.set("label", label) await app.promote_chat_member(configGet("destination_group"), self.id) if not await isAnAdmin(self.id): await app.set_administrator_title(configGet("destination_group"), self.id, label) - async def reset_label(self, chat: Chat) -> None: + async def label_reset(self, chat: Chat) -> None: """Reset label in destination group ### Args: diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 43e6cca..76daf30 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -40,7 +40,7 @@ async def callback_query_sponsor_yes(app, clb): col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"state": "approved", "sent": False}}) - await holo_user.set_label(configGet("destination_group"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"]) + await holo_user.label_set(configGet("destination_group"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"]) edited_markup = [[InlineKeyboardButton(text=str(locale("accepted", "button")), callback_data="nothing")]] diff --git a/modules/commands/label.py b/modules/commands/label.py index d871b47..316cc30 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -21,14 +21,14 @@ async def cmd_label(app, msg): label = " ".join(msg.command[2:]) if label.lower() == "reset": - await target.reset_label(msg.chat) + await target.label_reset(msg.chat) await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg)) else: if len(label) > 16: await msg.reply_text(locale("label_too_long", "message")) return - await target.set_label(msg.chat, label) + await target.label_set(msg.chat, label) await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg)) else: diff --git a/modules/scheduled.py b/modules/scheduled.py index 8eb63ec..ae73e04 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -61,7 +61,7 @@ if configGet("enabled", "scheduler", "sponsorships"): try: holo_user = HoloUser(entry["user"]) await app.send_message( entry["user"], locale("sponsorships_expired", "message") ) # type: ignore - await holo_user.reset_label(configGet("destination_group")) + await holo_user.label_reset(configGet("destination_group")) try: tg_user = await app.get_users(entry["user"]) logWrite(f"Notified user that sponsorship expires in {until_expiry} days") -- 2.39.2 From 5a6a96d3f9d95c4144fbe719d08b2997455e2cdf Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:14:35 +0100 Subject: [PATCH 12/30] Delete sponsorships on expiry --- modules/scheduled.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/scheduled.py b/modules/scheduled.py index ae73e04..3da6b8d 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -62,9 +62,10 @@ if configGet("enabled", "scheduler", "sponsorships"): holo_user = HoloUser(entry["user"]) await app.send_message( entry["user"], locale("sponsorships_expired", "message") ) # type: ignore await holo_user.label_reset(configGet("destination_group")) + col_sponsorships.find_one_and_delete({"user": holo_user.id}) try: tg_user = await app.get_users(entry["user"]) - logWrite(f"Notified user that sponsorship expires in {until_expiry} days") + logWrite(f"Notified user that sponsorship expired") except Exception as exp: logWrite(f"Could not find user {entry['user']} notify about sponsorship expired due to '{exp}'") except Exception as exp: -- 2.39.2 From 0302d8c1ae58cb452854eb67c495f4a226386365 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 01:40:07 +0100 Subject: [PATCH 13/30] Removed unused --- modules/commands/sponsorship.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index 7665dc7..930f93f 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -1,4 +1,3 @@ -from datetime import datetime from app import app, isAnAdmin from pyrogram import filters from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton @@ -12,17 +11,4 @@ async def cmd_sponsorship(app, msg): await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg)) else: await msg.reply_text(locale("sponsorship_application_empty", "message")) - # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): - # jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") - # sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") - # if sponsor["approved"]: - # if sponsor["expires"] is not None: - # if datetime.strptime(sponsor["expires"], "%d.%m.%Y") > datetime.now(): - # await msg.reply_text(f"You have an active sub til **{sponsor['expires']}**.") - # else: - # await msg.reply_text(f"Your sub expired {int((datetime.now()-datetime.strptime(sponsor['expires'], '%d.%m.%Y')).days)} days ago.") - # elif sponsor["approved"]: - # await msg.reply_text(f"Your sub expiration date is not valid.") - # else: - # await msg.reply_text(f"You have no active subscription.") # ============================================================================================================================== \ No newline at end of file -- 2.39.2 From 426b1550f6212c7086cfa7f076339cdf92d3b5da Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 01:40:23 +0100 Subject: [PATCH 14/30] Initialized /cancel command --- holochecker.py | 1 + modules/commands/cancel.py | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 modules/commands/cancel.py diff --git a/holochecker.py b/holochecker.py index 73d4f23..bb70530 100644 --- a/holochecker.py +++ b/holochecker.py @@ -12,6 +12,7 @@ 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.label import * from modules.commands.message import * from modules.commands.nearby import * diff --git a/modules/commands/cancel.py b/modules/commands/cancel.py new file mode 100644 index 0000000..654332b --- /dev/null +++ b/modules/commands/cancel.py @@ -0,0 +1,7 @@ +from app import app +from pyrogram import filters +from modules.utils import should_quote + +@app.on_message(~ filters.scheduled & filters.command("cancel", prefixes=["/"])) +async def command_cancel(app, msg): + await msg.reply_text("Command exists.", quote=should_quote(msg)) \ No newline at end of file -- 2.39.2 From eecb71a91ee12f79cc2cdadc6f7d7afeefa3bb94 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 01:44:07 +0100 Subject: [PATCH 15/30] Updated label_set --- classes/holo_user.py | 6 ++++-- modules/commands/label.py | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index b75d5e4..dbd890a 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -286,7 +286,7 @@ class HoloUser(): raise LabelTooLongError(label) self.label = label self.set("label", label) - await app.promote_chat_member(configGet("destination_group"), self.id) + await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges(can_pin_messages=True, can_manage_video_chats=True)) if not await isAnAdmin(self.id): await app.set_administrator_title(configGet("destination_group"), self.id, label) @@ -301,7 +301,9 @@ class HoloUser(): await app.set_administrator_title(configGet("destination_group"), self.id, "") if not await isAnAdmin(self.id): await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges( - can_manage_chat=False + can_manage_chat=False, + can_pin_messages=False, + can_manage_video_chats=False )) def application_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: diff --git a/modules/commands/label.py b/modules/commands/label.py index 316cc30..4e7e552 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -1,7 +1,7 @@ from app import app, isAnAdmin from pyrogram import filters from modules.utils import locale, should_quote, find_user -from classes.holo_user import HoloUser +from classes.holo_user import HoloUser, LabelTooLongError @app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"])) async def cmd_label(app, msg): @@ -25,10 +25,11 @@ async def cmd_label(app, msg): await msg.reply_text(f"Resetting **{target.id}**'s label...", quote=should_quote(msg)) else: - if len(label) > 16: + try: + await target.label_set(msg.chat, label) + except LabelTooLongError: await msg.reply_text(locale("label_too_long", "message")) return - await target.label_set(msg.chat, label) await msg.reply_text(f"Setting **{target.id}**'s label to **{label}**...", quote=should_quote(msg)) else: -- 2.39.2 From 1eb98750a7aac3c8d413138aa636cc3369f9a59e Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 01:44:21 +0100 Subject: [PATCH 16/30] Changed sponsorship locale --- locale/uk.json | 3 ++- modules/callbacks/sponsorship.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index 292964f..1e41026 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -20,7 +20,8 @@ "question3_found": "Використовую наступний результат:\n• {0} ({1})", "question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.", "question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```", - "sponsorship_apply": "ℹ️ Розпочато заповнення форми на отримання бонусів за платну підписку на холодівчат.", + "sponsorship_apply": "ℹ️ Оформіть платну підписку на когось з Холо, заповніть форму та отримайте особливу роль в якості винагороди!", + "sponsorship_applying": "ℹ️ Розпочато заповнення форми на отримання бонусів за платну підписку на холодівчат.", "sponsor1": "На яку саме дівчину платна підписка?", "sponsor2": "До якої дати (`ДД.ММ.РРРР`) підписка?", "sponsor2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`", diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 76daf30..e639661 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -19,7 +19,7 @@ async def callback_query_sponsor_apply(app, clb): edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]] - await clb.message.edit(text=locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup(edited_markup)) + await clb.message.edit(text=locale("sponsorship_applying", "message"), reply_markup=InlineKeyboardMarkup(edited_markup)) 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)))) await clb.answer(text=locale("sponsor_started", "callback").format(holo_user.id), show_alert=False) -- 2.39.2 From af862a345458bc60f8964235d8d67b4cac74ec82 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 01:49:38 +0100 Subject: [PATCH 17/30] Added messages to sponsor's locale --- classes/holo_user.py | 2 +- locale/uk.json | 5 ++++- modules/callbacks/sponsorship.py | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index dbd890a..c6856c1 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -512,7 +512,7 @@ class HoloUser(): return progress["sponsorship"]["label"] = query col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}}) - await msg.reply_text("Sponsorship application is filled. Want to send it?", reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) + await msg.reply_text(locale("sponsor_confirm", "message"), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) else: return diff --git a/locale/uk.json b/locale/uk.json index 1e41026..ecbea7e 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -30,6 +30,7 @@ "sponsor4": "Яку роль ти бажаєш отримати?", "sponsorship_application_empty": "❌ **Дія неможлива**\nУ тебе немає заповненої та схваленої анкети. Заповни таку за допомогою /reapply та спробуй ще раз після її підтвердження.", "confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?", + "sponsor_confirm": "Здається, це все. Перевір чи все правильно та жмакни кнопку на клавіатурі щоб продовжити.", "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)", "sponsorship_sent": "Дякуємо! Ми надіслали форму на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. Гарного дня! :)", "application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`\nЮзернейм: @{2}\n\n**Дані анкети:**\n{3}", @@ -190,7 +191,9 @@ "rules_home": "ℹ️ Показано головну правил", "rules_additional": "ℹ️ Показано додаткові правила", "reapply_stopped": "ℹ️ Перервано заповнення анкети", - "sponsor_started": "ℹ️ Заповнення форми розпочато" + "sponsor_started": "ℹ️ Заповнення форми розпочато", + "sponsor_accepted": "✅ Форму {0} схвалено", + "sponsor_rejected": "❌ Форму {0} відхилено" }, "inline": { "forbidden": { diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index e639661..3abbcd5 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -45,7 +45,7 @@ async def callback_query_sponsor_yes(app, clb): 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=f"✅ Confirmed {fullclb[2]}", show_alert=False) + 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, clb): @@ -62,4 +62,4 @@ async def callback_query_sponsor_no(app, clb): 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=f"❌ Rejected {fullclb[2]}", show_alert=False) \ No newline at end of file + await clb.answer(text=locale("sponsor_rejected", "callback").format(fullclb[2]), show_alert=False) \ No newline at end of file -- 2.39.2 From 85112dc653d9af6da67643b99030f07114a671c1 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 23 Dec 2022 12:54:51 +0100 Subject: [PATCH 18/30] Fixed some bugs --- classes/holo_user.py | 12 +++++------ modules/callbacks/reapply.py | 2 +- modules/callbacks/sponsorship.py | 37 ++++++++++++++++++++++++++++---- modules/commands/reapply.py | 2 +- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index c6856c1..766e2ff 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -13,7 +13,7 @@ from modules.logging import logWrite from modules.utils import configGet, locale, should_quote class DefaultApplicationTemp(dict): - def __init__(self, user: int): + def __init__(self, user: int, reapply: bool = False): super().__init__({}) self.dict = { "user": user, @@ -21,7 +21,7 @@ class DefaultApplicationTemp(dict): "complete": False, "sent": False, "state": "fill", - "reapply": False, + "reapply": reapply, "stage": 1, "application": { "1": None, @@ -326,14 +326,14 @@ class HoloUser(): """ return True if col_applications.find_one({"user": self.id}) is not None else False - def application_restart(self) -> None: + def application_restart(self, reapply: bool = False) -> None: """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).dict) else: col_tmp.delete_one({"user": self.id, "type": "application"}) - col_tmp.insert_one(document=DefaultApplicationTemp(self.id).dict) + col_tmp.insert_one(document=DefaultApplicationTemp(self.id, reapply=reapply).dict) async def application_next(self, query: str, msg: Message) -> None: """Move on filling application of user @@ -352,7 +352,7 @@ class HoloUser(): progress = col_tmp.find_one({"user": self.id, "type": "application"}) stage = progress["stage"] - if progress["state"] == "fill": + if progress["state"] == "fill" and progress["sent"] is False: if stage == 2: @@ -468,7 +468,7 @@ class HoloUser(): progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) stage = progress["stage"] - if progress["state"] == "fill": + if progress["state"] == "fill" and progress["sent"] is False: if stage == 1: diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index 9d0f53c..185467a 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -22,7 +22,7 @@ async def callback_reapply_query_accept(app, clb): col_applications.delete_one({"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_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "application"}}, {"$set": {"state": "approved", "sent": False}}) + 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")]] diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 3abbcd5..6b2fdd4 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -34,11 +34,33 @@ async def callback_query_sponsor_yes(app, clb): logWrite(f"User {holo_user.id} got 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}, {"date": {"$eq": datetime.now()}, "admin": {"$eq": clb.from_user.id}, "sponsorship": {"$eq": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}}) + 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"] + } + } + ) else: - col_sponsorships.insert_one({"user": holo_user.id, "date": datetime.now(), "admin": clb.from_user.id, "sponsorship": col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]}) + col_sponsorships.insert_one( + { + "user": holo_user.id, + "date": datetime.now(), + "admin": clb.from_user.id, + "sponsorship": col_tmp.find_one({"user": holo_user.id, "type": "sponsorship"})["sponsorship"] + } + ) - col_tmp.update_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"state": "approved", "sent": False}}) + col_tmp.update_one({"user": holo_user.id, "type":"sponsorship"}, + { + "$set": { + "state": "approved", + "sent": False + } + } + ) await holo_user.label_set(configGet("destination_group"), col_tmp.find_one({"user": {"$eq": holo_user.id}, "type": {"$eq": "sponsorship"}})["sponsorship"]["label"]) @@ -57,7 +79,14 @@ async def callback_query_sponsor_no(app, clb): await app.send_message(holo_user.id, locale("sponsor_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": "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")]] diff --git a/modules/commands/reapply.py b/modules/commands/reapply.py index 0936bf8..635b3ca 100644 --- a/modules/commands/reapply.py +++ b/modules/commands/reapply.py @@ -19,7 +19,7 @@ async def cmd_reapply(app, msg): if member.user.id == msg.from_user.id: left_chat = False if not left_chat: - holo_user.application_restart() + holo_user.application_restart(reapply=True) await welcome_pass(app, msg, once_again=True) else: await msg.reply_text(locale("reapply_left_chat", "message", locale=holo_user), reply_markup=InlineKeyboardMarkup([ -- 2.39.2 From 47896faf068caaadd973dee65c7089c36127529e Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:23:24 +0100 Subject: [PATCH 19/30] Application and sponsorship crosscheck --- classes/holo_user.py | 4 ++++ locale/uk.json | 2 ++ modules/callbacks/reapply.py | 11 ++++++++++- modules/callbacks/sponsorship.py | 11 ++++++++--- modules/commands/reapply.py | 5 ++++- modules/commands/sponsorship.py | 4 ++++ 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 766e2ff..f10f3ff 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -351,6 +351,10 @@ class HoloUser(): progress = col_tmp.find_one({"user": self.id, "type": "application"}) 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: diff --git a/locale/uk.json b/locale/uk.json index ecbea7e..9178313 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -90,6 +90,8 @@ "sponsorships_expires": "⚠️ **Нагадування**\nНадана платна підписка припинить діяти **за {0} д**. Будь ласка, оновіть дані про неї командою /sponsorship інакше роль буде втрачено!", "sponsorships_expired": "⚠️ **Нагадування**\nТермін дії вказаної підписки сплив. Для повторного отримання ролі користуйся командою /sponsorship.", "label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів", + "finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.", + "finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.", "voice_message": [ "why are u gae", "руки відірвало? пиши як людина", diff --git a/modules/callbacks/reapply.py b/modules/callbacks/reapply.py index 185467a..e75a529 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -3,7 +3,7 @@ from app import app from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove from pyrogram import filters from classes.holo_user import HoloUser -from modules.utils import configGet, locale, logWrite +from modules.utils import configGet, locale, logWrite, should_quote from modules.handlers.confirmation import confirm_yes from modules.handlers.welcome import welcome_pass from modules.database import col_tmp, col_applications @@ -76,6 +76,11 @@ async def callback_query_reapply_reject(app, clb): @app.on_callback_query(filters.regex("reapply_old_[\s\S]*")) async def callback_query_reapply_old(app, clb): fullclb = clb.data.split("_") + + if HoloUser(clb.from_user).sponsorship_state()[0] == "fill": + await clb.message.reply_text(locale("finish_sponsorship", "message"), quote=False)) + return + message = await app.get_messages(clb.from_user.id, int(fullclb[2])) 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")]])) @@ -86,6 +91,10 @@ async def callback_query_reapply_new(app, clb): fullclb = clb.data.split("_") + if HoloUser(clb.from_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}}) diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 6b2fdd4..584459b 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -1,18 +1,23 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ForceReply, 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.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, clb): +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)) + return + logWrite(f"User {holo_user.id} applied for sponsorship") holo_user.sponsorship_restart() diff --git a/modules/commands/reapply.py b/modules/commands/reapply.py index 635b3ca..92d0c02 100644 --- a/modules/commands/reapply.py +++ b/modules/commands/reapply.py @@ -2,7 +2,7 @@ from app import app from pyrogram import filters from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton from classes.holo_user import HoloUser -from modules.utils import configGet, locale +from modules.utils import configGet, locale, should_quote from modules.handlers.welcome import welcome_pass from modules.database import col_tmp @@ -19,6 +19,9 @@ async def cmd_reapply(app, msg): if member.user.id == msg.from_user.id: left_chat = False if not left_chat: + if holo_user.sponsorship_state()[0] == "fill": + 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: diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index 930f93f..9efb263 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -1,6 +1,7 @@ from app import app, isAnAdmin from pyrogram import filters from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from classes.holo_user import HoloUser from modules.utils import locale, should_quote from modules.database import col_applications @@ -8,6 +9,9 @@ from modules.database import col_applications @app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"])) async def cmd_sponsorship(app, msg): if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): + if HoloUser(msg.from_user).application_state()[0] == "fill": + await msg.reply_text(locale("finish_application", "message"), quote=should_quote(msg)) + return await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg)) else: await msg.reply_text(locale("sponsorship_application_empty", "message")) -- 2.39.2 From 5e06859b562d41e241184650d85b417ea1611536 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:36:54 +0100 Subject: [PATCH 20/30] Improved typing and linting --- modules/callbacks/nothing.py | 4 +++- modules/callbacks/reapply.py | 19 ++++++++++--------- modules/callbacks/rules.py | 9 +++++---- modules/callbacks/sponsorship.py | 4 ++-- modules/callbacks/sub.py | 11 ++++++----- modules/callbacks/sus.py | 7 ++++--- modules/commands/application.py | 4 +++- modules/commands/applications.py | 4 +++- modules/commands/cancel.py | 4 +++- modules/commands/label.py | 4 +++- modules/commands/message.py | 4 +++- modules/commands/nearby.py | 4 +++- modules/commands/reapply.py | 5 +++-- modules/commands/reboot.py | 4 +++- modules/commands/rules.py | 5 +++-- modules/commands/sponsorship.py | 5 +++-- modules/commands/start.py | 5 +++-- modules/commands/warn.py | 4 +++- modules/commands/warnings.py | 4 +++- modules/handlers/confirmation.py | 7 ++++--- modules/handlers/contact.py | 4 +++- modules/handlers/everything.py | 5 +++-- modules/handlers/group_join.py | 5 +++-- modules/handlers/sponsorship.py | 4 +++- modules/handlers/voice.py | 4 +++- modules/handlers/welcome.py | 5 +++-- 26 files changed, 91 insertions(+), 53 deletions(-) diff --git a/modules/callbacks/nothing.py b/modules/callbacks/nothing.py index 8f4a719..538ed27 100644 --- a/modules/callbacks/nothing.py +++ b/modules/callbacks/nothing.py @@ -1,9 +1,11 @@ from app import app from pyrogram import filters +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, clb): +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 e75a529..5496b5c 100644 --- a/modules/callbacks/reapply.py +++ b/modules/callbacks/reapply.py @@ -1,6 +1,7 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove, CallbackQuery +from pyrogram.client import Client from pyrogram import filters from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite, should_quote @@ -10,7 +11,7 @@ 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, clb): +async def callback_reapply_query_accept(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -56,7 +57,7 @@ async def callback_reapply_query_accept(app, clb): 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, clb): +async def callback_query_reapply_reject(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -74,25 +75,25 @@ async def callback_query_reapply_reject(app, clb): # 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, clb): +async def callback_query_reapply_old(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") if HoloUser(clb.from_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])) 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")]])) # 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, clb): +async def callback_query_reapply_new(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") if HoloUser(clb.from_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)) @@ -104,7 +105,7 @@ async def callback_query_reapply_new(app, clb): # 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, clb): +async def callback_query_reapply_stop(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(clb.from_user) diff --git a/modules/callbacks/rules.py b/modules/callbacks/rules.py index 0a5a0ba..8cba64c 100644 --- a/modules/callbacks/rules.py +++ b/modules/callbacks/rules.py @@ -1,5 +1,6 @@ from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery +from pyrogram.client import Client from pyrogram.errors import bad_request_400 from pyrogram import filters from modules.utils import locale, logWrite @@ -7,7 +8,7 @@ from modules.commands.rules import DefaultRulesMarkup # Callback rule ================================================================================================================ @app.on_callback_query(filters.regex("rule_[\s\S]*")) -async def callback_query_rule(app, clb): +async def callback_query_rule(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") @@ -46,7 +47,7 @@ async def callback_query_rule(app, clb): 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, clb): +async def callback_query_rules_home(app: Client, clb: CallbackQuery): logWrite(f"User {clb.from_user.id} requested to check out homepage rules") @@ -58,7 +59,7 @@ async def callback_query_rules_home(app, clb): 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, clb): +async def callback_query_rules_additional(app: Client, clb: CallbackQuery): logWrite(f"User {clb.from_user.id} requested to check out additional rules") diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 584459b..16291a7 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -29,7 +29,7 @@ async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery): await clb.answer(text=locale("sponsor_started", "callback").format(holo_user.id), show_alert=False) @app.on_callback_query(filters.regex("sponsor_yes_[\s\S]*")) -async def callback_query_sponsor_yes(app, clb): +async def callback_query_sponsor_yes(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -75,7 +75,7 @@ async def callback_query_sponsor_yes(app, clb): 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, clb): +async def callback_query_sponsor_no(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) diff --git a/modules/callbacks/sub.py b/modules/callbacks/sub.py index 5eebb09..9347798 100644 --- a/modules/callbacks/sub.py +++ b/modules/callbacks/sub.py @@ -1,7 +1,8 @@ from datetime import datetime from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery from pyrogram import filters +from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import configGet, locale, logWrite from modules.database import col_tmp, col_applications @@ -9,7 +10,7 @@ from modules.commands.rules import DefaultRulesMarkup # Callbacks application ======================================================================================================== @app.on_callback_query(filters.regex("sub_yes_[\s\S]*")) -async def callback_query_accept(app, clb): +async def callback_query_accept(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -51,7 +52,7 @@ async def callback_query_accept(app, clb): 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, clb): +async def callback_query_reject(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -68,7 +69,7 @@ async def callback_query_reject(app, clb): 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_aggressive_[\s\S]*")) -async def callback_query_reject_aggressive(app, clb): +async def callback_query_reject_aggressive(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -85,7 +86,7 @@ async def callback_query_reject_aggressive(app, clb): await clb.answer(text=locale("sub_aggressive", "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, clb): +async def callback_query_reject_russian(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) diff --git a/modules/callbacks/sus.py b/modules/callbacks/sus.py index 50c6d52..ae37ca1 100644 --- a/modules/callbacks/sus.py +++ b/modules/callbacks/sus.py @@ -1,5 +1,6 @@ from app import app -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, ChatPermissions +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 @@ -7,7 +8,7 @@ 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, clb): +async def callback_query_sus_allow(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) @@ -29,7 +30,7 @@ async def callback_query_sus_allow(app, clb): ) @app.on_callback_query(filters.regex("sus_reject_[\s\S]*")) -async def callback_query_sus_reject(app, clb): +async def callback_query_sus_reject(app: Client, clb: CallbackQuery): fullclb = clb.data.split("_") holo_user = HoloUser(int(fullclb[2])) diff --git a/modules/commands/application.py b/modules/commands/application.py index 62d1e28..c079049 100644 --- a/modules/commands/application.py +++ b/modules/commands/application.py @@ -2,7 +2,9 @@ from datetime import datetime from app import app, isAnAdmin from pyrogram import filters from pyrogram.enums.parse_mode import ParseMode +from pyrogram.types import Message from pyrogram.errors import bad_request_400 +from pyrogram.client import Client from classes.holo_user import HoloUser, UserNotFoundError from modules.utils import logWrite, locale, should_quote from dateutil.relativedelta import relativedelta @@ -10,7 +12,7 @@ from modules.database import col_applications # Applications command ========================================================================================================= @app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"])) -async def cmd_application(app, msg): +async def cmd_application(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: diff --git a/modules/commands/applications.py b/modules/commands/applications.py index b0c29b8..a7b672c 100644 --- a/modules/commands/applications.py +++ b/modules/commands/applications.py @@ -2,6 +2,8 @@ from os import sep, makedirs, remove from uuid import uuid1 from app import app, isAnAdmin 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 @@ -9,7 +11,7 @@ from modules.database import col_applications # Applications command ========================================================================================================= @app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"])) -async def cmd_applications(app, msg): +async def cmd_applications(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: logWrite(f"Admin {msg.from_user.id} requested export of a database") diff --git a/modules/commands/cancel.py b/modules/commands/cancel.py index 654332b..5e06a44 100644 --- a/modules/commands/cancel.py +++ b/modules/commands/cancel.py @@ -1,7 +1,9 @@ from app import app from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import should_quote @app.on_message(~ filters.scheduled & filters.command("cancel", prefixes=["/"])) -async def command_cancel(app, msg): +async def command_cancel(app: Client, msg: Message): await msg.reply_text("Command exists.", quote=should_quote(msg)) \ No newline at end of file diff --git a/modules/commands/label.py b/modules/commands/label.py index 4e7e552..26dc16d 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -1,10 +1,12 @@ from app import app, isAnAdmin from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import locale, should_quote, find_user from classes.holo_user import HoloUser, LabelTooLongError @app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"])) -async def cmd_label(app, msg): +async def cmd_label(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: diff --git a/modules/commands/message.py b/modules/commands/message.py index 74ceeb4..159fd52 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -1,11 +1,13 @@ from app import app, isAnAdmin from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import logWrite, locale, should_quote # Message command ============================================================================================================== @app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"])) -async def cmd_message(app, msg): +async def cmd_message(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index d7a41ec..d771179 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -1,11 +1,13 @@ from app import app, isAnAdmin from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import configGet, should_quote from modules.database import col_applications # Nearby command =============================================================================================================== @app.on_message(~ filters.scheduled & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) -async def cmd_nearby(app, msg): +async def cmd_nearby(app: Client, msg: Message): if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): await msg.reply_text("Yes, I exist.", quote=should_quote(msg)) # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): diff --git a/modules/commands/reapply.py b/modules/commands/reapply.py index 92d0c02..bcb7ac5 100644 --- a/modules/commands/reapply.py +++ b/modules/commands/reapply.py @@ -1,6 +1,7 @@ from app import app from pyrogram import filters -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message +from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import configGet, locale, should_quote from modules.handlers.welcome import welcome_pass @@ -8,7 +9,7 @@ from modules.database import col_tmp # Reapply command ============================================================================================================== @app.on_message(~ filters.scheduled & filters.private & filters.command(["reapply"], prefixes=["/"])) -async def cmd_reapply(app, msg): +async def cmd_reapply(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) diff --git a/modules/commands/reboot.py b/modules/commands/reboot.py index 876d163..5c3d25a 100644 --- a/modules/commands/reboot.py +++ b/modules/commands/reboot.py @@ -2,6 +2,8 @@ from app import app, isAnAdmin from os import getpid from sys import exit from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import locale, logWrite, should_quote from modules.scheduled import scheduler @@ -9,7 +11,7 @@ pid = getpid() # Shutdown command ============================================================================================================= @app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) -async def cmd_kill(app, msg): +async def cmd_kill(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: logWrite(f"Shutting down bot with pid {pid}") diff --git a/modules/commands/rules.py b/modules/commands/rules.py index b75102f..98b6c39 100644 --- a/modules/commands/rules.py +++ b/modules/commands/rules.py @@ -1,7 +1,8 @@ from typing import Union from app import app from pyrogram import filters -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, User +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, User, Message +from pyrogram.client import Client from modules.utils import locale from classes.holo_user import HoloUser @@ -35,6 +36,6 @@ class DefaultRulesMarkup(list): # Rules command ============================================================================================================= @app.on_message(~ filters.scheduled & filters.private & filters.command(["rules"], prefixes=["/"])) -async def cmd_rules(app, msg): +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 diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index 9efb263..d57a2ad 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -1,13 +1,14 @@ from app import app, isAnAdmin from pyrogram import filters -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message +from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import locale, should_quote from modules.database import col_applications # Sponsorship command ========================================================================================================== @app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"])) -async def cmd_sponsorship(app, msg): +async def cmd_sponsorship(app: Client, msg: Message): if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): if HoloUser(msg.from_user).application_state()[0] == "fill": await msg.reply_text(locale("finish_application", "message"), quote=should_quote(msg)) diff --git a/modules/commands/start.py b/modules/commands/start.py index 6c89afe..ac26461 100644 --- a/modules/commands/start.py +++ b/modules/commands/start.py @@ -1,12 +1,13 @@ from app import app from pyrogram import filters -from pyrogram.types import ReplyKeyboardMarkup +from pyrogram.types import ReplyKeyboardMarkup, Message +from pyrogram.client import Client from modules.utils import locale, logWrite from modules.database import col_users # Start command ================================================================================================================ @app.on_message(~ filters.scheduled & filters.private & filters.command(["start"], prefixes=["/"])) -async def cmd_start(app, msg): +async def cmd_start(app: Client, msg: Message): user = col_users.find_one({"user": msg.from_user.id}) diff --git a/modules/commands/warn.py b/modules/commands/warn.py index 50f948c..9227b47 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -1,12 +1,14 @@ from datetime import datetime from app import app, isAnAdmin from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import configGet, locale from modules.database import col_warnings # Warn command ================================================================================================================= @app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"])) -async def cmd_warn(app, msg): +async def cmd_warn(app: Client, msg: Message): if msg.chat.id == configGet("destination_group"): if msg.reply_to_message_id != None: diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index fe43186..494f6e3 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -1,12 +1,14 @@ from app import app, isAnAdmin 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.database import col_users, col_warnings # Warnings command ============================================================================================================= @app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"])) -async def cmd_warnings(app, msg): +async def cmd_warnings(app: Client, msg: Message): if await isAnAdmin(msg.from_user.id) is True: diff --git a/modules/handlers/confirmation.py b/modules/handlers/confirmation.py index 4cbdf55..0878d05 100644 --- a/modules/handlers/confirmation.py +++ b/modules/handlers/confirmation.py @@ -5,7 +5,8 @@ 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 +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 from modules.utils import all_locales, configGet, locale, logWrite @@ -17,7 +18,7 @@ confirmation_1 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_1.append(pattern[0][0]) @app.on_message(~ filters.scheduled & filters.private & filters.command(confirmation_1, prefixes=[""])) -async def confirm_yes(app, msg, kind: Literal["application", "sponsorship"] = "unknown"): +async def confirm_yes(app: Client, msg: Message, kind: Literal["application", "sponsorship"] = "unknown"): holo_user = HoloUser(msg.from_user) @@ -142,7 +143,7 @@ confirmation_2 = [] for pattern in all_locales("confirm", "keyboard"): confirmation_2.append(pattern[1][0]) @app.on_message(~ filters.scheduled & filters.private & filters.command(confirmation_2, prefixes=[""])) -async def confirm_no(app, msg, kind: Literal["application", "sponsorship"] = "unknown"): +async def confirm_no(app: Client, msg: Message, kind: Literal["application", "sponsorship"] = "unknown"): holo_user = HoloUser(msg.from_user) diff --git a/modules/handlers/contact.py b/modules/handlers/contact.py index 745e549..4be02d5 100644 --- a/modules/handlers/contact.py +++ b/modules/handlers/contact.py @@ -2,13 +2,15 @@ from dateutil.relativedelta import relativedelta from datetime import datetime from app import app, isAnAdmin from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.utils import locale, logWrite from modules.database import col_applications from classes.holo_user import HoloUser # Contact getting ============================================================================================================== @app.on_message(~ filters.scheduled & filters.contact & filters.private) -async def get_contact(app, msg): +async def get_contact(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) diff --git a/modules/handlers/everything.py b/modules/handlers/everything.py index 5a37c89..d9de5c7 100644 --- a/modules/handlers/everything.py +++ b/modules/handlers/everything.py @@ -2,6 +2,7 @@ from app import app, isAnAdmin import asyncio from pyrogram import filters from pyrogram.types import Message +from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import configGet, logWrite from modules.database import col_messages @@ -20,7 +21,7 @@ async def message_context(msg: Message) -> tuple: # Any other input ============================================================================================================== @app.on_message(~ filters.scheduled & filters.private) -async def any_stage(app, msg): +async def any_stage(app: Client, msg: Message): if msg.via_bot is None: @@ -113,7 +114,7 @@ async def any_stage(app, msg): # await msg.reply_text(locale("already_sent", "message")) @app.on_message(~ filters.scheduled & filters.group) -async def message_in_group(app, msg): +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 == configGet("bot_id")) and (msg.chat.id == configGet("destination_group")): if configGet("remove_application_time") > 0: diff --git a/modules/handlers/group_join.py b/modules/handlers/group_join.py index 4ea326e..d110573 100644 --- a/modules/handlers/group_join.py +++ b/modules/handlers/group_join.py @@ -1,5 +1,6 @@ from app import app, isAnAdmin -from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.types import ChatPermissions, InlineKeyboardMarkup, InlineKeyboardButton, ChatMemberUpdated +from pyrogram.client import Client from modules.utils import configGet, locale from modules.logging import logWrite from classes.holo_user import HoloUser @@ -7,7 +8,7 @@ from classes.holo_user import HoloUser # Filter users on join ========================================================================================================= @app.on_chat_member_updated(group=configGet("destination_group")) #@app.on_message(filters.new_chat_members, group=configGet("destination_group")) -async def filter_join(app, member): +async def filter_join(app: Client, member: ChatMemberUpdated): if member.invite_link != None: diff --git a/modules/handlers/sponsorship.py b/modules/handlers/sponsorship.py index 1fb1adb..f78a6de 100644 --- a/modules/handlers/sponsorship.py +++ b/modules/handlers/sponsorship.py @@ -1,10 +1,12 @@ from app import app from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from classes.holo_user import HoloUser @app.on_message(~ filters.scheduled & filters.photo & filters.private) -async def sponsor_proof(app, msg): +async def sponsor_proof(app: Client, msg: Message): if msg.via_bot is None: diff --git a/modules/handlers/voice.py b/modules/handlers/voice.py index 47fdb1c..a6bb361 100644 --- a/modules/handlers/voice.py +++ b/modules/handlers/voice.py @@ -1,10 +1,12 @@ from random import choice from app import app from pyrogram import filters +from pyrogram.types import Message +from pyrogram.client import Client from modules.logging import logWrite from modules.utils import configGet, locale @app.on_message(~ filters.scheduled & filters.voice & filters.chat(configGet("destination_group"))) -async def voice_message(app, msg): +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 diff --git a/modules/handlers/welcome.py b/modules/handlers/welcome.py index ca04c7f..bcd516a 100644 --- a/modules/handlers/welcome.py +++ b/modules/handlers/welcome.py @@ -1,6 +1,7 @@ from app import app from pyrogram import filters -from pyrogram.types import ForceReply, ReplyKeyboardMarkup +from pyrogram.types import ForceReply, ReplyKeyboardMarkup, Message +from pyrogram.client import Client from modules.utils import all_locales, locale, logWrite # Welcome check ================================================================================================================ @@ -31,7 +32,7 @@ welcome_2 = [] for pattern in all_locales("welcome", "keyboard"): welcome_2.append(pattern[1][0]) @app.on_message(~ filters.scheduled & filters.private & filters.command(welcome_2, prefixes=[""])) -async def welcome_reject(app, msg): +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)) -- 2.39.2 From 87d9afe74a7f7cc7682d63cbf10073595fb05e03 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Tue, 27 Dec 2022 13:40:58 +0100 Subject: [PATCH 21/30] Small fix of message method --- classes/holo_user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index f10f3ff..b5513a4 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -254,11 +254,11 @@ class HoloUser(): elif animation is not None: if isinstance(animation, Animation): animation = animation.file_id - new_message = await app.send_animation(animation, caption=caption, quote=True) + new_message = await app.send_animation(self.id, animation, caption=caption) elif voice is not None: if isinstance(voice, Voice): voice = voice.file_id - new_message = await app.send_voice(voice, caption=caption, quote=True) + new_message = await app.send_voice(self.id, voice, caption=caption) else: new_message = await app.send_message(self.id, text) -- 2.39.2 From 082acc85cf4aecf4a76e198c205d3bf27755db67 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Tue, 27 Dec 2022 18:46:17 +0100 Subject: [PATCH 22/30] Added custom filters --- modules/commands/application.py | 143 +++++++++++++++---------------- modules/commands/applications.py | 32 +++---- modules/commands/label.py | 49 ++++++----- modules/commands/message.py | 41 +++++---- modules/commands/reboot.py | 14 +-- modules/commands/sponsorship.py | 18 ++-- modules/commands/warn.py | 18 ++-- modules/commands/warnings.py | 57 ++++++------ modules/custom_filters.py | 12 +++ modules/handlers/contact.py | 61 +++++++------ modules/inline.py | 5 +- 11 files changed, 229 insertions(+), 221 deletions(-) create mode 100644 modules/custom_filters.py diff --git a/modules/commands/application.py b/modules/commands/application.py index c079049..2f90f99 100644 --- a/modules/commands/application.py +++ b/modules/commands/application.py @@ -1,5 +1,5 @@ from datetime import datetime -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.enums.parse_mode import ParseMode from pyrogram.types import Message @@ -9,90 +9,89 @@ from classes.holo_user import HoloUser, UserNotFoundError from modules.utils import logWrite, locale, should_quote from dateutil.relativedelta import relativedelta from modules.database import col_applications +from modules import custom_filters # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["application"], prefixes=["/"])) async def cmd_application(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: + try: try: - + holo_user = HoloUser(int(msg.command[1])) + except (ValueError, UserNotFoundError): 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): - 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)) + holo_user = HoloUser((await app.get_users(msg.command[1])).id) + except (bad_request_400.UsernameInvalid, bad_request_400.PeerIdInvalid): + await msg.reply_text(locale("no_user_application", "message", locale=msg.from_user).format(msg.command[1]), quote=should_quote(msg)) return - application_content = [] - i = 1 + application = col_applications.find_one({"user": holo_user.id}) - for question in application['application']: + 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)) + return - 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} р.)") - 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']}") - 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 = [] + i = 1 + + 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} р.)") + 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']}") else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=msg.from_user)} {application['application'][question]}") - - i += 1 + 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]}") + + 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)) + 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)) - # if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]): - # user_id = int(msg.command[1]) - # else: - # list_of_users = [] - # async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): - # list_of_users.append(m) - # user_id = list_of_users[0].user.id - # try: - # user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json") - # application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)] - # application_content = [] - # i = 1 - # for question in configGet("application", file=str(msg.from_user.id)): - # if i == 2: - # age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y')) - # application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)") - # else: - # application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}") - # i += 1 - # if user_data["sent"]: - # if user_data["approved"]: - # application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M")) - # elif application["rejected"]: - # application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M")) - # else: - # application_status = locale("application_status_on_hold", "message") - # else: - # if user_data["approved"]: - # application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M")) - # elif application["rejected"]: - # application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M")) - # else: - # application_status = locale("application_status_not_send", "message") - # logWrite(f"User {msg.from_user.id} requested application of {user_id}") - # await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), quote=should_quote(msg)) - - except IndexError: - await msg.reply_text(locale("application_invalid_syntax", "message", locale=msg.from_user), quote=should_quote(msg)) + # if (path.exists(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json") and jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{msg.command[1]}.json")["approved"]): + # user_id = int(msg.command[1]) + # else: + # list_of_users = [] + # async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): + # list_of_users.append(m) + # user_id = list_of_users[0].user.id + # try: + # user_data = jsonLoad(f"{configGet('data', 'locations')}{sep}users{sep}{user_id}.json") + # application = jsonLoad(f"{configGet('data', 'locations')}{sep}applications.json")[str(user_id)] + # application_content = [] + # i = 1 + # for question in configGet("application", file=str(msg.from_user.id)): + # if i == 2: + # age = relativedelta(datetime.now(), datetime.strptime(application['application']['2'], '%d.%m.%Y')) + # application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application']['2']} ({age.years} р.)") + # else: + # application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {application['application'][question]}") + # i += 1 + # if user_data["sent"]: + # if user_data["approved"]: + # application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M")) + # elif application["rejected"]: + # application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M")) + # else: + # application_status = locale("application_status_on_hold", "message") + # else: + # if user_data["approved"]: + # application_status = locale("application_status_accepted", "message").format((await app.get_users(application["approved_by"])).first_name, datetime.fromtimestamp(application["approval_date"]).strftime("%d.%m.%Y, %H:%M")) + # elif application["rejected"]: + # application_status = locale("application_status_rejected", "message").format((await app.get_users(application["rejected_by"])).first_name, datetime.fromtimestamp(application["refusal_date"]).strftime("%d.%m.%Y, %H:%M")) + # else: + # application_status = locale("application_status_not_send", "message") + # logWrite(f"User {msg.from_user.id} requested application of {user_id}") + # await msg.reply_text(locale("contact", "message").format(str(user_id), "\n".join(application_content), application_status), 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 diff --git a/modules/commands/applications.py b/modules/commands/applications.py index a7b672c..f51a699 100644 --- a/modules/commands/applications.py +++ b/modules/commands/applications.py @@ -1,6 +1,6 @@ from os import sep, makedirs, remove from uuid import uuid1 -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client @@ -8,23 +8,23 @@ 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 # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & filters.command(["applications"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["applications"], prefixes=["/"])) async def cmd_applications(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: - 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") + 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") # ============================================================================================================================== \ No newline at end of file diff --git a/modules/commands/label.py b/modules/commands/label.py index 26dc16d..27636d0 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -1,38 +1,37 @@ -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client from modules.utils import locale, should_quote, find_user from classes.holo_user import HoloUser, LabelTooLongError +from modules import custom_filters -@app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.private & filters.command(["label"], prefixes=["/"])) async def cmd_label(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: + if len(msg.command) < 3: + await msg.reply_text("Invalid syntax:\n`/label USER LABEL`") + return - if len(msg.command) < 3: - await msg.reply_text("Invalid syntax:\n`/label USER LABEL`") - return + target = await find_user(app, msg.command[1]) - target = await find_user(app, msg.command[1]) + if target is not None: + + target = HoloUser(target) - if target is not None: + 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)) - 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)) - - else: - try: - await target.label_set(msg.chat, label) - except LabelTooLongError: - await msg.reply_text(locale("label_too_long", "message")) - return - 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 + try: + await target.label_set(msg.chat, label) + except LabelTooLongError: + await msg.reply_text(locale("label_too_long", "message")) + return + 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 159fd52..265395c 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -1,34 +1,33 @@ -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client from classes.holo_user import HoloUser from modules.utils import logWrite, locale, should_quote +from modules import custom_filters # Message command ============================================================================================================== -@app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["message"], prefixes=["/"])) async def cmd_message(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: + try: try: - - try: - destination = HoloUser(int(msg.command[1])) - except ValueError: - destination = HoloUser(msg.command[1]) - - if ((msg.text is not None) and (len(msg.text.split()) > 2)): - await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) - elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)): - await destination.message(context=msg, text=msg.text, caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) - else: - await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) - - except IndexError: - 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'") + destination = HoloUser(int(msg.command[1])) except ValueError: - 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'") + destination = HoloUser(msg.command[1]) + + if ((msg.text is not None) and (len(msg.text.split()) > 2)): + await destination.message(context=msg, text=" ".join(msg.text.split()[2:]), caption=msg.caption, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) + elif ((msg.caption is not None) and (len(msg.caption.split()) > 2)): + await destination.message(context=msg, text=msg.text, caption=" ".join(msg.caption.split()[2:]), photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) + else: + await destination.message(context=msg, text=None, caption=None, photo=msg.photo, video=msg.video, file=msg.document, adm_context=True) + + except IndexError: + 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)) + logWrite(f"Admin {msg.from_user.id} tried to send message but 'ValueError'") # ============================================================================================================================== \ No newline at end of file diff --git a/modules/commands/reboot.py b/modules/commands/reboot.py index 5c3d25a..d929e1a 100644 --- a/modules/commands/reboot.py +++ b/modules/commands/reboot.py @@ -1,4 +1,4 @@ -from app import app, isAnAdmin +from app import app from os import getpid from sys import exit from pyrogram import filters @@ -6,16 +6,16 @@ from pyrogram.types import Message from pyrogram.client import Client from modules.utils import locale, logWrite, should_quote from modules.scheduled import scheduler +from modules import custom_filters pid = getpid() # Shutdown command ============================================================================================================= -@app.on_message(~ filters.scheduled & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) async def cmd_kill(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: - 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)) - scheduler.shutdown() - exit() + 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)) + scheduler.shutdown() + exit() # ============================================================================================================================== \ No newline at end of file diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index d57a2ad..b8a3746 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -1,19 +1,19 @@ -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message from pyrogram.client import Client from classes.holo_user import HoloUser +from modules import custom_filters from modules.utils import locale, should_quote from modules.database import col_applications # Sponsorship command ========================================================================================================== -@app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & filters.command(["sponsorship"], prefixes=["/"])) async def cmd_sponsorship(app: Client, msg: Message): - if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): - if HoloUser(msg.from_user).application_state()[0] == "fill": - await msg.reply_text(locale("finish_application", "message"), quote=should_quote(msg)) - return - await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), callback_data=f"sponsor_apply_{msg.from_user.id}")]]), quote=should_quote(msg)) - else: - await msg.reply_text(locale("sponsorship_application_empty", "message")) + if HoloUser(msg.from_user).application_state()[0] == "fill": + await msg.reply_text(locale("finish_application", "message"), quote=should_quote(msg)) + return + await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), 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/warn.py b/modules/commands/warn.py index 9227b47..0002b6d 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -1,22 +1,22 @@ from datetime import datetime -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client from modules.utils import configGet, locale from modules.database import col_warnings +from modules import custom_filters # Warn command ================================================================================================================= -@app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["warn"], prefixes=["/"])) async def cmd_warn(app: Client, msg: Message): if msg.chat.id == configGet("destination_group"): if msg.reply_to_message_id != None: - if await isAnAdmin(msg.from_user.id) is True: - 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}) - 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)) - 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)) + 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}) + 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)) + 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 diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 494f6e3..74d3e14 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -1,45 +1,44 @@ -from app import app, isAnAdmin +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.database import col_users, col_warnings +from modules import custom_filters # Warnings command ============================================================================================================= -@app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["warnings"], prefixes=["/"])) async def cmd_warnings(app: Client, msg: Message): - if await isAnAdmin(msg.from_user.id) is True: + if len(msg.command) <= 1: + await msg.reply_text(locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg)) + return - if len(msg.command) <= 1: - await msg.reply_text(locale("syntax_warnings", "message", locale=msg.from_user), quote=should_quote(msg)) + try: + user_db = col_users.find_one({"user": int(msg.command[1])}) + target_id = user_db["user"] + target_name = user_db["tg_name"] + except: + list_of_users = [] + async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): + list_of_users.append(m) + + if len(list_of_users) != 0: + target = list_of_users[0].user + target_name = target.first_name + target_id = str(target.id) + else: + await msg.reply_text(locale("no_user_warnings", "message", locale=msg.from_user).format(msg.command[1])) return - try: - user_db = col_users.find_one({"user": int(msg.command[1])}) - target_id = user_db["user"] - target_name = user_db["tg_name"] - except: - list_of_users = [] - async for m in app.get_chat_members(configGet("destination_group"), filter=ChatMembersFilter.SEARCH, query=msg.command[1]): - list_of_users.append(m) + warns = len(list(col_warnings.find({"user": target_id}))) - if len(list_of_users) != 0: - target = list_of_users[0].user - target_name = target.first_name - target_id = str(target.id) - else: - await msg.reply_text(locale("no_user_warnings", "message", 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)) + if warns == 0: + 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)) 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)) - else: - await msg.reply_text(locale("warnings_2", "message", locale=msg.from_user).format(target_name, target_id, warns), quote=should_quote(msg)) + 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 diff --git a/modules/custom_filters.py b/modules/custom_filters.py new file mode 100644 index 0000000..8686fb8 --- /dev/null +++ b/modules/custom_filters.py @@ -0,0 +1,12 @@ +from app import isAnAdmin +from modules.database import col_applications +from pyrogram import filters + +async def admin_func(_, __, msg): + return await isAnAdmin(msg) + +async def allowed_func(_, __, msg): + return True if (col_applications.find_one({"user": msg.from_user.id}) is not None) else False + +admin = filters.create(admin_func) +allowed = filters.create(allowed_func) \ No newline at end of file diff --git a/modules/handlers/contact.py b/modules/handlers/contact.py index 4be02d5..bd51f1e 100644 --- a/modules/handlers/contact.py +++ b/modules/handlers/contact.py @@ -1,55 +1,54 @@ from dateutil.relativedelta import relativedelta from datetime import datetime -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client from modules.utils import locale, logWrite from modules.database import col_applications from classes.holo_user import HoloUser +from modules import custom_filters # Contact getting ============================================================================================================== -@app.on_message(~ filters.scheduled & filters.contact & filters.private) +@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & filters.contact & filters.private) async def get_contact(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) - if holo_user.application_approved() or (await isAnAdmin(holo_user.id) is True): + if msg.contact.user_id != None: - if msg.contact.user_id != None: + application = col_applications.find_one({"user": msg.contact.user_id}) - 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)) + return - 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)) - return + application_content = [] + i = 1 - 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} р.)") - 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']}") - 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']})") + 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} р.)") + 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']}") else: - application_content.append(f"{locale(f'question{i}', 'message', 'question_titles', locale=holo_user.locale)} {application['application'][question]}") - - i += 1 + 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]}") + + 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)) - + 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)) + - 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)) + 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 diff --git a/modules/inline.py b/modules/inline.py index 851b42d..d0f1a8e 100644 --- a/modules/inline.py +++ b/modules/inline.py @@ -1,7 +1,8 @@ from datetime import datetime from os import path, sep from app import app, isAnAdmin -from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent +from pyrogram.types import InlineQueryResultArticle, InputTextMessageContent, InlineQuery +from pyrogram.client import Client from pyrogram.enums.chat_type import ChatType from pyrogram.enums.chat_members_filter import ChatMembersFilter from dateutil.relativedelta import relativedelta @@ -10,7 +11,7 @@ from modules.utils import configGet, locale from modules.database import col_applications @app.on_inline_query() -async def inline_answer(client, inline_query): +async def inline_answer(client: Client, inline_query: InlineQuery): if inline_query.chat_type in [ChatType.CHANNEL]: await inline_query.answer( -- 2.39.2 From e59aa98fd5441b5912edbcd9081ae4e2904233d4 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Tue, 27 Dec 2022 18:49:02 +0100 Subject: [PATCH 23/30] Working on /nearby --- modules/commands/nearby.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index d771179..a78adfa 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -1,15 +1,34 @@ -from app import app, isAnAdmin +from app import app from pyrogram import filters from pyrogram.types import Message from pyrogram.client import Client +from classes.holo_user import HoloUser +from modules import custom_filters from modules.utils import configGet, should_quote from modules.database import col_applications # Nearby command =============================================================================================================== -@app.on_message(~ filters.scheduled & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) async def cmd_nearby(app: Client, msg: Message): - if (await isAnAdmin(msg) is True) or (col_applications.find_one({"user": msg.from_user.id}) is not None): - await msg.reply_text("Yes, I exist.", quote=should_quote(msg)) + + if len(msg.command) < 1: + application = col_applications.find_one({"user": msg.from_user}) + if application is None: + await msg.reply_text("You have no application") + return + location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] + else: + # find location + location = "result" + + output = [] + users_nearby = col_applications.find( {"application": {"loc": { "$within": { "$center": [[location], 5] } }}} ) + + for user in users_nearby: + output.append(user) + + await msg.reply_text("Yes, I exist.", quote=should_quote(msg)) + # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): # jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") # sponsor = jsonLoad(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") -- 2.39.2 From 22011829a5072b92d2d59001794c19d085f3cc5c Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Wed, 28 Dec 2022 18:56:13 +0100 Subject: [PATCH 24/30] Geo update WIP --- classes/errors/geo.py | 5 +++++ classes/holo_user.py | 24 ++++++++++++++++++------ locale/uk.json | 2 ++ modules/commands/nearby.py | 22 ++++++++++++++++------ modules/database.py | 6 ++++-- modules/utils.py | 20 ++++++++++++++++++++ 6 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 classes/errors/geo.py diff --git a/classes/errors/geo.py b/classes/errors/geo.py new file mode 100644 index 0000000..b4b8b02 --- /dev/null +++ b/classes/errors/geo.py @@ -0,0 +1,5 @@ +class PlaceNotFoundError(Exception): + """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 diff --git a/classes/holo_user.py b/classes/holo_user.py index b5513a4..963fc47 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -8,9 +8,10 @@ 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.errors import bad_request_400 from dateutil.relativedelta import relativedelta +from classes.errors.geo import PlaceNotFoundError from modules.database import col_tmp, col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages from modules.logging import logWrite -from modules.utils import configGet, locale, should_quote +from modules.utils import configGet, find_location, locale, should_quote class DefaultApplicationTemp(dict): def __init__(self, user: int, reapply: bool = False): @@ -350,6 +351,10 @@ class HoloUser(): ) progress = col_tmp.find_one({"user": self.id, "type": "application"}) + + if progress is None: + return + stage = progress["stage"] if self.sponsorship_state()[0] == "fill": @@ -385,13 +390,16 @@ class HoloUser(): elif stage == 3: 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() - progress["application"][str(stage)] = result["geonames"][0] + 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)]["loc"] = [progress["application"][str(stage)]["lng"], 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(f"question3_found", "message", locale=self.locale).format(result["geonames"][0]["name"], result["geonames"][0]["adminName1"])) + 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 (ValueError, KeyError, IndexError): - await msg.reply_text(locale(f"question3_invalid", "message", locale=self.locale), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "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)))) 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)))) @@ -470,6 +478,10 @@ class HoloUser(): if col_tmp.find_one({"user": self.id, "type": "sponsorship"}) is not None: progress = col_tmp.find_one({"user": self.id, "type": "sponsorship"}) + + if progress is None: + return + stage = progress["stage"] if progress["state"] == "fill" and progress["sent"] is False: diff --git a/locale/uk.json b/locale/uk.json index 9178313..4d7fb2d 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -92,6 +92,8 @@ "label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів", "finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.", "finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.", + "nearby_invalid": "", + "nearby_error": "", "voice_message": [ "why are u gae", "руки відірвало? пиши як людина", diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index a78adfa..4391b0c 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -4,25 +4,35 @@ from pyrogram.types import Message from pyrogram.client import Client from classes.holo_user import HoloUser from modules import custom_filters -from modules.utils import configGet, should_quote +from modules.utils import configGet, locale, should_quote, find_location from modules.database import col_applications +from classes.errors.geo import PlaceNotFoundError # Nearby command =============================================================================================================== @app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) async def cmd_nearby(app: Client, msg: Message): - if len(msg.command) < 1: + holo_user = HoloUser(msg.from_user) + + if len(msg.command) < 2: application = col_applications.find_one({"user": msg.from_user}) if application is None: - await msg.reply_text("You have no application") + await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user.locale)) return location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] else: - # find location - location = "result" + try: + location_coordinates = find_location(" ".join(msg.command[2:])) + location = location_coordinates["lng"], location_coordinates["lat"] + except PlaceNotFoundError: + await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user.locale), quote=should_quote(msg)) + return + except Exception as exp: + await msg.reply_text(locale("nearby_error", "message", locale=holo_user.locale), quote=should_quote(msg)) + return output = [] - users_nearby = col_applications.find( {"application": {"loc": { "$within": { "$center": [[location], 5] } }}} ) + users_nearby = col_applications.find( {"application.loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } ) for user in users_nearby: output.append(user) diff --git a/modules/database.py b/modules/database.py index 3e368d0..6c51a89 100644 --- a/modules/database.py +++ b/modules/database.py @@ -1,4 +1,4 @@ -from pymongo import MongoClient +from pymongo import MongoClient, GEO2D from ujson import loads with open("config.json", "r", encoding="utf-8") as f: @@ -35,4 +35,6 @@ col_context = db.get_collection("context") col_messages = db.get_collection("messages") col_warnings = db.get_collection("warnings") col_applications = db.get_collection("applications") -col_sponsorships = db.get_collection("sponsorships") \ No newline at end of file +col_sponsorships = db.get_collection("sponsorships") + +col_applications.create_index([("application.3.loc", GEO2D)]) \ No newline at end of file diff --git a/modules/utils.py b/modules/utils.py index 317bb97..68c1e98 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -1,4 +1,5 @@ from typing import Any, Union +from requests import get from pyrogram.enums.chat_type import ChatType from pyrogram.types import User from pyrogram.client import Client @@ -10,6 +11,7 @@ from sys import exit from os import kill, listdir, sep from os import name as osname from traceback import print_exc +from classes.errors.geo import PlaceNotFoundError from modules.logging import logWrite @@ -171,6 +173,24 @@ 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. + + ### Args: + * query (`str`): Some city/village/state name + + ### Raises: + * PlaceNotFoundError: Exception is raised when API result is empty + + ### 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() + return result["geonames"][0] + except (ValueError, KeyError, IndexError): + raise PlaceNotFoundError(query) + try: from psutil import Process except ModuleNotFoundError: -- 2.39.2 From c763fc537b0ccf9b5d52e9e9134e0aefd266bdd6 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Wed, 28 Dec 2022 19:01:21 +0100 Subject: [PATCH 25/30] Locale usage fixes --- classes/holo_user.py | 2 +- modules/callbacks/sponsorship.py | 6 +++--- modules/commands/nearby.py | 6 +++--- modules/commands/sponsorship.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 963fc47..0352ecc 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -528,7 +528,7 @@ class HoloUser(): return progress["sponsorship"]["label"] = query col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "sponsorship"}}, {"$set": {"sponsorship": progress["sponsorship"], "complete": True}}) - await msg.reply_text(locale("sponsor_confirm", "message"), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) + await msg.reply_text(locale("sponsor_confirm", "message", locale=self.locale), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard", locale=self.locale), resize_keyboard=True)) else: return diff --git a/modules/callbacks/sponsorship.py b/modules/callbacks/sponsorship.py index 16291a7..cc1c0d4 100644 --- a/modules/callbacks/sponsorship.py +++ b/modules/callbacks/sponsorship.py @@ -24,9 +24,9 @@ async def callback_query_sponsor_apply(app: Client, clb: CallbackQuery): edited_markup = [[InlineKeyboardButton(text=str(locale("sponsor_started", "button")), callback_data="nothing")]] - await clb.message.edit(text=locale("sponsorship_applying", "message"), reply_markup=InlineKeyboardMarkup(edited_markup)) - 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)))) - await clb.answer(text=locale("sponsor_started", "callback").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): diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index 4391b0c..d3b38e9 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -17,7 +17,7 @@ async def cmd_nearby(app: Client, msg: Message): if len(msg.command) < 2: application = col_applications.find_one({"user": msg.from_user}) if application is None: - await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user.locale)) + await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user)) return location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] else: @@ -25,10 +25,10 @@ async def cmd_nearby(app: Client, msg: Message): location_coordinates = find_location(" ".join(msg.command[2:])) location = location_coordinates["lng"], location_coordinates["lat"] except PlaceNotFoundError: - await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user.locale), quote=should_quote(msg)) + await msg.reply_text(locale("nearby_invalid", "message", locale=holo_user), quote=should_quote(msg)) return except Exception as exp: - await msg.reply_text(locale("nearby_error", "message", locale=holo_user.locale), quote=should_quote(msg)) + await msg.reply_text(locale("nearby_error", "message", locale=holo_user), quote=should_quote(msg)) return output = [] diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index b8a3746..c64fe88 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -11,9 +11,9 @@ from modules.database import col_applications @app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & filters.command(["sponsorship"], prefixes=["/"])) async def cmd_sponsorship(app: Client, msg: Message): if HoloUser(msg.from_user).application_state()[0] == "fill": - await msg.reply_text(locale("finish_application", "message"), quote=should_quote(msg)) + await msg.reply_text(locale("finish_application", "message", locale=msg.from_user), quote=should_quote(msg)) return - await msg.reply_text(locale("sponsorship_apply", "message"), reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton(text=str(locale("sponsor_apply", "button")), 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 -- 2.39.2 From 8b2abc2cfa42c0037717fbff512e1856ae1381e8 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Thu, 29 Dec 2022 15:04:00 +0100 Subject: [PATCH 26/30] Updated /nearby command --- locale/uk.json | 6 ++++-- modules/commands/nearby.py | 24 +++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/locale/uk.json b/locale/uk.json index 4d7fb2d..12c5bed 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -92,8 +92,10 @@ "label_too_long": "Довжина назви ролі не повинна перевищувати 16 символів", "finish_sponsorship": "❌ **Дія неможлива**\nПерш ніж заповнювати анкету, треба завершити заповнення форми спонсора.", "finish_application": "❌ **Дія неможлива**\nПерш ніж заповнювати форму спонсора, треба завершити заповнення анкети.", - "nearby_invalid": "", - "nearby_error": "", + "nearby_invalid": "ℹ️ **Місце не знайдено**\nЗа наданим запитом не знайдено місце з координатами. Спробуйте ще раз формулючи запит в стилі \"Чернівці\" або \"Київська область\".", + "nearby_error": "⚠️ **Сталась помилка**\n\nПомилка: `{0}`\n\nTraceback:\n```\n{1}\n```", + "nearby_result": "Результати пошуку:\n\n{0}", + "nearby_empty": "Здається, нікого поблизу немає.", "voice_message": [ "why are u gae", "руки відірвало? пиши як людина", diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index d3b38e9..97eb9cb 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -1,3 +1,4 @@ +from traceback import print_exc from app import app from pyrogram import filters from pyrogram.types import Message @@ -14,30 +15,39 @@ async def cmd_nearby(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) - if len(msg.command) < 2: + # Check if any place provided + if len(msg.command) < 2: # Action if no place provided application = col_applications.find_one({"user": msg.from_user}) if application is None: await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user)) return location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] - else: + else: # Find a place from input query try: location_coordinates = find_location(" ".join(msg.command[2:])) location = location_coordinates["lng"], location_coordinates["lat"] - except PlaceNotFoundError: + 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: - await msg.reply_text(locale("nearby_error", "message", locale=holo_user), 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 = [] users_nearby = col_applications.find( {"application.loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } ) for user in users_nearby: - output.append(user) + if user["tg_username"] not in [None, "None", ""]: # Check if user has any name + output.append(f'• {user["tg_name"]} (@{user["tg_username"]}):\n {user["application"]["3"]["Name"]}, {user["application"]["3"]["adminName1"]}') + else: + output.append(f'• {user["tg_name"]}:\n {user["application"]["3"]["Name"]}, {user["application"]["3"]["adminName1"]}') - await msg.reply_text("Yes, I exist.", quote=should_quote(msg)) + # 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)) + else: + await msg.reply_text(locale("nearby_empty", "message", locale=holo_user), quote=should_quote(msg)) # if not path.exists(f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json"): # jsonSave(jsonLoad(f"{configGet('data', 'locations')}{sep}sponsor_default.json"), f"{configGet('data', 'locations')}{sep}sponsors{sep}{msg.from_user.id}.json") -- 2.39.2 From e6589fc3e51f064d94fe5cf1c12e2d8997d53748 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 30 Dec 2022 20:36:06 +0100 Subject: [PATCH 27/30] Improved admin group filter --- app.py | 9 ++++++++- modules/commands/application.py | 2 +- modules/commands/applications.py | 2 +- modules/commands/label.py | 2 +- modules/commands/message.py | 2 +- modules/commands/nearby.py | 2 +- modules/commands/reboot.py | 2 +- modules/commands/sponsorship.py | 2 +- modules/commands/warn.py | 2 +- modules/commands/warnings.py | 2 +- modules/handlers/contact.py | 2 +- modules/scheduled.py | 20 ++++++++++++++++++-- 12 files changed, 36 insertions(+), 13 deletions(-) diff --git a/app.py b/app.py index 833c744..a30216e 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,7 @@ +from os import path, sep +from ujson import JSONDecodeError from modules.logging import logWrite -from modules.utils import configGet +from modules.utils import configGet, jsonLoad from pyrogram.client import Client from pyrogram.errors import bad_request_400 @@ -8,6 +10,11 @@ app = Client("holochecker", bot_token=configGet("bot_token", "bot"), api_id=conf async def isAnAdmin(admin_id): if (admin_id == configGet("owner")) or (admin_id in configGet("admins")): return True + if path.exists(f"cache{sep}admins") is True: + try: + return True if admin_id in jsonLoad(f"cache{sep}admins") else False + except (FileNotFoundError, JSONDecodeError): + pass try: async for member in app.get_chat_members(configGet("admin_group")): if member.user.id == admin_id: diff --git a/modules/commands/application.py b/modules/commands/application.py index 2f90f99..abc758d 100644 --- a/modules/commands/application.py +++ b/modules/commands/application.py @@ -12,7 +12,7 @@ from modules.database import col_applications from modules import custom_filters # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["application"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.command(["application"], prefixes=["/"]) & custom_filters.admin) async def cmd_application(app: Client, msg: Message): try: diff --git a/modules/commands/applications.py b/modules/commands/applications.py index f51a699..ba409e9 100644 --- a/modules/commands/applications.py +++ b/modules/commands/applications.py @@ -11,7 +11,7 @@ from modules.database import col_applications from modules import custom_filters # Applications command ========================================================================================================= -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["applications"], prefixes=["/"])) +@app.on_message(~ 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") diff --git a/modules/commands/label.py b/modules/commands/label.py index 27636d0..60763b0 100644 --- a/modules/commands/label.py +++ b/modules/commands/label.py @@ -6,7 +6,7 @@ from modules.utils import locale, should_quote, find_user from classes.holo_user import HoloUser, LabelTooLongError from modules import custom_filters -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.private & filters.command(["label"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.private & filters.command(["label"], prefixes=["/"]) & custom_filters.admin) async def cmd_label(app: Client, msg: Message): if len(msg.command) < 3: diff --git a/modules/commands/message.py b/modules/commands/message.py index 265395c..60ce874 100644 --- a/modules/commands/message.py +++ b/modules/commands/message.py @@ -7,7 +7,7 @@ from modules.utils import logWrite, locale, should_quote from modules import custom_filters # Message command ============================================================================================================== -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["message"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.command(["message"], prefixes=["/"]) & custom_filters.admin) async def cmd_message(app: Client, msg: Message): try: diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index 97eb9cb..39d6ba8 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -10,7 +10,7 @@ from modules.database import col_applications from classes.errors.geo import PlaceNotFoundError # Nearby command =============================================================================================================== -@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & (filters.private | (filters.chat(configGet("admin_group")) | filters.chat(configGet("destination_group")))) & filters.command(["nearby"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin)) async def cmd_nearby(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) diff --git a/modules/commands/reboot.py b/modules/commands/reboot.py index d929e1a..0a5faf9 100644 --- a/modules/commands/reboot.py +++ b/modules/commands/reboot.py @@ -11,7 +11,7 @@ from modules import custom_filters pid = getpid() # Shutdown command ============================================================================================================= -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.private & filters.command(["kill", "die", "reboot"], prefixes=["/"])) +@app.on_message(~ 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}") diff --git a/modules/commands/sponsorship.py b/modules/commands/sponsorship.py index c64fe88..32e14dc 100644 --- a/modules/commands/sponsorship.py +++ b/modules/commands/sponsorship.py @@ -8,7 +8,7 @@ from modules.utils import locale, should_quote from modules.database import col_applications # Sponsorship command ========================================================================================================== -@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & filters.command(["sponsorship"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.command(["sponsorship"], prefixes=["/"]) & (custom_filters.allowed | custom_filters.admin)) async def cmd_sponsorship(app: Client, msg: Message): if HoloUser(msg.from_user).application_state()[0] == "fill": await msg.reply_text(locale("finish_application", "message", locale=msg.from_user), quote=should_quote(msg)) diff --git a/modules/commands/warn.py b/modules/commands/warn.py index 0002b6d..e974de6 100644 --- a/modules/commands/warn.py +++ b/modules/commands/warn.py @@ -8,7 +8,7 @@ from modules.database import col_warnings from modules import custom_filters # Warn command ================================================================================================================= -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["warn"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.command(["warn"], prefixes=["/"]) & custom_filters.admin) async def cmd_warn(app: Client, msg: Message): if msg.chat.id == configGet("destination_group"): diff --git a/modules/commands/warnings.py b/modules/commands/warnings.py index 74d3e14..d2a9c7e 100644 --- a/modules/commands/warnings.py +++ b/modules/commands/warnings.py @@ -8,7 +8,7 @@ from modules.database import col_users, col_warnings from modules import custom_filters # Warnings command ============================================================================================================= -@app.on_message(~ filters.scheduled & custom_filters.admin & filters.command(["warnings"], prefixes=["/"])) +@app.on_message(~ filters.scheduled & filters.command(["warnings"], prefixes=["/"]) & custom_filters.admin) async def cmd_warnings(app: Client, msg: Message): if len(msg.command) <= 1: diff --git a/modules/handlers/contact.py b/modules/handlers/contact.py index bd51f1e..b6459a5 100644 --- a/modules/handlers/contact.py +++ b/modules/handlers/contact.py @@ -10,7 +10,7 @@ from classes.holo_user import HoloUser from modules import custom_filters # Contact getting ============================================================================================================== -@app.on_message(~ filters.scheduled & (custom_filters.allowed | custom_filters.admin) & filters.contact & filters.private) +@app.on_message(~ filters.scheduled & filters.contact & filters.private & (custom_filters.allowed | custom_filters.admin)) async def get_contact(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) diff --git a/modules/scheduled.py b/modules/scheduled.py index 3da6b8d..601ee5a 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -1,4 +1,4 @@ -from os import listdir, path, sep +from os import listdir, makedirs, path, sep from apscheduler.schedulers.asyncio import AsyncIOScheduler from datetime import datetime, timedelta from app import app @@ -6,12 +6,28 @@ from pyrogram.types import BotCommand, BotCommandScopeChat from pyrogram.errors import bad_request_400 from pyrogram.enums.chat_members_filter import ChatMembersFilter from classes.holo_user import HoloUser -from modules.utils import configGet, locale, logWrite +from modules.utils import configGet, jsonSave, locale, logWrite from dateutil.relativedelta import relativedelta from modules.database import col_applications, col_sponsorships scheduler = AsyncIOScheduler() +@scheduler.scheduled_job(trigger="interval", seconds=20) +async def cache_group_members(): + list_of_users = [] + async for member in app.get_chat_members(configGet("destination_group")): + list_of_users.append(member.user.id) + makedirs("cache", exist_ok=True) + jsonSave(list_of_users, f"cache{sep}group_members") + +@scheduler.scheduled_job(trigger="interval", seconds=40) +async def cache_admins(): + list_of_users = [] + async for member in app.get_chat_members(configGet("admin_group")): + list_of_users.append(member.user.id) + makedirs("cache", exist_ok=True) + jsonSave(list_of_users, f"cache{sep}admins") + # Cache the avatars of group members if configGet("enabled", "scheduler", "cache_avatars"): @scheduler.scheduled_job(trigger="date", run_date=datetime.now()+timedelta(seconds=10)) -- 2.39.2 From 25be843cd8c2be9dadf2c669f9b1b57c8c9b4856 Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Fri, 30 Dec 2022 23:29:17 +0100 Subject: [PATCH 28/30] Improved /nearby --- classes/holo_user.py | 2 +- config_example.json | 1 + modules/commands/nearby.py | 30 +++++++++++++++++++----------- modules/database.py | 4 ++-- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index 0352ecc..edf0a02 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -392,7 +392,7 @@ class HoloUser(): 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)]["loc"] = [progress["application"][str(stage)]["lng"], progress["application"][str(stage)]["lat"]] + progress["application"][str(stage)]["loc"] = [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}}) diff --git a/config_example.json b/config_example.json index d228852..937d212 100644 --- a/config_example.json +++ b/config_example.json @@ -9,6 +9,7 @@ "admin_group": 0, "destination_group": 0, "remove_application_time": -1, + "search_radius": 50, "admins": [], "bot": { "api_id": 0, diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index 39d6ba8..f38334a 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -5,8 +5,9 @@ from pyrogram.types import Message 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.database import col_applications +from modules.database import col_applications, col_users from classes.errors.geo import PlaceNotFoundError # Nearby command =============================================================================================================== @@ -16,16 +17,17 @@ async def cmd_nearby(app: Client, msg: Message): holo_user = HoloUser(msg.from_user) # Check if any place provided - if len(msg.command) < 2: # Action if no place provided - application = col_applications.find_one({"user": msg.from_user}) + 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)) return location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][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[2:])) - location = location_coordinates["lng"], location_coordinates["lat"] + 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)) return @@ -35,13 +37,19 @@ async def cmd_nearby(app: Client, msg: Message): # Find all users registered in the area provided output = [] - users_nearby = col_applications.find( {"application.loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } ) + applications_nearby = col_applications.find( {"application.3.loc": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } ) + # {"application": {"3": {"loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } } } ) - for user in users_nearby: - if user["tg_username"] not in [None, "None", ""]: # Check if user has any name - output.append(f'• {user["tg_name"]} (@{user["tg_username"]}):\n {user["application"]["3"]["Name"]}, {user["application"]["3"]["adminName1"]}') - else: - output.append(f'• {user["tg_name"]}:\n {user["application"]["3"]["Name"]}, {user["application"]["3"]["adminName1"]}') + for entry in applications_nearby: + 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"]}') + + 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: diff --git a/modules/database.py b/modules/database.py index 6c51a89..8b038cb 100644 --- a/modules/database.py +++ b/modules/database.py @@ -1,4 +1,4 @@ -from pymongo import MongoClient, GEO2D +from pymongo import MongoClient, GEOSPHERE from ujson import loads with open("config.json", "r", encoding="utf-8") as f: @@ -37,4 +37,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.loc", GEO2D)]) \ No newline at end of file +col_applications.create_index([("application.3.loc", GEOSPHERE)]) \ No newline at end of file -- 2.39.2 From ace71fd6be52e1ae871931f2fd1c5ce436135777 Mon Sep 17 00:00:00 2001 From: profitroll Date: Mon, 2 Jan 2023 10:48:55 +0100 Subject: [PATCH 29/30] Members/admins caching is now configurable --- config_example.json | 8 ++++++++ modules/scheduled.py | 30 ++++++++++++++++-------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/config_example.json b/config_example.json index 937d212..55bbd79 100644 --- a/config_example.json +++ b/config_example.json @@ -42,6 +42,14 @@ "cache_avatars": { "interval": 6, "enabled": true + }, + "cache_members": { + "interval": 30, + "enabled": true + }, + "cache_admins": { + "interval": 120, + "enabled": true } }, "locations": { diff --git a/modules/scheduled.py b/modules/scheduled.py index 601ee5a..979c964 100644 --- a/modules/scheduled.py +++ b/modules/scheduled.py @@ -12,21 +12,23 @@ from modules.database import col_applications, col_sponsorships scheduler = AsyncIOScheduler() -@scheduler.scheduled_job(trigger="interval", seconds=20) -async def cache_group_members(): - list_of_users = [] - async for member in app.get_chat_members(configGet("destination_group")): - list_of_users.append(member.user.id) - makedirs("cache", exist_ok=True) - jsonSave(list_of_users, f"cache{sep}group_members") +if configGet("enabled", "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("destination_group")): + list_of_users.append(member.user.id) + makedirs("cache", exist_ok=True) + jsonSave(list_of_users, f"cache{sep}group_members") -@scheduler.scheduled_job(trigger="interval", seconds=40) -async def cache_admins(): - list_of_users = [] - async for member in app.get_chat_members(configGet("admin_group")): - list_of_users.append(member.user.id) - makedirs("cache", exist_ok=True) - jsonSave(list_of_users, f"cache{sep}admins") +if configGet("enabled", "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_group")): + list_of_users.append(member.user.id) + makedirs("cache", exist_ok=True) + jsonSave(list_of_users, f"cache{sep}admins") # Cache the avatars of group members if configGet("enabled", "scheduler", "cache_avatars"): -- 2.39.2 From 950666e4addb3621206979a94af5abba2fcd384b Mon Sep 17 00:00:00 2001 From: profitroll Date: Mon, 2 Jan 2023 11:13:41 +0100 Subject: [PATCH 30/30] Changed "loc" to "location" in application --- classes/holo_user.py | 2 +- modules/commands/nearby.py | 6 +++--- modules/database.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/classes/holo_user.py b/classes/holo_user.py index edf0a02..257e4ec 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -392,7 +392,7 @@ class HoloUser(): 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)]["loc"] = [float(progress["application"][str(stage)]["lng"]), float(progress["application"][str(stage)]["lat"])] + 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}}) diff --git a/modules/commands/nearby.py b/modules/commands/nearby.py index f38334a..890a314 100644 --- a/modules/commands/nearby.py +++ b/modules/commands/nearby.py @@ -22,7 +22,7 @@ async def cmd_nearby(app: Client, msg: Message): if application is None: await msg.reply_text(locale("nearby_user_empty", "message", locale=holo_user)) return - location = application["application"]["3"]["loc"][0], application["application"]["3"]["loc"][1] + 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: @@ -37,8 +37,8 @@ async def cmd_nearby(app: Client, msg: Message): # Find all users registered in the area provided output = [] - applications_nearby = col_applications.find( {"application.3.loc": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } ) - # {"application": {"3": {"loc": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } } } ) + applications_nearby = col_applications.find( {"application.3.location": { "$nearSphere": {"$geometry": {"type": "Point", "coordinates": [location[0], location[1]]}, "$maxDistance": configGet("search_radius")*1000} } } ) + # {"application": {"3": {"location": {"$near": { "$geometry": { "type": "Point", "coordinates": location }, "$maxDistance": 30000 }} } } } ) for entry in applications_nearby: if not entry["user"] == msg.from_user.id: diff --git a/modules/database.py b/modules/database.py index 8b038cb..9a4ba1d 100644 --- a/modules/database.py +++ b/modules/database.py @@ -37,4 +37,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.loc", GEOSPHERE)]) \ No newline at end of file +col_applications.create_index([("application.3.location", GEOSPHERE)]) \ No newline at end of file -- 2.39.2