From b173544506257778be6429fe2e03e929a5eac00f Mon Sep 17 00:00:00 2001 From: Profitroll <47523801+profitrollgame@users.noreply.github.com> Date: Thu, 20 Oct 2022 12:24:32 +0200 Subject: [PATCH] Locales added --- TASK.md | 4 +-- config_example.json | 1 + data/user_default.json | 23 +++++++++++++ locale/uk.json | 61 ++++++++++++++++++++++++++++++++++ main.py | 23 +++++++++++-- modules/utils.py | 75 +++++++++++++++++++++++------------------- 6 files changed, 149 insertions(+), 38 deletions(-) create mode 100644 data/user_default.json create mode 100644 locale/uk.json diff --git a/TASK.md b/TASK.md index a5ae1b9..47f1605 100644 --- a/TASK.md +++ b/TASK.md @@ -5,10 +5,10 @@ 1. Лінка веде на бота. 2. Перший пост від бота: вітання та питання, чи хоче людина доєднатися до українського ком'юніті фанатів Хололайва 3. Дві кнопки: "Так-Ні" -3а. Якщо "Ні", то бот вибачається та каже, що, коли захоче, то людина фрі ту джоін. Під цим кнопка "Я передумав, я хочу" + * Якщо "Ні", то бот вибачається та каже, що, коли захоче, то людина фрі ту джоін. Під цим кнопка "Я передумав, я хочу" 4. Якщо "Так", бот кидає анкету та просить заповнити за пунктами. Після цього наступна відповідь людини пересилається в чат ХолоКиїв (лінку дамо тобі) 5. З адмінської сторони має бути доступ до бота з окремим адмін-доступом, де можна для кожного юзера, який відправив анкету ботові, натиснути кнопку апрув або дінай -5а. Якщо дінай, бот вибачається та каже повертатися, коли буде бажання втягнутися + * Якщо дінай, бот вибачається та каже повертатися, коли буде бажання втягнутися 6. Якщо апрув, бот кидає лінку до чату Можно кидать не просто "заполните анкету", а что бы бот поочерёдно задавал вопросы. И после каждого ответа, он их сохранял в отдельное облако ответов diff --git a/config_example.json b/config_example.json index 3e8bc14..87d515a 100644 --- a/config_example.json +++ b/config_example.json @@ -1,4 +1,5 @@ { + "locale": "uk", "owner": 0, "admins": [], "bot": { diff --git a/data/user_default.json b/data/user_default.json new file mode 100644 index 0000000..7cf3b68 --- /dev/null +++ b/data/user_default.json @@ -0,0 +1,23 @@ +{ + "stage": 0, + "link": null, + "approved": false, + "approved_by": null, + "application_date": null, + "approval_date": null, + "telegram_id": null, + "telegram_name": null, + "telegram_phone": null, + "application": { + "1": null, + "2": null, + "3": null, + "4": null, + "5": null, + "6": null, + "7": null, + "8": null, + "9": null, + "10": null + } +} \ No newline at end of file diff --git a/locale/uk.json b/locale/uk.json new file mode 100644 index 0000000..d1dd2a9 --- /dev/null +++ b/locale/uk.json @@ -0,0 +1,61 @@ +{ + "commands": { + "start": "Почати користуватись ботом", + "rules": "Правила пропонування фото" + }, + "commands_admin": { + "forwards": "Переглянути репости", + "reboot": "Перезапустити бота" + }, + "message": { + "start": "Привіт і ласкаво просимо!\n\nЦей бот створено для прийому заявок на вступ до нашої спільноти. Для продовження нас цікавить відповідь на одне питання:\n\nЧи хочеш ти доєднатися до українського ком'юніті фанатів Хололайв?", + "goodbye": "Добре, дякуємо за чесність! Вибачте, але за таких умов ми не будемо тебе додавати до спільноти. Якщо передумаєш та захочеш приєднатись - просто натисни на кнопку.", + "privacy_notice": "Раді це чути!\n\nДля продовження треба буде заповнити невеличку анкетку. Будь ласка, віднесись до цього серйозно. Ми відповідально ставимось до персональних даних, тому ця анкета не буде передана третім особам, а буде використана лише для проходження до спільноти.", + "question1": "Як до тебе можна звертатись?", + "question2": "Скільки тобі років?", + "question3": "З якого ти міста та де проживаєш зараз?\n\n⚠️ Будь ласка, не вказуйте точних адрес! \"Київщина\" може бути достатньою конкретизацією.", + "question4": "Коли вперше довелось дізнатись про Хололайв?", + "question5": "Чим тебе зацікавив Хололайв?", + "question6": "Контент якої дівчини тобі подобається найбільше?", + "question7": "Назви контент хоча б п'яти японських холодівчат, які тобі подобаються найбільше.", + "question8": "Чи дивишся ти стріми дівчат Хололайву?", + "question9": "Чиї пісні з Хололайву тобі подобаються найбільше?", + "question10": "Ну і нарешті, розкажи трохи про себе. Про хобі, чим тобі подобається займатись. Одним повідомленням, будь ласка.", + "question2_underage": "Вибач, але треба досягти віку {0} років, щоб приєднатись до нас. Такі обмеження існують для того, щоб всім у спільноті було цікаво одне з одним.", + "question2_invalid": "Будь ласка, введи ціле число.", + "question2_joke": "Тижпрограміст, ми так і поняли. Але будь ласка, введи реальне значення.", + "shutdown": "Вимкнення бота з підом `{0}`", + "startup": "Запуск бота з підом `{0}`", + "startup_downtime": "Запуск бота з підом `{0}` (лежав {1})", + "sub_yes": "✅ Подання схвалено та прийнято", + "sub_no": "❌ Подання розглянуто та відхилено" + }, + "keyboards": { + "welcome": [ + [ + "Так, звісно" + ], + [ + "Ні, дякую" + ] + ], + "return": [ + [ + "Я передумав, я хочу" + ] + ] + }, + "force_reply": { + "question1": "Ім'я або звертання" + }, + "button": { + "sub_yes": "✅ Прийняти", + "sub_no": "❌ Відхилити", + "accepted": "✅ Прийнято", + "declined": "❌ Відхилено" + }, + "callback": { + "sub_yes": "✅ Подання схвалено", + "sub_no": "❌ Подання відхилено" + } +} \ No newline at end of file diff --git a/main.py b/main.py index ddcf1fc..86300ca 100644 --- a/main.py +++ b/main.py @@ -4,7 +4,7 @@ from modules.utils import * from pyrogram.client import Client from pyrogram import filters -from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, BotCommand, BotCommandScopeChat +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, BotCommand, BotCommandScopeChat, ReplyKeyboardMarkup, ForceReply from pyrogram import idle # type: ignore from pyrogram.errors.exceptions import bad_request_400 @@ -12,6 +12,19 @@ pid = getpid() app = Client("holochecker", bot_token=configGet("bot_token", "bot"), api_id=configGet("api_id", "bot"), api_hash=configGet("api_hash", "bot")) +@app.on_message(~ filters.scheduled & filters.command(["start"], prefixes=["/"])) +async def cmd_start(app, msg): + + try: + user_conf = configGet("stage", file=str(msg.from_user.id)) + if user_conf["stage"] != 0: + return + except FileNotFoundError: + jsonSave(jsonLoad(f"data{sep}user_default.json"), f"data{sep}users{sep}{msg.from_user.id}.json") + user_conf = configGet("stage", file=str(msg.from_user.id)) + + await msg.reply_text(locale("start"), reply_markup=ReplyKeyboardMarkup(locale("welcome", "keyboards"))) + @app.on_message(~ filters.scheduled & filters.command(["kill", "die", "reboot"], prefixes=["", "/"])) async def cmd_kill(app, msg): @@ -20,13 +33,19 @@ async def cmd_kill(app, msg): await msg.reply_text(f"Вимкнення бота з підом `{pid}`") killProc(pid) +@app.on_message(~ filters.scheduled & (filters.regex(locale("welcome", "keyboards")[0][0]) | filters.regex(locale("return", "keyboards")[0][0]))) +async def any_message(app, msg): + + await msg.reply_text(locale("privacy_notice", "message")) + await msg.reply_text(locale("question1", "message"), reply_markup=ForceReply(placeholder=locale("question1", "force_reply"))) + if __name__ == "__main__": logWrite(f"Starting up with pid {pid}") # Yes, it should be in some kind of async main() function but I don't give a shit. - # I did compare performance and it's much more useful this way. Change my mind. + # I did compare performance, almost no difference and it's much more useful this way. Change my mind. app.start() # type: ignore app.send_message(configGet("owner"), f"Starting up with pid `{pid}`") # type: ignore diff --git a/modules/utils.py b/modules/utils.py index 204d0d5..b43c5ff 100644 --- a/modules/utils.py +++ b/modules/utils.py @@ -1,8 +1,9 @@ +from typing import Union from ujson import JSONDecodeError as JSONDecodeError from ujson import loads, dumps from sys import exit -from os import kill +from os import kill, sep from os import name as osname from traceback import print_exc @@ -33,14 +34,19 @@ def jsonSave(contents, filename): return -def configSet(key: str, value, *args: str): +def configSet(key: str, value, *args: str, file: str = "config"): """Set key to a value Args: * key (str): The last key of the keys path. * value (str/int/float/list/dict/None): Some needed value. * *args (str): Path to key like: dict[args][key]. + * file (str): User ID to save. Saved to config if not provided. Defaults to "config". """ - this_dict = jsonLoad("config.json") + if file == "config": + filepath = "" + else: + filepath = f"data{sep}users{sep}" + this_dict = jsonLoad(f"{filepath}{file}.json") string = "this_dict" for arg in args: string += f'["{arg}"]' @@ -49,54 +55,55 @@ def configSet(key: str, value, *args: str): else: string += f'["{key}"] = {value}' exec(string) - jsonSave(this_dict, "config.json") + jsonSave(this_dict, f"{filepath}{file}.json") return -def configGet(key: str, *args: str): +def configGet(key: str, *args: str, file: str = "config"): """Get value of the config key Args: * key (str): The last key of the keys path. * *args (str): Path to key like: dict[args][key]. + * file (str): User ID to load. Loads config if not provided. Defaults to "config". Returns: * any: Value of provided key """ - this_dict = jsonLoad("config.json") + if file == "config": + this_dict = jsonLoad("config.json") + else: + this_dict = jsonLoad(f"data{sep}users{sep}{file}.json") this_key = this_dict for dict_key in args: this_key = this_key[dict_key] return this_key[key] -# def locale(key: str, *args: str, locale=configGet("locale")): -# """Get value of locale string -# Args: -# * key (str): The last key of the locale's keys path. -# * *args (list): Path to key like: dict[args][key]. -# * locale (str): Locale to looked up in. Defaults to config's locale value. -# Returns: -# * any: Value of provided locale key -# """ -# if (locale == None): -# locale = configGet("locale") +def locale(key: str, *args: str, locale=configGet("locale")) -> Union[str, list, dict]: + """Get value of locale string + Args: + * key (str): The last key of the locale's keys path. + * *args (list): Path to key like: dict[args][key]. + * locale (str): Locale to looked up in. Defaults to config's locale value. + Returns: + * any: Value of provided locale key + """ + if (locale == None): + locale = configGet("locale") -# try: -# this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{locale}.json') -# except FileNotFoundError: -# try: -# this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json') -# except FileNotFoundError: -# try: -# this_dict = jsonLoad(f'{configGet("locale_fallback", "locations")}{sep}{configGet("locale")}.json') -# except: -# return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' + try: + this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{locale}.json') + except FileNotFoundError: + try: + this_dict = jsonLoad(f'{configGet("locale", "locations")}{sep}{configGet("locale")}.json') + except FileNotFoundError: + return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' -# this_key = this_dict -# for dict_key in args: -# this_key = this_key[dict_key] + this_key = this_dict + for dict_key in args: + this_key = this_key[dict_key] -# try: -# return this_key[key] -# except KeyError: -# return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' + try: + return this_key[key] + except KeyError: + return f'⚠️ Locale in config is invalid: could not get "{key}" in {str(args)} from locale "{locale}"' try: from psutil import Process