diff --git a/classes/holo_user.py b/classes/holo_user.py index c6de204..12cfb8c 100644 --- a/classes/holo_user.py +++ b/classes/holo_user.py @@ -1,10 +1,13 @@ +from datetime import datetime +from requests import get from traceback import print_exc from app import app, isAnAdmin -from typing import Any, List, Union -from pyrogram.types import User, ChatMember, ChatPrivileges, Chat, Message, Photo, Video, Document, Animation, Voice +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.client import Client from pyrogram.errors import bad_request_400 -from modules.database import col_users, col_context, col_warnings, col_applications, col_sponsorships, col_messages +from dateutil.relativedelta import relativedelta +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 @@ -232,4 +235,141 @@ class HoloUser(): if (not await isAnAdmin(self.id)) and (chat.id == configGet("admin_group")): await app.promote_chat_member(configGet("destination_group"), self.id, privileges=ChatPrivileges( can_manage_chat=False - )) \ No newline at end of file + )) + + def application_state(self) -> tuple[Literal["none", "fill", "approved", "rejected"], bool]: + tmp_application = col_tmp.find_one({"user": self.id, "type": "application"}) + if tmp_application is None: + return "none", False + else: + return tmp_application["state"], tmp_application["complete"] + + def application_restart(self): + doc = { + "user": self.id, + "type": "application", + "complete": False, + "sent": False, + "state": "fill", + "reapply": False, + "stage": 1, + "application": { + "1": None, + "2": None, + "3": None, + "4": None, + "5": None, + "6": None, + "7": None, + "8": None, + "9": None, + "10": None + } + } + if col_tmp.find_one({"user": self.id, "type": "application"}) is None: + col_tmp.insert_one(document=doc) + else: + col_tmp.delete_one({"user": self.id, "type": "application"}) + col_tmp.insert_one(document=doc) + + async def application_next(self, query: str, msg: Union[Message, None] = None): + + if col_tmp.find_one({"user": self.id, "type": "application"}) is None: + + col_tmp.insert_one( + document={ + "user": self.id, + "type": "application", + "complete": False, + "sent": False, + "state": "fill", + "reapply": False, + "stage": 1, + "application": { + "1": None, + "2": None, + "3": None, + "4": None, + "5": None, + "6": None, + "7": None, + "8": None, + "9": None, + "10": None + } + } + ) + + progress = col_tmp.find_one({"user": self.id, "type": "application"}) + stage = progress["stage"] + + if progress["state"] == "fill": + + if stage == 2: + + try: + input_dt = datetime.strptime(query, "%d.%m.%Y") + except ValueError: + logWrite(f"User {msg.from_user.id} failed stage {stage} due to sending invalid date format") + await msg.reply_text(locale(f"question2_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply")))) + return + + if datetime.now() <= input_dt: + logWrite(f"User {msg.from_user.id} failed stage {stage} due to joking") + await msg.reply_text(locale("question2_joke", "message"), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply")))) + return + + elif ((datetime.now() - input_dt).days) < ((datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days): + logWrite(f"User {msg.from_user.id} failed stage {stage} due to being underage") + await msg.reply_text(locale("question2_underage", "message").format(str(configGet("age_allowed"))), reply_markup=ForceReply(placeholder=str(locale("question2", "force_reply")))) + return + + else: + print(f'Look: {((datetime.now() - input_dt).days)} > {(datetime.now() - datetime.now().replace(year=datetime.now().year - configGet("age_allowed"))).days}') + progress["application"][str(stage)] = input_dt + col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) + await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply")))) + + 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] + 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").format(result["geonames"][0]["name"], result["geonames"][0]["adminName1"])) + await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply")))) + except (ValueError, KeyError, IndexError): + await msg.reply_text(locale(f"question3_invalid", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply")))) + return + except Exception as exp: + await msg.reply_text(locale("question3_error", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage}", "force_reply")))) + try: + await app.send_message(configGet("owner"), locale("question3_traceback", "message").format(query, exp, print_exc())) + except bad_request_400.PeerIdInvalid: + logWrite(f"Could not notify admin about failure when sending message! Admin has never interacted with bot!") + return + + elif stage == 10: + progress["application"][str(stage)] = query + col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "complete": True}}) + application_content = [] + i = 1 + for question in progress["application"]: + if i == 2: + age = relativedelta(datetime.now(), progress['application']['2']) + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['2'].strftime('%d.%m.%Y')} ({age.years} р.)") + elif i == 3: + if progress['application']['3']['countryCode'] == "UA": + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']})") + else: + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application']['3']['name']} ({progress['application']['3']['adminName1']}, {progress['application']['3']['countryName']})") + else: + application_content.append(f"{locale('question'+str(i), 'message', 'question_titles')} {progress['application'][question]}") + i += 1 + await msg.reply_text(locale("confirm", "message").format("\n".join(application_content)), reply_markup=ReplyKeyboardMarkup(locale("confirm", "keyboard"), resize_keyboard=True)) + + else: + progress["application"][str(stage)] = query + col_tmp.update_one({"user": {"$eq": self.id}, "type": {"$eq": "application"}}, {"$set": {"application": progress["application"], "stage": progress["stage"]+1}}) + await msg.reply_text(locale(f"question{stage+1}", "message"), reply_markup=ForceReply(placeholder=str(locale(f"question{stage+1}", "force_reply")))) + + logWrite(f"User {self.id} completed stage {stage} of application") \ No newline at end of file diff --git a/config_example.json b/config_example.json index cfa538b..64717d8 100644 --- a/config_example.json +++ b/config_example.json @@ -22,6 +22,9 @@ "port": 27017, "name": "holochecker" }, + "geocoding": { + "username": "demo" + }, "logging": { "size": 512, "location": "logs" diff --git a/locale/uk.json b/locale/uk.json index 7e62a86..9078c0b 100644 --- a/locale/uk.json +++ b/locale/uk.json @@ -5,7 +5,7 @@ "privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.", "question1": "Як до тебе можна звертатись?", "question2": "Коли в тебе день народження?", - "question3": "З якого ти міста та де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київщина\" може бути достатньою конкретизацією.", + "question3": "З якого ти міста або де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київ\" або \"Київська Область\" є достатньою конкретизацією.\n\nПриклади:\n• Київ\n• Одеська область\n• Макіївка (Луганська область)", "question4": "Коли вперше довелось дізнатись про Хололайв?", "question5": "Чим тебе зацікавив Хололайв?", "question6": "Контент якої дівчини тобі подобається найбільше?", @@ -16,6 +16,10 @@ "question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.", "question2_invalid": "Будь ласка, введи дату формату `ДД.ММ.РРРР`", "question2_joke": "Шутнік, ми так і поняли. Але будь ласка, введи реальне значення.", + "question3_invalid": "Місто/населений пункт не знайдено. Користуйтесь прикладами нижче щоб вказати де ви проживаєте та спробуйте ще раз:\n\n• Київ\n• Одеська область\n• Макіївка (Луганська область)", + "question3_found": "Використовую наступний результат:\n• {0} ({1})", + "question3_error": "⚠️ **Сталась помилка**\nНе вдалось отримати географічну мітку. Розробника повідомлено про цю помилку. Будь ласка, спробуйте ще раз.", + "question3_traceback": "⚠️ **Сталась помилка**\nПомилка отримання геокодингу для `{0}`\nПомилка: `{1}`\n\nTraceback:\n```\n{2}\n```", "confirm": "Супер, дякуємо!\n\nБудь ласка, перевір правильність даних:\n{0}\n\nВсе правильно?", "application_sent": "Дякуємо! Ми надіслали твою анкетку на перевірку. Ти отримаєш повідомлення як тільки її перевірять та приймуть рішення. До тих пір від тебе більше нічого не потребується. Гарного дня! :)", "application_got": "Отримано анкету від `{0}`\n\nІм'я тг: `{1}`, `{2}`\nЮзернейм: @{3}\n\n**Дані анкети:**\n{4}",