diff --git a/.env.dist b/.env.dist index bbf4e5d..822e4e4 100644 --- a/.env.dist +++ b/.env.dist @@ -5,15 +5,12 @@ IP= TIMEZONE= MODERATE_CHAT= -POSTGRES_USER= -POSTGRES_PASSWORD= -DB_HOST= -DB_PORT= -POSTGRES_DB= +SIGNATURE_SECRET_KEY= +USE_REDIS= -SECRET_KEY= -API_KEY= +REDIS_PORT= +REDIS_HOST= -QIWI_KEY= -PHONE_NUMBER= -SECRET_P2= \ No newline at end of file +API_ID= +API_HASH= +SESSION_STR= diff --git a/.gitignore b/.gitignore index 7aa9e8c..eeafb93 100644 --- a/.gitignore +++ b/.gitignore @@ -133,4 +133,5 @@ dmypy.json # Django Settings with Secret key /django_project/django_project/settings.py -photos/ \ No newline at end of file +photos/ +!photos/.gitkeep diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ddbbf05 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,34 @@ +exclude: 'docs|frontend|deprecated|README.md|CODE_OF_CONDUCT.md|LICENSE|.github' +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + - id: check-toml + - id: end-of-file-fixer + - id: trailing-whitespace + - repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: [ --py38-plus ] + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.1.8" + hooks: + - id: ruff + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + additional_dependencies: + - mdformat-gfm + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.5.1 + hooks: + - id: mypy + args: [ --follow-imports=silent, --disable-error-code=no-untyped-call, --explicit-package-bases ] + exclude: tests/ diff --git a/Dockerfile b/Dockerfile index 0a4cdde..6db380f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,4 +10,3 @@ WORKDIR /src COPY requirements.txt /src RUN pip install -r /src/requirements.txt COPY . /src - diff --git a/README.md b/README.md index ee1064c..8b4e375 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,7 @@ ### :monocle_face: About -| 🏗️ The project has moved elsewhere, and currently available at [que.group](https://github.com/QueGroup) | -|----------------------------------------------------------------------------------------------------------| - -Open-source Dating Telegram bot built on aiogram 2.x to facilitate the search for new connections. The bot incorporates +Open-source Dating Telegram bot built on aiogram 3.x to facilitate the search for new connections. The bot incorporates a classic profile browsing system, along with filtering options and event organization capabilities. Users can create and join events, fostering community engagement. Additionally, the project is closely integrated with neural networks, enhancing its capabilities. @@ -20,13 +17,13 @@ enhancing its capabilities. ### :alembic: Built With ![Python](https://img.shields.io/badge/Python-FFD43B?style=for-the-badge&logo=python&logoColor=blue)\ -![Django](https://img.shields.io/badge/Django-092E20?style=for-the-badge&logo=django&logoColor=green)\ ![AIOHTTP](https://img.shields.io/badge/aiohttp-%232C5bb4.svg?style=for-the-badge&logo=aiohttp&logoColor=white)\ ![Poetry](https://img.shields.io/badge/Poetry-%233B82F6.svg?style=for-the-badge&logo=poetry&logoColor=0B3D8D)\ -![Babel](https://img.shields.io/badge/Babel-F9DC3e?style=for-the-badge&logo=babel&logoColor=black)\ -![Postgresql](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white)\ ![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge&logo=docker&logoColor=white)\ -![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white) +![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)\ +![Aiogram](https://img.shields.io/badge/aiogram--V3-blue?style=for-the-badge&logo=telegram&logoColor=white)\ +![Redis](https://img.shields.io/badge/redis-%23DD0031.svg?style=for-the-badge&logo=redis&logoColor=white)\ +![GitHub Actions](https://img.shields.io/badge/github%20actions-%232671E5.svg?style=for-the-badge&logo=githubactions&logoColor=white) ### :hammer: Development diff --git a/app.py b/app.py deleted file mode 100644 index a9004f5..0000000 --- a/app.py +++ /dev/null @@ -1,66 +0,0 @@ -# noinspection PyUnresolvedReferences -import logging -import os - -import django -from aiogram import ( - executor, -) - -# noinspection PyUnresolvedReferences -import filters - -# noinspection PyUnresolvedReferences -from django_project.telegrambot.telegrambot import ( - settings, -) - -from loader import ( - dp, - scheduler, -) -from utils.db_api.db_commands import ( - reset_view_limit, -) -from utils.logger import ( - setup_logger, -) -from utils.notify_admins import ( - AdminNotification, -) -from utils.set_bot_commands import ( - set_default_commands, -) - - -async def on_startup(dispatcher) -> None: - await set_default_commands(dispatcher) - scheduler.add_job( - func=reset_view_limit, - trigger="cron", - hour=0, - id="reset_view_limit", - replace_existing=True, - ) - await AdminNotification.send(dispatcher) - - -def setup_django(): - os.environ.setdefault( - "DJANGO_SETTINGS_MODULE", "django_project.telegrambot.telegrambot.settings" - ) - os.environ.update({"DJANGO_ALLOW_ASYNC_UNSAFE": "true"}) - django.setup() - - -if __name__ == "__main__": - setup_django() - setup_logger("INFO", ["aiogram.bot.api"]) - # noinspection PyUnresolvedReferences - import middlewares - - # noinspection PyUnresolvedReferences - import handlers - - scheduler.start() - executor.start_polling(dp, on_startup=on_startup, skip_updates=True) diff --git a/babel.cfg b/babel.cfg index 40fadc3..ec17d42 100644 --- a/babel.cfg +++ b/babel.cfg @@ -1,10 +1,7 @@ -[python: data/**.py] -[python: django_project/**.py] -[python: filters/**.py] -[python: functions/**.py] -[python: handlers/**.py] -[python: keyboards/**.py] -[python: logs/**.py] -[python: middlewares/**.py] -[python: utils/**.py] -encoding = utf-8 \ No newline at end of file +[python: src/tgbot/filters/**.py] +[python: src/tgbot/services/**.py] +[python: src/tgbot/handlers/**.py] +[python: src/tgbot/keyboards/**.py] +[python: src/tgbot/middlewares/**.py] +[python: src/tgbot/utils/**.py] +encoding = utf-8 diff --git a/bot.conf b/bot.conf index 931814b..ac1562f 100644 --- a/bot.conf +++ b/bot.conf @@ -17,4 +17,4 @@ autorestart=true autorestart=true environment=HOME="/home/ubuntu",USER="ubuntu" stderr_logfile=/home/ubuntu/DatingBot/logfile_err_django.log -stdout_logfile=/home/ubuntu/DatingBot/logfile_django.log \ No newline at end of file +stdout_logfile=/home/ubuntu/DatingBot/logfile_django.log diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..65c01ca --- /dev/null +++ b/bot.py @@ -0,0 +1,156 @@ +import asyncio +import logging +from typing import ( + Sequence, +) + +from aiogram import ( + Bot, + Dispatcher, +) +from aiogram.client.default import ( + DefaultBotProperties, +) +from aiogram.enums import ( + ParseMode, +) +from aiogram.fsm.storage.memory import ( + MemoryStorage, +) +from aiogram.fsm.storage.redis import ( + DefaultKeyBuilder, + RedisStorage, +) +from aiogram.utils.i18n import ( + ConstI18nMiddleware, + I18n, +) +import betterlogging as bl +from que_sdk import ( + QueClient, +) +from redis.asyncio.client import Redis # type: ignore +from yandex_geocoder import ( + Client, +) + +from src.tgbot import ( + services, +) +from src.tgbot.config import ( + Config, + load_config, +) +from src.tgbot.handlers import ( + routers_list, +) +from src.tgbot.middlewares import ( # type: ignore + AccessControlMiddleware, + AlbumMiddleware, + DIMiddleware, +) + + +async def on_startup(bot: Bot, admin_ids: Sequence[int]) -> None: + await services.broadcast(bot, list(admin_ids), "Бот запущен") # type: ignore + + +def setup_logging() -> None: + """ + Set up logging configuration for the application. + + This method initializes the logging configuration for the application. + It sets the log level to INFO and configures a basic colorized log for + output. The log format includes the filename, line number, log level, + timestamp, logger name, and log message. + + Returns: + None + + Example usage: + setup_logging() + """ + log_level = logging.INFO + bl.basic_colorized_config(level=log_level) + + logging.basicConfig( + level=logging.INFO, + format="%(filename)s:%(lineno)d #%(levelname)-8s [%(asctime)s] - %(name)s - %(message)s", + ) + logger = logging.getLogger(__name__) + logger.info("Starting bot") + + +def register_global_middlewares( + dp: Dispatcher, + config: Config, + client: QueClient, + redis: Redis, + i18n: I18n, + ya_client: Client +) -> None: + logging.info("Setup middlewares...") + middleware_types = [ + DIMiddleware(config, client, ya_client), + AccessControlMiddleware(client=client), + ConstI18nMiddleware(locale="ru", i18n=i18n) + ] + # dp.message.middleware(ThrottlingMiddleware(redis)) + dp.message.middleware(AlbumMiddleware()) + for middleware_type in middleware_types: + dp.message.outer_middleware(middleware_type) + dp.callback_query.outer_middleware(middleware_type) + + +def get_storage(config: Config) -> MemoryStorage | RedisStorage: + """ + Return storage based on the provided configuration. + + Args: + config (Config): The configuration object. + + Returns: + Storage: The storage object based on the configuration. + """ + if config.tg_bot.use_redis: + return RedisStorage.from_url( + config.redis.dsn(), + key_builder=DefaultKeyBuilder(with_bot_id=True, with_destiny=True), + ) + else: + return MemoryStorage() + + +async def main() -> None: + setup_logging() + + config = load_config() + i18n = I18n(path=config.tg_bot.LOCALES_DIR, default_locale="ru", domain="messages") + storage = get_storage(config) + client = QueClient() + ya_client = Client(api_key=config.misc.yandex_map_api_key) + + redis = Redis( + host=config.redis.host, + port=config.redis.port, + decode_responses=True, + max_connections=10, + auto_close_connection_pool=True + ) + + bot = Bot(token=config.tg_bot.token, default=DefaultBotProperties(parse_mode=ParseMode.MARKDOWN)) + dp = Dispatcher(storage=storage) + + register_global_middlewares(dp, config, client, redis, i18n, ya_client) + dp.include_routers(*routers_list) + await services.set_default_commands(bot, config) + await on_startup(bot, config.tg_bot.admin_ids) + await dp.start_polling(bot) + + +if __name__ == "__main__": + try: + # FIXME: Почему-то с редисом asyncio.run(main()) не работает + asyncio.get_event_loop().run_until_complete(main()) + except (KeyboardInterrupt, SystemExit): + logging.error("Бот был выключен!") diff --git a/brandbook/1_page.png b/brandbook/1_page.png deleted file mode 100644 index a6811ef..0000000 Binary files a/brandbook/1_page.png and /dev/null differ diff --git a/brandbook/2_page.png b/brandbook/2_page.png deleted file mode 100644 index ad2ff2d..0000000 Binary files a/brandbook/2_page.png and /dev/null differ diff --git a/brandbook/3_page.png b/brandbook/3_page.png deleted file mode 100644 index 0d9f882..0000000 Binary files a/brandbook/3_page.png and /dev/null differ diff --git a/brandbook/4_page.png b/brandbook/4_page.png deleted file mode 100644 index 2aa80a4..0000000 Binary files a/brandbook/4_page.png and /dev/null differ diff --git a/data/config.py b/data/config.py deleted file mode 100644 index 1e42f74..0000000 --- a/data/config.py +++ /dev/null @@ -1,121 +0,0 @@ -from dataclasses import ( - dataclass, -) -from functools import ( - lru_cache, -) -import inspect -from pathlib import ( - Path, -) -from typing import ( - List, -) - -from environs import ( - Env, -) -from yarl import ( - URL, -) - -env = Env() -env.read_env() - - -# The frozen=True arg protects instances of the class from accidental modification -@dataclass(frozen=True, slots=True) -class DataBaseConfig: - user: str - password: str - host: str - database: str - port: str - - -@dataclass(frozen=True, slots=True) -class TgBot: - token: str - admin_ids: List[int] - support_ids: List[int] - timezone: str - ip: str - I18N_DOMAIN: str - moderate_chat: int - use_redis: bool - - -@dataclass(frozen=True, slots=True) -class Miscellaneous: - secret_key: str - yandex_api_key: str - client_id: str - redirect_url: URL - yoomoney_key: str - production: bool - - -@dataclass(frozen=True, slots=True) -class Config: - tg_bot: TgBot - db: DataBaseConfig - misc: Miscellaneous - - -def search_env() -> Path: - current_frame = inspect.currentframe() - frame = current_frame.f_back - caller_dir = Path(frame.f_code.co_filename).parent.resolve() - start = caller_dir / ".env" - return start - - -def change_env(section: str, value: str) -> None: - dumped_env = env.dump() - text = "" - start = search_env() - - with open(start, "w", encoding="utf-8") as file: - for v in dumped_env: - if v: - e = dumped_env[v] - if v == section: - e = value - text += f"{v}={e}\n" - file.write(text) - - -@lru_cache -def load_config() -> Config: - return Config( - tg_bot=TgBot( - token=env.str("BOT_TOKEN"), - admin_ids=list(map(int, env.list("ADMINS"))), - support_ids=list(map(int, env.list("SUPPORTS"))), - ip=env.str("IP"), - timezone=env.str("TIMEZONE"), - I18N_DOMAIN="dating", - moderate_chat=env.int("MODERATE_CHAT"), - use_redis=env.bool("USE_REDIS"), - ), - db=DataBaseConfig( - user=env.str("POSTGRES_USER"), - password=env.str("POSTGRES_PASSWORD"), - host=env.str("DB_HOST"), - database=env.str("POSTGRES_DB"), - port=env.str("DB_PORT"), - ), - misc=Miscellaneous( - secret_key=env.str("SECRET_KEY"), - yandex_api_key=env.str("API_KEY"), - client_id=env.str("CLIENT_ID"), - redirect_url=env.str("REDIRECT_URI"), - yoomoney_key=env.str("YOOMONEY_KEY"), - production=env.bool("PRODUCTION"), - ), - ) - - -# TODO: Move to dataclass -BASE_DIR = Path(__file__).parent.parent -LOCALES_DIR = BASE_DIR / "locales" diff --git a/data/__init__.py b/deprecated/admin/__init__.py similarity index 100% rename from data/__init__.py rename to deprecated/admin/__init__.py diff --git a/django_project/__init__.py b/deprecated/admin/inline/__init__.py similarity index 100% rename from django_project/__init__.py rename to deprecated/admin/inline/__init__.py diff --git a/keyboards/admin/inline/customers.py b/deprecated/admin/inline/customers.py similarity index 99% rename from keyboards/admin/inline/customers.py rename to deprecated/admin/inline/customers.py index b5af811..9214a48 100644 --- a/keyboards/admin/inline/customers.py +++ b/deprecated/admin/inline/customers.py @@ -5,7 +5,6 @@ from aiogram.utils.callback_data import ( CallbackData, ) - from loader import ( _, ) diff --git a/keyboards/admin/inline/mailing.py b/deprecated/admin/inline/mailing.py similarity index 99% rename from keyboards/admin/inline/mailing.py rename to deprecated/admin/inline/mailing.py index 1c693e3..ed58cc0 100644 --- a/keyboards/admin/inline/mailing.py +++ b/deprecated/admin/inline/mailing.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/admin/inline/payments.py b/deprecated/admin/inline/payments.py similarity index 99% rename from keyboards/admin/inline/payments.py rename to deprecated/admin/inline/payments.py index 99149d6..1ab0d6f 100644 --- a/keyboards/admin/inline/payments.py +++ b/deprecated/admin/inline/payments.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/admin/inline/ref.py b/deprecated/admin/inline/ref.py similarity index 99% rename from keyboards/admin/inline/ref.py rename to deprecated/admin/inline/ref.py index 021f3d6..fa696a5 100644 --- a/keyboards/admin/inline/ref.py +++ b/deprecated/admin/inline/ref.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/admin/inline/reply_menu.py b/deprecated/admin/inline/reply_menu.py similarity index 99% rename from keyboards/admin/inline/reply_menu.py rename to deprecated/admin/inline/reply_menu.py index 2aa8669..ac366b8 100644 --- a/keyboards/admin/inline/reply_menu.py +++ b/deprecated/admin/inline/reply_menu.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/admin/inline/setting.py b/deprecated/admin/inline/setting.py similarity index 99% rename from keyboards/admin/inline/setting.py rename to deprecated/admin/inline/setting.py index d9f7243..e92a6c2 100644 --- a/keyboards/admin/inline/setting.py +++ b/deprecated/admin/inline/setting.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/admin/main_menu.py b/deprecated/admin/main_menu.py similarity index 100% rename from keyboards/admin/main_menu.py rename to deprecated/admin/main_menu.py diff --git a/functions/main_app/app_scheduler.py b/deprecated/app_scheduler.py similarity index 79% rename from functions/main_app/app_scheduler.py rename to deprecated/app_scheduler.py index fc7e435..b99d7a1 100644 --- a/functions/main_app/app_scheduler.py +++ b/deprecated/app_scheduler.py @@ -1,20 +1,17 @@ from aiogram.types import ( Message, ) - -from keyboards.inline.questionnaires_inline import ( - viewing_ques_keyboard, -) from loader import ( _, bot, ) -from utils.db_api import ( - db_commands, + +from src.tgbot.keyboards.inline.questionnaires_inline import ( + viewing_ques_keyboard, ) -async def send_message_week(message: Message) -> None: +async def send_message_week(message: Message, db_commands=None) -> None: user = await db_commands.select_user(telegram_id=message.from_user.id) user_gender = "Парней" if user.need_partner_sex == "Мужской" else "Девушек" diff --git a/utils/misc/AsyncObj.py b/deprecated/async_obj.py similarity index 79% rename from utils/misc/AsyncObj.py rename to deprecated/async_obj.py index 32f7654..b9f0068 100644 --- a/utils/misc/AsyncObj.py +++ b/deprecated/async_obj.py @@ -1,11 +1,12 @@ import asyncio from typing import ( - NoReturn, + Any, + Generator, ) class AsyncObj: - def __init__(self, *args, **kwargs): + def __init__(self, *args: Any, **kwargs: Any) -> None: """ Init. @@ -15,7 +16,7 @@ def __init__(self, *args, **kwargs): self.__stored_args = args, kwargs self.async_initialized = False - async def __ainit__(self, *args, **kwargs) -> None: + async def __ainit__(self, *args: Any, **kwargs: Any) -> None: """Async constructor, you should implement this.""" async def __initobj(self) -> "AsyncObj": @@ -26,10 +27,10 @@ async def __initobj(self) -> "AsyncObj": await self.__ainit__(*self.__stored_args[0], **self.__stored_args[1]) return self - def __await__(self): + def __await__(self) -> Generator[Any, None, "AsyncObj"]: return self.__initobj().__await__() - def __init_subclass__(cls, **kwargs) -> NoReturn: + def __init_subclass__(cls, **kwargs: Any) -> None: # __ainit__ must be async assert asyncio.iscoroutinefunction(cls.__ainit__) diff --git a/functions/dating/create_forms_funcs.py b/deprecated/create_forms_funcs.py similarity index 88% rename from functions/dating/create_forms_funcs.py rename to deprecated/create_forms_funcs.py index c6ce1f4..95a1f9b 100644 --- a/functions/dating/create_forms_funcs.py +++ b/deprecated/create_forms_funcs.py @@ -1,8 +1,5 @@ import random import secrets -from typing import ( - Optional, -) from aiogram.types import ( CallbackQuery, @@ -10,25 +7,25 @@ from aiogram.utils.exceptions import ( BadRequest, ) +from loader import ( + bot, +) -from functions.dating.get_next_user_func import ( +from deprecated.get_next_user_func import ( get_next_user, ) -from functions.dating.send_form_func import ( +from deprecated.send_form_func import ( send_questionnaire, ) -from keyboards.inline.questionnaires_inline import ( +from src.tgbot.keyboards.inline.questionnaires_inline import ( questionnaires_keyboard, ) -from loader import ( - bot, -) async def create_questionnaire( form_owner: int, chat_id: int, - add_text: Optional[str] = None, + add_text: str | None = None, monitoring: bool = False, report_system: bool = False, ) -> None: diff --git a/deprecated/data_operations.py b/deprecated/data_operations.py new file mode 100644 index 0000000..8386636 --- /dev/null +++ b/deprecated/data_operations.py @@ -0,0 +1,20 @@ +import shutil + +import aiofiles + + +async def dump_users_to_file(db_commands=None): + async with aiofiles.open("users.txt", "w", encoding="utf-8") as file: + _text = "" + _users = await db_commands.select_all_users() + for user in _users: + _text += str(user) + "\n" + + await file.write(_text) + + return "users.txt" + + +async def backup_configs(): + shutil.make_archive("backup_data", "zip", "./logs/") + return "./backup_data.zip" diff --git a/django_project/telegrambot/__init__.py b/deprecated/default/__init__.py similarity index 100% rename from django_project/telegrambot/__init__.py rename to deprecated/default/__init__.py diff --git a/keyboards/default/admin_default.py b/deprecated/default/admin_default.py similarity index 99% rename from keyboards/default/admin_default.py rename to deprecated/default/admin_default.py index 728e579..51d66c5 100644 --- a/keyboards/default/admin_default.py +++ b/deprecated/default/admin_default.py @@ -2,7 +2,6 @@ KeyboardButton, ReplyKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/default/get_contact_default.py b/deprecated/default/get_contact_default.py similarity index 99% rename from keyboards/default/get_contact_default.py rename to deprecated/default/get_contact_default.py index 43e6f82..196919f 100644 --- a/keyboards/default/get_contact_default.py +++ b/deprecated/default/get_contact_default.py @@ -2,7 +2,6 @@ KeyboardButton, ReplyKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/default/get_location_default.py b/deprecated/default/get_location_default.py similarity index 99% rename from keyboards/default/get_location_default.py rename to deprecated/default/get_location_default.py index 22aad08..0181a5a 100644 --- a/keyboards/default/get_location_default.py +++ b/deprecated/default/get_location_default.py @@ -2,7 +2,6 @@ KeyboardButton, ReplyKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/default/get_photo.py b/deprecated/default/get_photo.py similarity index 99% rename from keyboards/default/get_photo.py rename to deprecated/default/get_photo.py index e19c7ea..cc4dcbd 100644 --- a/keyboards/default/get_photo.py +++ b/deprecated/default/get_photo.py @@ -2,7 +2,6 @@ KeyboardButton, ReplyKeyboardMarkup, ) - from loader import ( _, ) diff --git a/functions/main_app/determin_location.py b/deprecated/determin_location.py similarity index 81% rename from functions/main_app/determin_location.py rename to deprecated/determin_location.py index eea9ea2..10c37af 100644 --- a/functions/main_app/determin_location.py +++ b/deprecated/determin_location.py @@ -9,22 +9,19 @@ from aiogram.types import ( Message, ) - -from keyboards.inline.registration_inline import ( - confirm_keyboard, -) from loader import ( _, client, logger, ) -from utils.YandexMap.exceptions import ( + +from src.infrastructure.YandexMap.exceptions import ( NothingFound, ) -from utils.db_api import ( - db_commands, +from src.tgbot.keyboards.inline.registration_inline import ( + confirm_keyboard, ) -from utils.misc.AsyncObj import ( +from src.tgbot.misc.async_obj import ( AsyncObj, ) @@ -64,7 +61,7 @@ async def det_loc(self) -> None: class RegistrationStrategy(UserDataUpdateStrategy): - async def update_user_data(self: Location, message: Message): + async def update_user_data(self: Location, message: Message, db_commands=None): await db_commands.update_user_data( telegram_id=message.from_user.id, city=self.city, @@ -75,21 +72,21 @@ async def update_user_data(self: Location, message: Message): class FiltersStrategy(UserDataUpdateStrategy): - async def update_user_data(self: Location, message: Message): + async def update_user_data(self: Location, message: Message, db_commands=None): await db_commands.update_user_data( telegram_id=message.from_user.id, need_city=self.city ) class EventStrategy(UserDataUpdateStrategy): - async def update_user_data(self: Location, message: Message): + async def update_user_data(self: Location, message: Message, db_commands=None): await db_commands.update_user_meetings_data( telegram_id=message.from_user.id, venue=self.city ) class EventFiltersStrategy(UserDataUpdateStrategy): - async def update_user_data(self: Location, message: Message): + async def update_user_data(self: Location, message: Message, db_commands=None): await db_commands.update_user_meetings_data( telegram_id=message.from_user.id, need_location=self.city ) diff --git a/deprecated/extra_features.py b/deprecated/extra_features.py new file mode 100644 index 0000000..72d5fab --- /dev/null +++ b/deprecated/extra_features.py @@ -0,0 +1,119 @@ +# from datetime import ( +# datetime, +# ) +# +# from aiogram.types import ( +# CallbackQuery, +# ) +# from aiogram.utils.exceptions import ( +# BadRequest, +# ) +# +# from loader import ( +# _, +# bot, +# ) +# from src.infrastructure.db_api import ( +# db_commands, +# ) +# from deprecated.templates_messages import ( +# ME, +# ) +# +# +# async def add_events_to_user(call: CallbackQuery, event_id: int) -> None: +# """Function that stores id's of events liked by a user.""" +# user = await db_commands.select_user(telegram_id=call.from_user.id) +# event_list = user.events +# +# if str(event_id) not in event_list: +# await db_commands.update_user_events( +# telegram_id=call.from_user.id, events_id=event_id +# ) +# +# +# async def check_availability_on_event() -> bool: +# """Function that checks the availability of seats for an event.""" +# ... +# +# +# async def check_event_date(telegram_id: int) -> None: +# """Function that checks whether an event has passed or not.""" +# event = await db_commands.select_user_meetings(telegram_id) +# event_time = event.time_event +# if event_time is None: +# return +# event_datetime, now_datetime = ( +# datetime.strptime(event_time, "%d-%m-%Y"), +# datetime.now().date(), +# ) +# is_admin = True +# verification_status = True +# is_active = True +# +# if event_datetime.date() <= now_datetime: +# is_admin = False +# verification_status = False +# is_active = False +# await db_commands.update_user_meetings_data( +# telegram_id=telegram_id, +# is_admin=is_admin, +# verification_status=verification_status, +# is_active=is_active, +# ) +# +# +# async def create_form( +# form_owner: int, chat_id: int, call: CallbackQuery, view: bool | None = True +# ) -> None: +# """Function that fills the form with text.""" +# try: +# owner = await db_commands.select_user_meetings(telegram_id=form_owner) +# document = { +# "title": owner.event_name, +# "date": owner.time_event, +# "place": owner.venue, +# "description": owner.commentary, +# "photo_id": owner.photo_id, +# "telegram_id": form_owner, +# } +# if view: +# await ME.send_event_message( +# text=document, bot=bot, chat_id=chat_id, view_event=True, call=call +# ) +# else: +# await ME.send_event_list( +# text=document, call=call, bot=bot, telegram_id=call.from_user.id +# ) +# except BadRequest: +# await call.answer( +# text=_("На данный момент у нас нет подходящих мероприятий для вас"), +# show_alert=True, +# ) +# +# +# async def get_next_random_event_id(telegram_id: int) -> int | None: +# """Function that returns a random id of an event created by another user.""" +# event_ids = await db_commands.search_event_forms() +# +# other_events_ids = [] +# for e in event_ids: +# if e["telegram_id"] != telegram_id: +# other_events_ids.append(e["telegram_id"]) +# +# for event_id in other_events_ids: +# if not await db_commands.check_returned_event_id( +# telegram_id=telegram_id, id_of_events_seen=event_id +# ): +# await db_commands.add_returned_event_id( +# telegram_id=telegram_id, id_of_events_seen=event_id +# ) +# return event_id +# +# raise ValueError("No more event ids") +# +# +# async def get_next_registration(telegram_id: int) -> list[int]: +# user = await db_commands.select_user(telegram_id=telegram_id) +# events: list = user.events +# return events diff --git a/deprecated/get_next_user_func.py b/deprecated/get_next_user_func.py new file mode 100644 index 0000000..cea47f8 --- /dev/null +++ b/deprecated/get_next_user_func.py @@ -0,0 +1,53 @@ +# from typing import ( +# List, +# ) +# +# from async_lru import ( +# alru_cache, +# ) +# +# from src.infrastructure.db_api import ( +# db_commands, +# ) +# +# +# @alru_cache +# async def get_next_user( +# telegram_id: int, monitoring: bool = False, offset: int = 0, limit: int = 100 +# ) -> List[int]: +# user = await db_commands.select_user_object(telegram_id=telegram_id) +# viewed_profiles = user.viewed_profiles.all() +# +# if monitoring: +# user_filter = await db_commands.search_users_all(offset, limit) +# else: +# user_filter = await db_commands.search_users( +# user.need_partner_sex, +# user.need_partner_age_min, +# user.need_partner_age_max, +# user.need_city, +# offset, +# limit, +# ) +# +# viewed_profiles_ids = [profile.telegram_id for profile in viewed_profiles] +# +# user_list = [] +# for i in user_filter: +# if ( +# int(i["telegram_id"]) != int(telegram_id) +# and i["telegram_id"] not in viewed_profiles_ids +# ): +# user_list.append(i["telegram_id"]) +# +# if not user_list: +# user_filter_2 = await db_commands.search_users_all(offset, limit) +# for k in user_filter_2: +# if ( +# k not in user_filter +# and int(k["telegram_id"]) != int(telegram_id) +# and k["telegram_id"] not in viewed_profiles_ids +# ): +# user_list.append(k["telegram_id"]) +# +# return user_list diff --git a/django_project/telegrambot/common/__init__.py b/deprecated/handlers/__init__.py similarity index 100% rename from django_project/telegrambot/common/__init__.py rename to deprecated/handlers/__init__.py diff --git a/handlers/admins/__init__.py b/deprecated/handlers/admins/__init__.py similarity index 100% rename from handlers/admins/__init__.py rename to deprecated/handlers/admins/__init__.py diff --git a/handlers/admins/advert/__init__.py b/deprecated/handlers/admins/advert/__init__.py similarity index 100% rename from handlers/admins/advert/__init__.py rename to deprecated/handlers/admins/advert/__init__.py diff --git a/handlers/admins/advert/advertisement.py b/deprecated/handlers/admins/advert/advertisement.py similarity index 87% rename from handlers/admins/advert/advertisement.py rename to deprecated/handlers/admins/advert/advertisement.py index 1db9d64..b96eaf2 100644 --- a/handlers/admins/advert/advertisement.py +++ b/deprecated/handlers/admins/advert/advertisement.py @@ -5,20 +5,20 @@ CallbackQuery, Message, ) +from loader import ( + _, + dp, +) -from filters.IsAdminFilter import ( +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from keyboards.admin.inline.mailing import ( +from src.tgbot.keyboards.admin.inline.mailing import ( mailing_menu, ) -from keyboards.inline.cancel_inline import ( +from src.tgbot.keyboards.inline.cancel_inline import ( cancel_keyboard, ) -from loader import ( - _, - dp, -) @dp.message_handler(IsAdmin(), commands="ad", state="*") diff --git a/handlers/admins/advert/mailing/__init__.py b/deprecated/handlers/admins/advert/mailing/__init__.py similarity index 100% rename from handlers/admins/advert/mailing/__init__.py rename to deprecated/handlers/admins/advert/mailing/__init__.py diff --git a/handlers/admins/advert/mailing/create.py b/deprecated/handlers/admins/advert/mailing/create.py similarity index 98% rename from handlers/admins/advert/mailing/create.py rename to deprecated/handlers/admins/advert/mailing/create.py index b549471..93b0356 100644 --- a/handlers/admins/advert/mailing/create.py +++ b/deprecated/handlers/admins/advert/mailing/create.py @@ -15,23 +15,23 @@ escape_md, quote_html, ) - -from filters.IsAdminFilter import ( - IsAdmin, -) -from keyboards.admin.inline.mailing import ( - add_buttons_keyboard, - confirm_with_button_keyboard, -) from loader import ( _, bot, dp, logger, ) -from utils.db_api import ( + +from src.infrastructure.db_api import ( db_commands, ) +from src.tgbot.filters.is_admin_filter import ( + IsAdmin, +) +from src.tgbot.keyboards.admin.inline.mailing import ( + add_buttons_keyboard, + confirm_with_button_keyboard, +) @dp.message_handler(IsAdmin(), content_types=["text"], state="broadcast_get_content") diff --git a/django_project/telegrambot/common/migrations/__init__.py b/deprecated/handlers/admins/advert/ref/__init__.py similarity index 100% rename from django_project/telegrambot/common/migrations/__init__.py rename to deprecated/handlers/admins/advert/ref/__init__.py diff --git a/django_project/telegrambot/telegrambot/__init__.py b/deprecated/handlers/admins/advert/requiredsub/__init__.py similarity index 100% rename from django_project/telegrambot/telegrambot/__init__.py rename to deprecated/handlers/admins/advert/requiredsub/__init__.py diff --git a/handlers/admins/customers/__init__.py b/deprecated/handlers/admins/customers/__init__.py similarity index 100% rename from handlers/admins/customers/__init__.py rename to deprecated/handlers/admins/customers/__init__.py diff --git a/handlers/admins/customers/users.py b/deprecated/handlers/admins/customers/users.py similarity index 92% rename from handlers/admins/customers/users.py rename to deprecated/handlers/admins/customers/users.py index dd97404..8a9ebc8 100644 --- a/handlers/admins/customers/users.py +++ b/deprecated/handlers/admins/customers/users.py @@ -5,24 +5,24 @@ CallbackQuery, Message, ) +from loader import ( + dp, +) -from filters.IsAdminFilter import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from keyboards.admin.inline.customers import ( +from src.tgbot.keyboards.admin.inline.customers import ( manipulation_callback, user_blocking_keyboard, user_manipulation, ) -from keyboards.admin.inline.reply_menu import ( +from src.tgbot.keyboards.admin.inline.reply_menu import ( admin_cancel_keyboard, ) -from loader import ( - dp, -) -from utils.db_api import ( - db_commands, -) @dp.message_handler(IsAdmin(), commands="users", state="*") diff --git a/handlers/admins/monitoring.py b/deprecated/handlers/admins/monitoring.py similarity index 84% rename from handlers/admins/monitoring.py rename to deprecated/handlers/admins/monitoring.py index 3f874bb..2548c12 100644 --- a/handlers/admins/monitoring.py +++ b/deprecated/handlers/admins/monitoring.py @@ -1,25 +1,25 @@ from aiogram import ( types, ) - -from filters.IsAdminFilter import ( - IsAdmin, +from loader import ( + _, + dp, ) -from functions.dating.create_forms_funcs import ( + +from deprecated.create_forms_funcs import ( monitoring_questionnaire, ) -from keyboards.inline.admin_inline import ( - start_monitoring_keyboard, +from src.infrastructure.db_api import ( + db_commands, ) -from keyboards.inline.questionnaires_inline import ( - action_keyboard_monitoring, +from src.tgbot.filters.is_admin_filter import ( + IsAdmin, ) -from loader import ( - _, - dp, +from src.tgbot.keyboards.inline.admin_inline import ( + start_monitoring_keyboard, ) -from utils.db_api import ( - db_commands, +from src.tgbot.keyboards.inline.questionnaires_inline import ( + action_keyboard_monitoring, ) diff --git a/handlers/admins/settings/__init__.py b/deprecated/handlers/admins/settings/__init__.py similarity index 100% rename from handlers/admins/settings/__init__.py rename to deprecated/handlers/admins/settings/__init__.py diff --git a/handlers/admins/settings/admins.py b/deprecated/handlers/admins/settings/admins.py similarity index 92% rename from handlers/admins/settings/admins.py rename to deprecated/handlers/admins/settings/admins.py index 9b1ef49..e4d8662 100644 --- a/handlers/admins/settings/admins.py +++ b/deprecated/handlers/admins/settings/admins.py @@ -5,28 +5,28 @@ CallbackQuery, Message, ) +from loader import ( + dp, +) -from data.config import ( +from src.tgbot.config import ( change_env, load_config, ) -from filters.IsAdminFilter import ( +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from keyboards.admin.inline.reply_menu import ( +from src.tgbot.keyboards.admin.inline.reply_menu import ( admin_cancel_keyboard, settings_keyboard, ) -from keyboards.admin.inline.setting import ( +from src.tgbot.keyboards.admin.inline.setting import ( add_admins_keyboard, ) -from loader import ( - dp, -) -from states.admins import ( +from src.tgbot.misc.states import ( AdminsActions, ) -from utils.set_bot_commands import ( +from src.tgbot.services.app.set_bot_commands import ( set_default_commands, ) diff --git a/handlers/admins/settings/logs_user.py b/deprecated/handlers/admins/settings/logs_user.py similarity index 86% rename from handlers/admins/settings/logs_user.py rename to deprecated/handlers/admins/settings/logs_user.py index ae9d525..4cea0a9 100644 --- a/handlers/admins/settings/logs_user.py +++ b/deprecated/handlers/admins/settings/logs_user.py @@ -6,23 +6,23 @@ InputFile, Message, ) - -from filters.IsAdminFilter import ( - IsAdmin, +from loader import ( + dp, ) -from functions.main_app.auxiliary_tools import ( + +from deprecated.data_operations import ( backup_configs, dump_users_to_file, ) -from handlers.users.back import ( +from src.tgbot.filters.is_admin_filter import ( + IsAdmin, +) +from src.tgbot.handlers.users.back import ( delete_message, ) -from keyboards.admin.inline.reply_menu import ( +from src.tgbot.keyboards.admin.inline.reply_menu import ( logs_keyboard, ) -from loader import ( - dp, -) @dp.message_handler(IsAdmin(), commands="logs", state="*") diff --git a/handlers/admins/settings/setting.py b/deprecated/handlers/admins/settings/setting.py similarity index 79% rename from handlers/admins/settings/setting.py rename to deprecated/handlers/admins/settings/setting.py index c923d43..7309d59 100644 --- a/handlers/admins/settings/setting.py +++ b/deprecated/handlers/admins/settings/setting.py @@ -1,16 +1,16 @@ from aiogram.types import ( Message, ) +from loader import ( + dp, +) -from filters.IsAdminFilter import ( +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from keyboards.admin.inline.reply_menu import ( +from src.tgbot.keyboards.admin.inline.reply_menu import ( settings_keyboard, ) -from loader import ( - dp, -) @dp.message_handler(IsAdmin(), commands="settings", state="*") diff --git a/handlers/admins/settings/tech_works.py b/deprecated/handlers/admins/settings/tech_works.py similarity index 87% rename from handlers/admins/settings/tech_works.py rename to deprecated/handlers/admins/settings/tech_works.py index 1b08562..f826203 100644 --- a/handlers/admins/settings/tech_works.py +++ b/deprecated/handlers/admins/settings/tech_works.py @@ -5,25 +5,25 @@ CallbackQuery, Message, ) - -from filters.IsAdminFilter import ( - IsAdmin, -) -from keyboards.admin.main_menu import ( - admin_keyboard, -) -from keyboards.inline.admin_inline import ( - tech_works_keyboard, -) from loader import ( _, dp, ) -from utils.db_api import ( + +from deprecated.statistics import ( + get_statistics, +) +from src.infrastructure.db_api import ( db_commands, ) -from utils.statistics import ( - get_statistics, +from src.tgbot.filters.is_admin_filter import ( + IsAdmin, +) +from src.tgbot.keyboards.admin.main_menu import ( + admin_keyboard, +) +from src.tgbot.keyboards.inline.admin_inline import ( + tech_works_keyboard, ) diff --git a/handlers/echo_handler.py b/deprecated/handlers/echo_handler.py similarity index 95% rename from handlers/echo_handler.py rename to deprecated/handlers/echo_handler.py index 2e21b4a..4c8f3c4 100644 --- a/handlers/echo_handler.py +++ b/deprecated/handlers/echo_handler.py @@ -10,16 +10,16 @@ from aiogram.utils.markdown import ( hcode, ) - -from keyboards.inline.main_menu_inline import ( - start_keyboard, -) from loader import ( _, dp, logger, ) +from src.tgbot.keyboards.inline.main_menu_inline import ( + start_keyboard, +) + @dp.message_handler(state=None) async def bot_echo(message: types.Message) -> None: diff --git a/handlers/errors/__init__.py b/deprecated/handlers/errors/__init__.py similarity index 100% rename from handlers/errors/__init__.py rename to deprecated/handlers/errors/__init__.py diff --git a/handlers/errors/error_handler.py b/deprecated/handlers/errors/error_handler.py similarity index 99% rename from handlers/errors/error_handler.py rename to deprecated/handlers/errors/error_handler.py index 91b0c6c..3ade325 100644 --- a/handlers/errors/error_handler.py +++ b/deprecated/handlers/errors/error_handler.py @@ -10,7 +10,6 @@ TelegramAPIError, Unauthorized, ) - from loader import ( dp, ) diff --git a/handlers/groups/__init__.py b/deprecated/handlers/groups/__init__.py similarity index 100% rename from handlers/groups/__init__.py rename to deprecated/handlers/groups/__init__.py diff --git a/handlers/groups/event_moderate.py b/deprecated/handlers/groups/event_moderate.py similarity index 87% rename from handlers/groups/event_moderate.py rename to deprecated/handlers/groups/event_moderate.py index d9fff25..3d4df52 100644 --- a/handlers/groups/event_moderate.py +++ b/deprecated/handlers/groups/event_moderate.py @@ -3,27 +3,27 @@ from aiogram.types import ( CallbackQuery, ) +from loader import ( + _, + bot, + dp, +) -from data.config import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.config import ( load_config, ) -from filters.IsAdminFilter import ( +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from keyboards.inline.main_menu_inline import ( +from src.tgbot.keyboards.inline.main_menu_inline import ( start_keyboard, ) -from keyboards.inline.poster_inline import ( +from src.tgbot.keyboards.inline.poster_inline import ( poster_keyboard, ) -from loader import ( - _, - bot, - dp, -) -from utils.db_api import ( - db_commands, -) # FIXME: Broken handler diff --git a/handlers/groups/start.py b/deprecated/handlers/groups/start.py similarity index 83% rename from handlers/groups/start.py rename to deprecated/handlers/groups/start.py index 3970545..32acd9b 100644 --- a/handlers/groups/start.py +++ b/deprecated/handlers/groups/start.py @@ -4,17 +4,17 @@ from aiogram.types import ( Message, ) +from loader import ( + _, + dp, +) -from filters.FiltersChat import ( +from src.tgbot.filters.filters_chat import ( IsGroup, ) -from filters.IsAdminFilter import ( +from src.tgbot.filters.is_admin_filter import ( IsAdmin, ) -from loader import ( - _, - dp, -) @dp.message_handler(IsGroup(), IsAdmin(), Command("start")) diff --git a/handlers/users/__init__.py b/deprecated/handlers/users/__init__.py similarity index 100% rename from handlers/users/__init__.py rename to deprecated/handlers/users/__init__.py diff --git a/handlers/users/back.py b/deprecated/handlers/users/back.py similarity index 91% rename from handlers/users/back.py rename to deprecated/handlers/users/back.py index 0f0e79e..71cac31 100644 --- a/handlers/users/back.py +++ b/deprecated/handlers/users/back.py @@ -9,33 +9,33 @@ from aiogram.types import ( CallbackQuery, ) +from loader import ( + _, + dp, +) -from functions.main_app.auxiliary_tools import ( +from deprecated.inline.filters_inline import ( + filters_keyboard, +) +from deprecated.message_operations import ( delete_message, display_profile, information_menu, registration_menu, ) -from handlers.users.event import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.handlers.users.event import ( view_meetings_handler, view_own_event, ) -from keyboards.inline.admin_inline import ( +from src.tgbot.keyboards.inline.admin_inline import ( unban_user_keyboard, ) -from keyboards.inline.filters_inline import ( - filters_keyboard, -) -from keyboards.inline.menu_profile_inline import ( +from src.tgbot.keyboards.inline.menu_profile_inline import ( get_profile_keyboard, ) -from loader import ( - _, - dp, -) -from utils.db_api import ( - db_commands, -) class Command(ABC): diff --git a/handlers/users/brandbook.py b/deprecated/handlers/users/brandbook.py similarity index 89% rename from handlers/users/brandbook.py rename to deprecated/handlers/users/brandbook.py index c4d1a74..8a7ee20 100644 --- a/handlers/users/brandbook.py +++ b/deprecated/handlers/users/brandbook.py @@ -1,22 +1,22 @@ from aiogram.types import ( CallbackQuery, ) +from loader import ( + _, + dp, +) -from functions.main_app.auxiliary_tools import ( +from deprecated.message_operations import ( handle_guide_callback, information_menu, send_photo_with_caption, ) -from keyboards.inline.back_inline import ( +from src.tgbot.keyboards.inline.back_inline import ( only_back_keyboard, ) -from keyboards.inline.guide_inline import ( +from src.tgbot.keyboards.inline.guide_inline import ( guide_callback, ) -from loader import ( - _, - dp, -) @dp.callback_query_handler(text="information") diff --git a/handlers/users/buy_unban.py b/deprecated/handlers/users/buy_unban.py similarity index 88% rename from handlers/users/buy_unban.py rename to deprecated/handlers/users/buy_unban.py index fd3791d..9c0f6ec 100644 --- a/handlers/users/buy_unban.py +++ b/deprecated/handlers/users/buy_unban.py @@ -6,27 +6,27 @@ from aiogram.types import ( CallbackQuery, ) - -from data.config import ( - load_config, -) -from keyboards.inline.main_menu_inline import ( - start_keyboard, -) -from keyboards.inline.payments_inline import ( - payment_menu_keyboard, - yoomoney_keyboard, -) from loader import ( _, dp, wallet, ) -from utils.db_api import ( + +from src.infrastructure.Yoomoney.types import ( + PaymentSource, +) +from src.infrastructure.db_api import ( db_commands, ) -from utils.yoomoney.types import ( - PaymentSource, +from src.tgbot.config import ( + load_config, +) +from src.tgbot.keyboards.inline.main_menu_inline import ( + start_keyboard, +) +from src.tgbot.keyboards.inline.payments_inline import ( + payment_menu_keyboard, + yoomoney_keyboard, ) @@ -44,7 +44,7 @@ async def get_payment_menu(call: CallbackQuery) -> None: ) -@dp.callback_query_handler(text="yoomoney") +@dp.callback_query_handler(text="Yoomoney") async def get_payment(call: CallbackQuery, state: FSMContext) -> None: payment_form = await wallet.create_payment_form( amount_rub=2, @@ -64,7 +64,7 @@ async def get_payment(call: CallbackQuery, state: FSMContext) -> None: ) -@dp.callback_query_handler(text="yoomoney:check_payment", state="payment") +@dp.callback_query_handler(text="Yoomoney:check_payment", state="payment") async def check_payment(call: CallbackQuery, state: FSMContext) -> None: data = await state.get_data() payment_is_completed: bool = await wallet.check_payment_on_successful( diff --git a/handlers/users/change_datas.py b/deprecated/handlers/users/change_datas.py similarity index 95% rename from handlers/users/change_datas.py rename to deprecated/handlers/users/change_datas.py index a0a1818..2404598 100644 --- a/handlers/users/change_datas.py +++ b/deprecated/handlers/users/change_datas.py @@ -18,49 +18,49 @@ from django.db import ( DataError, ) +from loader import ( + _, + dp, + logger, +) -from functions.main_app.auxiliary_tools import ( +from deprecated.determin_location import ( + Location, + RegistrationStrategy, +) +from deprecated.photo_operations import ( saving_censored_photo, update_normal_photo, ) -from functions.main_app.determin_location import ( - Location, - RegistrationStrategy, +from src.infrastructure.NudeNet.predictor import ( + classification_image, + generate_censored_image, +) +from src.infrastructure.NudeNet.profanity_filter import ( + censored_message, +) +from src.infrastructure.YandexMap.exceptions import ( + NothingFound, ) -from handlers.users.back import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.handlers.users.back import ( delete_message, ) -from keyboards.default.get_photo import ( +from src.tgbot.keyboards.default.get_photo import ( get_photo_from_profile, ) -from keyboards.inline.change_data_profile_inline import ( +from src.tgbot.keyboards.inline.change_data_profile_inline import ( change_info_keyboard, gender_keyboard, ) -from keyboards.inline.main_menu_inline import ( +from src.tgbot.keyboards.inline.main_menu_inline import ( start_keyboard, ) -from loader import ( - _, - dp, - logger, -) -from states.new_data_state import ( +from src.tgbot.misc.states import ( NewData, ) -from utils.NudeNet.predictor import ( - classification_image, - generate_censored_image, -) -from utils.YandexMap.exceptions import ( - NothingFound, -) -from utils.db_api import ( - db_commands, -) -from utils.misc.profanityFilter import ( - censored_message, -) @dp.callback_query_handler(text="change_profile") diff --git a/handlers/users/change_event_datas.py b/deprecated/handlers/users/change_event_datas.py similarity index 93% rename from handlers/users/change_event_datas.py rename to deprecated/handlers/users/change_event_datas.py index 6a4a166..6413415 100644 --- a/handlers/users/change_event_datas.py +++ b/deprecated/handlers/users/change_event_datas.py @@ -7,20 +7,20 @@ CallbackQuery, Message, ) - -from handlers.users.back import ( - delete_message, -) -from keyboards.inline.poster_inline import ( - change_datas_keyboard, -) from loader import ( _, dp, ) -from utils.db_api import ( + +from src.infrastructure.db_api import ( db_commands, ) +from src.tgbot.handlers.users.back import ( + delete_message, +) +from src.tgbot.keyboards.inline.poster_inline import ( + change_datas_keyboard, +) @dp.callback_query_handler(text="change_event_data") diff --git a/handlers/users/event.py b/deprecated/handlers/users/event.py similarity index 96% rename from handlers/users/event.py rename to deprecated/handlers/users/event.py index df7d155..5c62ecd 100644 --- a/handlers/users/event.py +++ b/deprecated/handlers/users/event.py @@ -19,41 +19,41 @@ from django.db import ( DataError, ) +from loader import ( + _, + bot, + dp, + logger, +) -from data.config import ( - load_config, +from deprecated.determin_location import ( + EventStrategy, + Location, ) -from functions.event.extra_features import ( +from deprecated.extra_features import ( check_event_date, ) -from functions.event.templates_messages import ( +from deprecated.templates_messages import ( ME, ) -from functions.main_app.determin_location import ( - EventStrategy, - Location, +from src.infrastructure.YandexMap.exceptions import ( + NothingFound, +) +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.config import ( + load_config, ) -from keyboards.inline.calendar import ( +from src.tgbot.keyboards.inline.calendar import ( SimpleCalendar, calendar_callback, search_cb, ) -from keyboards.inline.poster_inline import ( +from src.tgbot.keyboards.inline.poster_inline import ( cancel_registration_keyboard, poster_keyboard, ) -from loader import ( - _, - bot, - dp, - logger, -) -from utils.YandexMap.exceptions import ( - NothingFound, -) -from utils.db_api import ( - db_commands, -) @dp.callback_query_handler(text="meetings") diff --git a/handlers/users/event_list.py b/deprecated/handlers/users/event_list.py similarity index 93% rename from handlers/users/event_list.py rename to deprecated/handlers/users/event_list.py index 2b2e63d..510aaa6 100644 --- a/handlers/users/event_list.py +++ b/deprecated/handlers/users/event_list.py @@ -6,16 +6,16 @@ from aiogram.types import ( CallbackQuery, ) - -from functions.event.extra_features import ( - create_form, - get_next_registration, -) from loader import ( _, dp, ) -from utils.db_api import ( + +from deprecated.extra_features import ( + create_form, + get_next_registration, +) +from src.infrastructure.db_api import ( db_commands, ) diff --git a/handlers/users/filters.py b/deprecated/handlers/users/filters.py similarity index 93% rename from handlers/users/filters.py rename to deprecated/handlers/users/filters.py index 6767bd7..86ca136 100644 --- a/handlers/users/filters.py +++ b/deprecated/handlers/users/filters.py @@ -13,35 +13,35 @@ from aiogram.utils.exceptions import ( BadRequest, ) - -from functions.main_app.auxiliary_tools import ( - choice_gender, - show_dating_filters, +from loader import ( + _, + dp, ) -from functions.main_app.determin_location import ( + +from deprecated.determin_location import ( FiltersStrategy, Location, ) -from handlers.users.back import ( - delete_message, -) -from keyboards.inline.change_data_profile_inline import ( - gender_keyboard, -) -from keyboards.inline.filters_inline import ( +from deprecated.inline.filters_inline import ( event_filters_keyboard, filters_keyboard, ) -from loader import ( - _, - dp, +from deprecated.message_operations import ( + choice_gender, + show_dating_filters, ) -from utils.YandexMap.exceptions import ( +from src.infrastructure.YandexMap.exceptions import ( NothingFound, ) -from utils.db_api import ( +from src.infrastructure.db_api import ( db_commands, ) +from src.tgbot.handlers.users.back import ( + delete_message, +) +from src.tgbot.keyboards.inline.change_data_profile_inline import ( + gender_keyboard, +) @dp.callback_query_handler(text="filters") diff --git a/handlers/users/registration.py b/deprecated/handlers/users/registration.py similarity index 93% rename from handlers/users/registration.py rename to deprecated/handlers/users/registration.py index 71b879c..1f46b6e 100644 --- a/handlers/users/registration.py +++ b/deprecated/handlers/users/registration.py @@ -22,53 +22,55 @@ from django.db import ( DataError, ) +from loader import ( + _, + client, + dp, + logger, +) -from functions.main_app.auxiliary_tools import ( +from deprecated.determin_location import ( + Location, + RegistrationStrategy, +) +from deprecated.message_operations import ( choice_gender, +) +from deprecated.photo_operations import ( saving_censored_photo, saving_normal_photo, ) -from functions.main_app.determin_location import ( - Location, - RegistrationStrategy, +from src.infrastructure.NudeNet.predictor import ( + classification_image, + generate_censored_image, +) +from src.infrastructure.NudeNet.profanity_filter import ( + censored_message, +) +from src.infrastructure.YandexMap.exceptions import ( + NothingFound, ) -from keyboards.default.get_location_default import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.keyboards.default.get_location_default import ( location_keyboard, ) -from keyboards.default.get_photo import ( +from src.tgbot.keyboards.default.get_photo import ( get_photo_from_profile, ) -from keyboards.inline.cancel_inline import ( +from src.tgbot.keyboards.inline.cancel_inline import ( cancel_registration_keyboard, ) -from keyboards.inline.change_data_profile_inline import ( +from src.tgbot.keyboards.inline.change_data_profile_inline import ( gender_keyboard, ) -from keyboards.inline.registration_inline import ( +from src.tgbot.keyboards.inline.registration_inline import ( second_registration_keyboard, ) -from loader import ( - _, - client, - dp, - logger, -) -from states.reg_state import ( +from src.tgbot.misc.states import ( RegData, ) -from utils.NudeNet.predictor import ( - classification_image, - generate_censored_image, -) -from utils.YandexMap.exceptions import ( - NothingFound, -) -from utils.db_api import ( - db_commands, -) -from utils.misc.profanityFilter import ( - censored_message, -) @dp.callback_query_handler(text="registration") diff --git a/handlers/users/start.py b/deprecated/handlers/users/start.py similarity index 94% rename from handlers/users/start.py rename to deprecated/handlers/users/start.py index 304245f..e7a6452 100644 --- a/handlers/users/start.py +++ b/deprecated/handlers/users/start.py @@ -11,24 +11,24 @@ from aiogram.utils.exceptions import ( BadRequest, ) - -from filters import ( - IsPrivate, +from loader import ( + _, + dp, ) -from functions.main_app.auxiliary_tools import ( + +from deprecated.message_operations import ( check_user_in_db, delete_message, registration_menu, ) -from keyboards.inline.language_inline import ( - language_keyboard, +from src.infrastructure.db_api import ( + db_commands, ) -from loader import ( - _, - dp, +from src.tgbot.filters import ( + IsPrivate, ) -from utils.db_api import ( - db_commands, +from src.tgbot.keyboards.inline.language_inline import ( + language_keyboard, ) diff --git a/handlers/users/support.py b/deprecated/handlers/users/support.py similarity index 96% rename from handlers/users/support.py rename to deprecated/handlers/users/support.py index 71a748a..8269b0f 100644 --- a/handlers/users/support.py +++ b/deprecated/handlers/users/support.py @@ -7,14 +7,19 @@ from aiogram.utils.exceptions import ( BadRequest, ) +from loader import ( + _, + bot, + dp, +) -from handlers.users.back import ( +from src.tgbot.handlers.users.back import ( delete_message, ) -from keyboards.inline.main_menu_inline import ( +from src.tgbot.keyboards.inline.main_menu_inline import ( start_keyboard, ) -from keyboards.inline.support_inline import ( +from src.tgbot.keyboards.inline.support_inline import ( cancel_support, cancel_support_callback, check_support_available, @@ -22,11 +27,6 @@ support_callback, support_keyboard, ) -from loader import ( - _, - bot, - dp, -) @dp.callback_query_handler(text="support") diff --git a/handlers/users/user_profile.py b/deprecated/handlers/users/user_profile.py similarity index 82% rename from handlers/users/user_profile.py rename to deprecated/handlers/users/user_profile.py index a9c5e37..2cdb9f2 100644 --- a/handlers/users/user_profile.py +++ b/deprecated/handlers/users/user_profile.py @@ -1,23 +1,23 @@ from aiogram.types import ( CallbackQuery, ) +from loader import ( + _, + dp, +) -from functions.main_app.auxiliary_tools import ( +from deprecated.message_operations import ( display_profile, ) -from handlers.users.back import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.handlers.users.back import ( delete_message, ) -from keyboards.inline.menu_profile_inline import ( +from src.tgbot.keyboards.inline.menu_profile_inline import ( get_profile_keyboard, ) -from loader import ( - _, - dp, -) -from utils.db_api import ( - db_commands, -) @dp.callback_query_handler(text="my_profile") diff --git a/handlers/users/verification.py b/deprecated/handlers/users/verification.py similarity index 90% rename from handlers/users/verification.py rename to deprecated/handlers/users/verification.py index 710f34a..8cd68d3 100644 --- a/handlers/users/verification.py +++ b/deprecated/handlers/users/verification.py @@ -7,23 +7,23 @@ CallbackQuery, ReplyKeyboardRemove, ) +from loader import ( + _, + dp, +) -from handlers.users.back import ( +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.handlers.users.back import ( delete_message, ) -from keyboards.default.get_contact_default import ( +from src.tgbot.keyboards.default.get_contact_default import ( contact_keyboard, ) -from keyboards.inline.main_menu_inline import ( +from src.tgbot.keyboards.inline.main_menu_inline import ( start_keyboard, ) -from loader import ( - _, - dp, -) -from utils.db_api import ( - db_commands, -) @dp.callback_query_handler(text="verification") diff --git a/handlers/users/view_event.py b/deprecated/handlers/users/view_event.py similarity index 95% rename from handlers/users/view_event.py rename to deprecated/handlers/users/view_event.py index 26abfe3..a6d9719 100644 --- a/handlers/users/view_event.py +++ b/deprecated/handlers/users/view_event.py @@ -4,21 +4,21 @@ from aiogram.types import ( CallbackQuery, ) +from loader import ( + _, + bot, + dp, +) -from functions.event.extra_features import ( +from deprecated.extra_features import ( add_events_to_user, check_event_date, create_form, get_next_random_event_id, ) -from keyboards.inline.poster_inline import ( +from src.tgbot.keyboards.inline.poster_inline import ( poster_keyboard, ) -from loader import ( - _, - bot, - dp, -) @dp.callback_query_handler(text="view_poster") diff --git a/handlers/users/view_ques.py b/deprecated/handlers/users/view_ques.py similarity index 94% rename from handlers/users/view_ques.py rename to deprecated/handlers/users/view_ques.py index d138038..5718036 100644 --- a/handlers/users/view_ques.py +++ b/deprecated/handlers/users/view_ques.py @@ -7,11 +7,31 @@ from django.db import ( IntegrityError, ) +from loader import ( + _, + bot, + dp, + logger, +) -from data.config import ( +from deprecated.get_next_user_func import ( + get_next_user, +) +from deprecated.message_operations import ( + delete_message, +) +from src.infrastructure.db_api import ( + db_commands, +) +from src.tgbot.config import ( load_config, ) -from functions.dating import ( +from src.tgbot.keyboards.inline.questionnaires_inline import ( + action_keyboard, + action_reciprocity_keyboard, + action_report_keyboard, +) +from src.tgbot.services.dating import ( ChooseReportReason, DislikeAction, DislikeReciprocity, @@ -24,26 +44,6 @@ StartFindingSuccess, StoppedAction, ) -from functions.dating.get_next_user_func import ( - get_next_user, -) -from functions.main_app.auxiliary_tools import ( - delete_message, -) -from keyboards.inline.questionnaires_inline import ( - action_keyboard, - action_reciprocity_keyboard, - action_report_keyboard, -) -from loader import ( - _, - bot, - dp, - logger, -) -from utils.db_api import ( - db_commands, -) @dp.callback_query_handler(text="find_ques") diff --git a/django_project/telegrambot/usersmanage/__init__.py b/deprecated/inline/__init__.py similarity index 100% rename from django_project/telegrambot/usersmanage/__init__.py rename to deprecated/inline/__init__.py diff --git a/keyboards/inline/admin_inline.py b/deprecated/inline/admin_inline.py similarity index 99% rename from keyboards/inline/admin_inline.py rename to deprecated/inline/admin_inline.py index 4385d54..d37fdde 100644 --- a/keyboards/inline/admin_inline.py +++ b/deprecated/inline/admin_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/back_inline.py b/deprecated/inline/back_inline.py similarity index 99% rename from keyboards/inline/back_inline.py rename to deprecated/inline/back_inline.py index 1441c4e..f8410fb 100644 --- a/keyboards/inline/back_inline.py +++ b/deprecated/inline/back_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/calendar.py b/deprecated/inline/calendar.py similarity index 100% rename from keyboards/inline/calendar.py rename to deprecated/inline/calendar.py diff --git a/keyboards/inline/cancel_inline.py b/deprecated/inline/cancel_inline.py similarity index 99% rename from keyboards/inline/cancel_inline.py rename to deprecated/inline/cancel_inline.py index 98f4d83..9ab0001 100644 --- a/keyboards/inline/cancel_inline.py +++ b/deprecated/inline/cancel_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/change_data_profile_inline.py b/deprecated/inline/change_data_profile_inline.py similarity index 99% rename from keyboards/inline/change_data_profile_inline.py rename to deprecated/inline/change_data_profile_inline.py index edaf9af..7c4d637 100644 --- a/keyboards/inline/change_data_profile_inline.py +++ b/deprecated/inline/change_data_profile_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/filters_inline.py b/deprecated/inline/filters_inline.py similarity index 99% rename from keyboards/inline/filters_inline.py rename to deprecated/inline/filters_inline.py index fb23064..4769e3f 100644 --- a/keyboards/inline/filters_inline.py +++ b/deprecated/inline/filters_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/guide_inline.py b/deprecated/inline/guide_inline.py similarity index 99% rename from keyboards/inline/guide_inline.py rename to deprecated/inline/guide_inline.py index 9c5c167..8b84e34 100644 --- a/keyboards/inline/guide_inline.py +++ b/deprecated/inline/guide_inline.py @@ -5,7 +5,6 @@ from aiogram.utils.callback_data import ( CallbackData, ) - from loader import ( _, ) diff --git a/keyboards/inline/language_inline.py b/deprecated/inline/language_inline.py similarity index 99% rename from keyboards/inline/language_inline.py rename to deprecated/inline/language_inline.py index ceb6b77..35450d2 100644 --- a/keyboards/inline/language_inline.py +++ b/deprecated/inline/language_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/main_menu_inline.py b/deprecated/inline/main_menu_inline.py similarity index 93% rename from keyboards/inline/main_menu_inline.py rename to deprecated/inline/main_menu_inline.py index 195b89c..5429669 100644 --- a/keyboards/inline/main_menu_inline.py +++ b/deprecated/inline/main_menu_inline.py @@ -1,27 +1,23 @@ -from typing import ( - Union, -) - from aiogram.types import ( CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, ) - -from data.config import ( - load_config, -) from loader import ( _, ) -from utils.db_api import ( + +from src.infrastructure.db_api import ( db_commands, ) +from src.tgbot.config import ( + load_config, +) async def start_keyboard( - obj: Union[CallbackQuery, Message, int] + obj: CallbackQuery | Message | int ) -> InlineKeyboardMarkup: markup = InlineKeyboardMarkup(row_width=2) try: diff --git a/keyboards/inline/menu_profile_inline.py b/deprecated/inline/menu_profile_inline.py similarity index 99% rename from keyboards/inline/menu_profile_inline.py rename to deprecated/inline/menu_profile_inline.py index f4bdf2e..f07067c 100644 --- a/keyboards/inline/menu_profile_inline.py +++ b/deprecated/inline/menu_profile_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/necessary_links_inline.py b/deprecated/inline/necessary_links_inline.py similarity index 100% rename from keyboards/inline/necessary_links_inline.py rename to deprecated/inline/necessary_links_inline.py diff --git a/keyboards/inline/payments_inline.py b/deprecated/inline/payments_inline.py similarity index 93% rename from keyboards/inline/payments_inline.py rename to deprecated/inline/payments_inline.py index f8fd51e..3a6b74d 100644 --- a/keyboards/inline/payments_inline.py +++ b/deprecated/inline/payments_inline.py @@ -2,18 +2,17 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) -from yarl import ( - URL, -) - from loader import ( _, ) +from yarl import ( + URL, +) async def payment_menu_keyboard() -> InlineKeyboardMarkup: markup = InlineKeyboardMarkup() - yoomoney = InlineKeyboardButton(text=_("💳 ЮMoney"), callback_data="yoomoney") + yoomoney = InlineKeyboardButton(text=_("💳 ЮMoney"), callback_data="Yoomoney") markup.add(yoomoney) return markup @@ -22,7 +21,7 @@ async def yoomoney_keyboard(url: str | URL = None) -> InlineKeyboardMarkup: markup = InlineKeyboardMarkup(row_width=1) pay_yoomoney = InlineKeyboardButton(text=_("💳 Оплатить"), url=url) check_prices = InlineKeyboardButton( - text=_("🔄 Проверить оплату"), callback_data="yoomoney:check_payment" + text=_("🔄 Проверить оплату"), callback_data="Yoomoney:check_payment" ) markup.add(pay_yoomoney, check_prices) return markup diff --git a/keyboards/inline/poster_inline.py b/deprecated/inline/poster_inline.py similarity index 96% rename from keyboards/inline/poster_inline.py rename to deprecated/inline/poster_inline.py index be79b32..56954a5 100644 --- a/keyboards/inline/poster_inline.py +++ b/deprecated/inline/poster_inline.py @@ -1,23 +1,19 @@ -from typing import ( - Union, -) - from aiogram.types import ( CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message, ) - from loader import ( _, ) -from utils.db_api import ( + +from src.infrastructure.db_api import ( db_commands, ) -async def poster_keyboard(obj: Union[Message, CallbackQuery]) -> InlineKeyboardMarkup: +async def poster_keyboard(obj: Message | CallbackQuery) -> InlineKeyboardMarkup: user = await db_commands.select_user_meetings(telegram_id=obj.from_user.id) is_admin = user.is_admin is_verification = user.verification_status diff --git a/keyboards/inline/questionnaires_inline.py b/deprecated/inline/questionnaires_inline.py similarity index 99% rename from keyboards/inline/questionnaires_inline.py rename to deprecated/inline/questionnaires_inline.py index e224c3b..3358d59 100644 --- a/keyboards/inline/questionnaires_inline.py +++ b/deprecated/inline/questionnaires_inline.py @@ -5,7 +5,6 @@ from aiogram.utils.callback_data import ( CallbackData, ) - from loader import ( _, ) diff --git a/keyboards/inline/registration_inline.py b/deprecated/inline/registration_inline.py similarity index 99% rename from keyboards/inline/registration_inline.py rename to deprecated/inline/registration_inline.py index a7c3a2a..32a6d53 100644 --- a/keyboards/inline/registration_inline.py +++ b/deprecated/inline/registration_inline.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/settings_menu.py b/deprecated/inline/settings_menu.py similarity index 99% rename from keyboards/inline/settings_menu.py rename to deprecated/inline/settings_menu.py index ad4fb86..6c5cba5 100644 --- a/keyboards/inline/settings_menu.py +++ b/deprecated/inline/settings_menu.py @@ -2,7 +2,6 @@ InlineKeyboardButton, InlineKeyboardMarkup, ) - from loader import ( _, ) diff --git a/keyboards/inline/support_inline.py b/deprecated/inline/support_inline.py similarity index 88% rename from keyboards/inline/support_inline.py rename to deprecated/inline/support_inline.py index 88efaf5..ba97abe 100644 --- a/keyboards/inline/support_inline.py +++ b/deprecated/inline/support_inline.py @@ -1,8 +1,4 @@ import random -from typing import ( - Optional, - Union, -) from aiogram.types import ( InlineKeyboardButton, @@ -11,20 +7,20 @@ from aiogram.utils.callback_data import ( CallbackData, ) - -from data.config import ( - load_config, -) from loader import ( _, dp, ) +from src.tgbot.config import ( + load_config, +) + support_callback = CallbackData("ask_support", "messages", "user_id", "as_user") cancel_support_callback = CallbackData("cancel_support", "user_id") -async def check_support_available(support_id) -> Optional[int]: +async def check_support_available(support_id) -> int | None: state = dp.current_state(chat=support_id, user=support_id) state_str = str(await state.get_state()) if state_str == "in_support": @@ -33,7 +29,7 @@ async def check_support_available(support_id) -> Optional[int]: return support_id -async def get_support_manager() -> Optional[int]: +async def get_support_manager() -> int | None: random.shuffle(load_config().tg_bot.support_ids) for support_id in load_config().tg_bot.support_ids: support_id = await check_support_available(support_id) @@ -43,7 +39,7 @@ async def get_support_manager() -> Optional[int]: return -async def support_keyboard(messages, user_id=None) -> Union[bool, InlineKeyboardMarkup]: +async def support_keyboard(messages, user_id=None) -> bool | InlineKeyboardMarkup: if user_id: contact_id = int(user_id) as_user = "no" diff --git a/functions/main_app/language_ware.py b/deprecated/language_ware.py similarity index 67% rename from functions/main_app/language_ware.py rename to deprecated/language_ware.py index bffa931..7156380 100644 --- a/functions/main_app/language_ware.py +++ b/deprecated/language_ware.py @@ -1,32 +1,27 @@ from typing import ( Any, - Optional, - Tuple, ) from aiogram import ( types, ) -from aiogram.contrib.middlewares.i18n import ( +from aiogram.utils.i18n import ( I18nMiddleware, ) -from data.config import ( +from src.tgbot.config import ( LOCALES_DIR, load_config, ) -from utils.db_api import ( - db_commands, -) -async def get_lang(user_id) -> Optional[str]: +async def get_lang(user_id, db_commands=None) -> str | None: user = await db_commands.select_user(telegram_id=user_id) return user.language if user else None class ACLMiddleware(I18nMiddleware): - async def get_user_locale(self, action: str, args: Tuple[Any]) -> Optional[str]: + async def get_user_locale(self, action: str, args: tuple[Any]) -> str | None: user_id = types.User.get_current().id return await get_lang(user_id) or (await super().get_user_locale(action, args)) diff --git a/deprecated/message_operations.py b/deprecated/message_operations.py new file mode 100644 index 0000000..7eda773 --- /dev/null +++ b/deprecated/message_operations.py @@ -0,0 +1,263 @@ +# from contextlib import ( +# suppress, +# ) +# import datetime +# import os +# import random +# import re +# +# from aiogram import ( +# types, +# ) +# +# from aiogram.types import ( +# CallbackQuery, +# InlineKeyboardMarkup, +# Message, +# ) +# +# from asyncpg import ( +# UniqueViolationError, +# ) +# +# +# from src.tgbot.keyboards.inline.filters_inline import ( +# dating_filters_keyboard, +# ) +# from src.tgbot.keyboards.inline.guide_inline import ( +# create_pagination_keyboard, +# ) +# from src.tgbot.keyboards.inline.main_menu_inline import ( +# start_keyboard, +# ) +# from src.tgbot.keyboards.inline.settings_menu import ( +# information_keyboard, +# ) +# from deprecated.app_scheduler import ( +# send_message_week, +# ) +# +# +# # async def delete_message(message: Message) -> None: +# # with suppress(MessageCantBeDeleted, MessageToDeleteNotFound): +# # await message.delete() +# +# +# async def choice_gender(call: CallbackQuery) -> None: +# """Function that saves to the database the gender that the user has selected.""" +# sex_mapping = {"male": "Мужской", "female": "Женский"} +# +# selected_sex = sex_mapping.get(call.data) +# +# # if selected_sex: +# # try: +# # await db_commands.update_user_data( +# # telegram_id=call.from_user.id, need_partner_sex=selected_sex +# # ) +# # except UniqueViolationError: +# # pass +# +# +# async def display_profile(call: CallbackQuery, markup: InlineKeyboardMarkup) -> None: +# """Function for displaying the user profile.""" +# user = await db_commands.select_user(telegram_id=call.from_user.id) +# count_referrals = await db_commands.count_all_users_kwarg( +# referrer_id=call.from_user.id +# ) +# user_verification = "✅" if user.verification else "" +# +# user_info_template = _( +# "{name}, {age} лет, {city}, {verification}\n\n{commentary}\n\n" +# "Партнерка:\nКоличество приглашенных друзей: {reff}\nРеферальная ссылка:\n {link}" +# ) +# info = await bot.get_me() +# user_info = user_info_template.format( +# name=user.varname, +# age=user.age, +# city=user.city, +# verification=user_verification, +# commentary=user.commentary, +# reff=count_referrals, +# link=f"https://t.me/{info.username}?start={call.from_user.id}", +# ) +# +# await call.message.answer_photo( +# caption=user_info, photo=user.photo_id, reply_markup=markup +# ) +# +# +# async def show_dating_filters(obj: CallbackQuery | Message) -> None: +# user_id = obj.from_user.id +# user = await db_commands.select_user(telegram_id=user_id) +# markup = await dating_filters_keyboard() +# +# text = _( +# "Фильтр по подбору партнеров:\n\n" +# "🚻 Необходимы пол партнера: {}\n" +# "🔞 Возрастной диапазон: {}-{} лет\n\n" +# "🏙️ Город партнера: {}" +# ).format( +# user.need_partner_sex, +# user.need_partner_age_min, +# user.need_partner_age_max, +# user.need_city, +# ) +# try: +# await obj.message.edit_text(text, reply_markup=markup) +# except AttributeError: +# await obj.answer(text, reply_markup=markup) +# +# +# async def registration_menu( +# obj: CallbackQuery | Message, +# ) -> None: +# support = await db_commands.select_user( +# telegram_id=load_config().tg_bot.support_ids[0] +# ) +# markup = await start_keyboard(obj) +# heart = random.choice(["💙", "💚", "💛", "🧡", "💜", "🖤", "❤", "🤍", "💖", "💝"]) +# text = _( +# "Приветствую вас, {fullname}!!\n\n" +# "{heart} Querendo - платформа для поиска новых знакомств.\n\n" +# "🪧 Новости о проекте вы можете прочитать в нашем канале - " +# "https://t.me/que_group \n\n" +# "🤝 Сотрудничество: \n" +# "Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " +# "@{supports}\n\n" +# ).format(fullname=obj.from_user.full_name, heart=heart, supports=support.username) +# try: +# await obj.message.edit_text(text=text, reply_markup=markup) +# scheduler.add_job( +# send_message_week, +# trigger="interval", +# weeks=1, +# jitter=120, +# args={obj.message}, +# ) +# except AttributeError: +# await obj.answer(text=text, reply_markup=markup) +# scheduler.add_job( +# send_message_week, trigger="interval", weeks=1, jitter=120, args={obj} +# ) +# except BadRequest: +# await delete_message(obj.message) +# +# await obj.message.answer(text=text, reply_markup=markup) +# +# +# async def check_user_in_db(telegram_id: int, message: Message, username: str) -> None: +# if not await db_commands.check_user_exists( +# telegram_id +# ) and not await check_user_meetings_exists(telegram_id): +# user = await db_commands.select_user_object(telegram_id=telegram_id) +# referrer_id = message.text[7:] +# if referrer_id != "" and referrer_id != telegram_id: +# await db_commands.add_user( +# name=message.from_user.full_name, +# telegram_id=telegram_id, +# username=username, +# referrer_id=referrer_id, +# ) +# await db_commands.update_user_data( +# telegram_id=telegram_id, limit_of_views=user.limit_of_views + 15 +# ) +# await bot.send_message( +# chat_id=referrer_id, +# text=_( +# "По вашей ссылке зарегистрировался пользователь {}!\n" +# "Вы получаете дополнительных 15 ❤️" +# ).format(message.from_user.username), +# ) +# else: +# await db_commands.add_user( +# name=message.from_user.full_name, +# telegram_id=telegram_id, +# username=username, +# ) +# await db_commands.add_meetings_user(telegram_id=telegram_id, username=username) +# if telegram_id in load_config().tg_bot.admin_ids: +# await db_commands.add_user_to_settings(telegram_id=telegram_id) +# +# +# async def finished_registration( +# state: FSMContext, telegram_id: int, message: Message +# ) -> None: +# await state.finish() +# await db_commands.update_user_data(telegram_id=telegram_id, status=True) +# +# user = await db_commands.select_user(telegram_id=telegram_id) +# +# markup = await start_keyboard(obj=message) +# +# text = _( +# "Регистрация успешно завершена! \n\n " +# "{}, " +# "{} лет, " +# "{}\n\n" +# "О себе - {}" +# ).format(user.varname, user.age, user.city, user.commentary) +# +# await message.answer_photo(caption=text, photo=user.photo_id, reply_markup=markup) +# +# +# async def send_photo_with_caption( +# call: CallbackQuery, +# photo: str, +# caption: str, +# step: int, +# total_steps: int, +# ) -> None: +# markup = await create_pagination_keyboard(step, total_steps) +# +# await call.message.delete() +# await call.message.answer_photo( +# types.InputFile(photo), reply_markup=markup, caption=caption +# ) +# +# +# async def handle_guide_callback( +# call: CallbackQuery, +# callback_data: dict, +# ) -> None: +# step = int(callback_data.get("value")) +# +# photo_path = f"brandbook/{step}_page.png" +# caption = _("Руководство по боту: \nСтраница №{}").format(step) +# await send_photo_with_caption( +# call=call, +# photo=photo_path, +# caption=caption, +# step=step, +# total_steps=len(os.listdir("brandbook/")), +# ) +# +# +# async def information_menu(call: CallbackQuery) -> None: +# start_date = datetime.datetime(2021, 8, 10, 14, 0) +# now_date = datetime.datetime.now() +# delta = now_date - start_date +# count_users = await db_commands.count_users() +# markup = await information_keyboard() +# txt = _( +# "Вы попали в раздел Информации бота, здесь вы можете посмотреть: статистику," +# "изменить язык, а также посмотреть наш брендбук.\n\n" +# "🌐 Дней работаем: {}\n" +# "👤 Всего пользователей: {}\n" +# ).format(delta.days, count_users) +# try: +# await call.message.edit_text(text=txt, reply_markup=markup) +# except BadRequest: +# await delete_message(call.message) +# await call.message.answer(text=txt, reply_markup=markup) +# +# +# async def get_report_reason(call: CallbackQuery) -> str: +# match = re.search(r"report:(.*?):", call.data) +# reason_key = match.group(1) +# reason_mapping = { +# "adults_only": "🔞 Развратный контент", +# "drugs": "💊 Продажа наркотиков", +# "scam": "💰 Мошенничество", +# "another": "🦨 Другая причина", +# } +# return reason_mapping.get(reason_key, "Неизвестная причина") diff --git a/deprecated/notify_admins.py b/deprecated/notify_admins.py new file mode 100644 index 0000000..84323b7 --- /dev/null +++ b/deprecated/notify_admins.py @@ -0,0 +1,60 @@ +# from abc import ( +# ABC, +# abstractmethod, +# ) +# +# import aiogram +# from aiogram import ( +# Dispatcher, +# ) +# import aiogram.utils.exceptions +# from aiogram.utils.exceptions import ( +# ChatNotFound, +# ) +# +# from loader import ( +# _, +# bot, +# logger, +# ) +# from src.tgbot.config import ( +# load_config, +# ) +# +# +# class BaseNotification(ABC): +# @abstractmethod +# def send(self, *args): +# pass +# +# +# class AdminNotification(BaseNotification): +# def __init__(self, dp: Dispatcher): +# self.dp = dp +# +# async def send(self) -> None: +# logger.info(_("Оповещение администрации...")) +# for admin in load_config().tg_bot.admin_ids: +# try: +# await bot.send_message( +# admin, _("Бот был успешно запущен"), disable_notification=True +# ) +# except ChatNotFound: +# logger.debug("Чат с админом не найден") +# +# +# class ErrorNotification(BaseNotification): +# def __init__(self, error_message: Exception): +# self.__error_message = error_message +# +# async def send(self) -> None: +# text = ( +# f"❗ Error During Operation ❗\n" +# f"{self.__error_message}\n\n❗" +# f" The bot will restart automatically." +# ) +# for user_id in load_config().tg_bot.admin_ids: +# try: +# await bot.send_message(user_id, text) +# except (aiogram.exceptions.BotBlocked, aiogram.exceptions.ChatNotFound): +# continue diff --git a/deprecated/photo_operations.py b/deprecated/photo_operations.py new file mode 100644 index 0000000..6c9dd68 --- /dev/null +++ b/deprecated/photo_operations.py @@ -0,0 +1,103 @@ +# import asyncio +# import pathlib +# +# from aiogram.fsm.context import FSMContext +# from aiogram.types import ( +# InlineKeyboardMarkup, +# InputFile, +# Message, +# ReplyKeyboardRemove, +# ) +# +# +# async def saving_normal_photo( +# message: Message, telegram_id: int, file_id: str, state: FSMContext +# ) -> None: +# """Функция, сохраняющая фотографию пользователя без цензуры.""" +# try: +# await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) +# +# await message.answer( +# text=_("Фото принято!"), reply_markup=ReplyKeyboardRemove() +# ) +# except Exception as err: +# logger.info(f"Ошибка в saving_normal_photo | err: {err}") +# await message.answer( +# text=_( +# "Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" +# "Если ошибка осталась, напишите агенту поддержки." +# ) +# ) +# await finished_registration(state=state, telegram_id=telegram_id, message=message) +# +# +# async def saving_censored_photo( +# message: Message, +# telegram_id: int, +# state: FSMContext, +# out_path: str | pathlib.Path, +# flag: str | None = "registration", +# markup: InlineKeyboardMarkup | None = None, +# ) -> None: +# """.Функция, сохраняющая фотографию пользователя с цензурой.""" +# photo = InputFile(out_path) +# id_photo = await bot.send_photo( +# chat_id=telegram_id, +# photo=photo, +# caption=_( +# "Во время проверки вашего фото мы обнаружили подозрительный контент!\n" +# "Поэтому мы чуть-чуть подкорректировали вашу фотографию" +# ), +# ) +# file_id = id_photo["photo"][0]["file_id"] +# await asyncio.sleep(1) +# try: +# await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) +# +# except Exception as err: +# logger.info(f"Ошибка в saving_censored_photo | err: {err}") +# await message.answer( +# text=_( +# "Произошла ошибка!" +# " Попробуйте еще раз либо отправьте другую фотографию. \n" +# "Если ошибка осталась, напишите агенту поддержки." +# ) +# ) +# if flag == "change_datas": +# await message.answer( +# text=_("Фото принято!\n" "Выберите, что вы хотите изменить: "), +# reply_markup=markup, +# ) +# await state.reset_state() +# elif flag == "registration": +# await finished_registration( +# state=state, telegram_id=telegram_id, message=message +# ) +# +# +# async def update_normal_photo( +# message: Message, +# telegram_id: int, +# file_id: str, +# state: FSMContext, +# markup +# ) -> None: +# """Функция, которая обновляет фотографию пользователя.""" +# try: +# await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) +# await message.answer( +# text=_("Фото принято!"), reply_markup=ReplyKeyboardRemove() +# ) +# await asyncio.sleep(3) +# await message.answer( +# text=_("Выберите, что вы хотите изменить: "), reply_markup=markup +# ) +# await state.reset_state() +# except Exception as err: +# logger.info(f"Ошибка в update_normal_photo | err: {err}") +# await message.answer( +# text=_( +# "Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" +# "Если ошибка осталась, напишите агенту поддержки." +# ) +# ) diff --git a/deprecated/reaction_strategies.py b/deprecated/reaction_strategies.py new file mode 100644 index 0000000..dc56f56 --- /dev/null +++ b/deprecated/reaction_strategies.py @@ -0,0 +1,252 @@ +# from abc import ( +# ABC, +# abstractmethod, +# ) +# import asyncio +# import random +# import secrets +# +# from aiogram.dispatcher import ( +# FSMContext, +# ) +# from aiogram.types import ( +# CallbackQuery, +# ) +# +# from loader import ( +# _, +# bot, +# ) +# from src.tgbot.config import ( +# load_config, +# ) +# from src.infrastructure.db_api import ( +# db_commands, +# ) +# from src.tgbot.keyboards.inline.main_menu_inline import ( +# start_keyboard, +# ) +# from src.tgbot.keyboards.inline.questionnaires_inline import ( +# report_menu_keyboard, +# user_link_keyboard, +# ) +# from deprecated.message_operations import ( +# get_report_reason, +# ) +# from deprecated.create_forms_funcs import ( +# create_questionnaire, +# create_questionnaire_reciprocity, +# rand_user_list, +# ) +# from deprecated.get_next_user_func import ( +# get_next_user, +# ) +# +# +# class ActionStrategy(ABC): +# @abstractmethod +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# pass +# +# +# class StartFindingSuccess(ActionStrategy): +# async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): +# await call.message.delete() +# telegram_id = call.from_user.id +# user_list = await get_next_user(telegram_id) +# random_user = random.choice(user_list) +# await create_questionnaire(form_owner=random_user, chat_id=telegram_id) +# await state.set_state("finding") +# +# +# class StartFindingFailure(ActionStrategy): +# async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): +# await call.answer(_("На данный момент у нас нет подходящих анкет для вас")) +# +# +# class StartFindingReachLimit(ActionStrategy): +# async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): +# await call.answer( +# text=_("У вас достигнут лимит на просмотры анкет"), show_alert=True +# ) +# +# +# class LikeAction(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# user = await db_commands.select_user_object(telegram_id=call.from_user.id) +# text = _("Кому-то понравилась твоя анкета") +# target_id = int(callback_data["target_id"]) +# +# await create_questionnaire( +# form_owner=call.from_user.id, chat_id=target_id, add_text=text +# ) +# +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=None, +# ) +# +# await db_commands.update_user_data( +# telegram_id=call.from_user.id, limit_of_views=user.limit_of_views - 1 +# ) +# await create_questionnaire( +# form_owner=(await rand_user_list(call)), chat_id=call.from_user.id +# ) +# +# await state.reset_data() +# +# +# class DislikeAction(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=None, +# ) +# await create_questionnaire( +# form_owner=(await rand_user_list(call)), chat_id=call.from_user.id +# ) +# await state.reset_data() +# +# +# class StoppedAction(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# text = _( +# "Рад был помочь, {fullname}!\nНадеюсь, ты нашел кого-то благодаря мне" +# ).format(fullname=call.from_user.full_name) +# await call.answer(text, show_alert=True) +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=await start_keyboard(call), +# ) +# await state.reset_state() +# +# +# class LikeReciprocity(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# user_for_like = int(callback_data["user_for_like"]) +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=None, +# ) +# await call.message.answer( +# text=_("Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉"), +# reply_markup=await user_link_keyboard(telegram_id=user_for_like), +# ) +# await create_questionnaire_reciprocity( +# liker=call.from_user.id, chat_id=user_for_like, add_text="" +# ) +# await bot.send_message( +# chat_id=user_for_like, +# text="Есть взаимная симпатия! Начиная общаться 👉", +# reply_markup=await user_link_keyboard(telegram_id=call.from_user.id), +# ) +# await state.reset_state() +# +# +# class DislikeReciprocity(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=await start_keyboard(call), +# ) +# await state.reset_state() +# +# +# class GoBackToViewing(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=None, +# ) +# +# user_list = await get_next_user(call.from_user.id) +# random_user = secrets.choice(user_list) +# await state.set_state("finding") +# try: +# await create_questionnaire( +# form_owner=random_user, chat_id=call.from_user.id +# ) +# await state.reset_data() +# except IndexError: +# await call.answer(_("На данный момент у нас нет подходящих анкет для вас")) +# await state.reset_data() +# +# +# class ChooseReportReason(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# await state.reset_state() +# await bot.edit_message_reply_markup( +# chat_id=call.from_user.id, +# message_id=call.message.message_id, +# reply_markup=None, +# ) +# target_id = int(callback_data["target_id"]) +# await call.message.answer( +# text=_("Выберите причину жалобы:"), +# reply_markup=await report_menu_keyboard(telegram_id=target_id), +# ) +# +# +# class SendReport(ActionStrategy): +# async def execute( +# self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] +# ): +# target_id = int(callback_data["target_id"]) +# target_user = await db_commands.select_user(telegram_id=target_id) +# +# counter_of_report = target_user.counter_of_report +# username = call.from_user.username +# user_id = call.from_user.id +# report_reason = await get_report_reason(call) +# +# text = _( +# "Жалоба от пользователя: [@{username} | {tg_id}]\n\n" +# "На пользователя: [{owner_id}]\n" +# "Причина жалобы: {reason}\n" +# "Количество жалоб на пользователя: {counter_of_report}" +# ).format( +# username=username, +# tg_id=user_id, +# owner_id=target_id, +# reason=report_reason, +# counter_of_report=counter_of_report, +# ) +# +# await db_commands.update_user_data( +# telegram_id=target_id, counter_of_report=counter_of_report + 1 +# ) +# +# moderate_chat = load_config().tg_bot.moderate_chat +# if counter_of_report >= 5 and not target_user.on_check_by_admin: +# await db_commands.update_user_data( +# telegram_id=target_id, on_check_by_admin=True +# ) +# await create_questionnaire( +# form_owner=target_id, +# chat_id=moderate_chat, +# report_system=True, +# add_text=text, +# ) +# await asyncio.sleep(0.5) diff --git a/deprecated/send_form_func.py b/deprecated/send_form_func.py new file mode 100644 index 0000000..71832f9 --- /dev/null +++ b/deprecated/send_form_func.py @@ -0,0 +1,134 @@ +# from typing import ( +# Optional, +# ) +# +# from aiogram.types import ( +# InlineKeyboardMarkup, +# ) +# from aiogram.utils.exceptions import ( +# BadRequest, +# ) +# +# from loader import ( +# _, +# bot, +# logger, +# ) +# from src.infrastructure.db_api import ( +# db_commands, +# ) +# from src.tgbot.keyboards.admin.inline.customers import ( +# user_blocking_keyboard, +# ) +# from src.tgbot.keyboards.inline.questionnaires_inline import ( +# questionnaires_keyboard, +# reciprocity_keyboard, +# ) +# +# +# async def send_questionnaire( +# chat_id: int, +# owner_id: int | None = None, +# markup: InlineKeyboardMarkup | None = None, +# add_text: str | None = None, +# monitoring: bool = False, +# report_system: bool = False, +# ) -> None: +# user = await db_commands.select_user(owner_id) +# text_template = _("{}, {} лет, {} {verification}\n\n") +# user_verification = "✅" if user.verification else "" +# +# text_without_inst = _(text_template + "{commentary}").format( +# user.varname, +# user.age, +# user.city, +# commentary=user.commentary, +# verification=user_verification, +# ) +# +# text_with_inst_template = text_template + _( +# "Инстаграм - {instagram}\n" +# ) +# text_with_inst = _(text_with_inst_template).format( +# user.varname, +# user.age, +# user.city, +# user.commentary, +# verification=user_verification, +# instagram=user.instagram, +# ) +# +# caption_with_add_text = _("{}\n\n" + text_template + "{}").format( +# add_text, +# user.varname, +# user.age, +# user.city, +# user.commentary, +# verification=user_verification, +# ) +# +# add_text_with_inst = _( +# "{}\n\n" + text_template + "Инстаграм - {instagram}\n" +# ).format( +# add_text, +# user.varname, +# user.age, +# user.city, +# user.commentary, +# verification=user_verification, +# instagram=user.instagram, +# ) +# try: +# if add_text is None and user.instagram is None: +# await bot.send_photo( +# chat_id=chat_id, +# caption=text_without_inst, +# photo=user.photo_id, +# reply_markup=await questionnaires_keyboard( +# target_id=owner_id, monitoring=monitoring +# ), +# ) +# elif add_text is None: +# await bot.send_photo( +# chat_id=chat_id, +# caption=text_with_inst, +# photo=user.photo_id, +# reply_markup=await questionnaires_keyboard( +# target_id=owner_id, monitoring=monitoring +# ), +# ) +# elif markup is None and user.instagram is None: +# await bot.send_photo( +# chat_id=chat_id, +# caption=caption_with_add_text, +# photo=user.photo_id, +# ) +# elif markup is None: +# await bot.send_photo( +# chat_id=chat_id, caption=add_text_with_inst, photo=user.photo_id +# ) +# elif user.instagram is None and not report_system: +# await bot.send_photo( +# chat_id=chat_id, +# caption=caption_with_add_text, +# photo=user.photo_id, +# reply_markup=await reciprocity_keyboard(user_for_like=owner_id), +# ) +# elif report_system: +# await bot.send_photo( +# chat_id=chat_id, +# caption=add_text, +# photo=user.photo_id, +# reply_markup=await user_blocking_keyboard( +# user_id=owner_id, is_banned=user.is_banned +# ), +# ) +# else: +# await bot.send_photo( +# chat_id=chat_id, +# caption=add_text_with_inst, +# photo=user.photo_id, +# reply_markup=await reciprocity_keyboard(user_for_like=owner_id), +# ) +# except BadRequest as err: +# logger.info(f"{err}. Error in the send_questionnaire function") diff --git a/deprecated/states.py b/deprecated/states.py new file mode 100644 index 0000000..7bfb86d --- /dev/null +++ b/deprecated/states.py @@ -0,0 +1,44 @@ +from aiogram.fsm.state import ( + State, + StatesGroup, +) + + +class AdminsActions(StatesGroup): + add = State() + delete = State() + + +class NewData(StatesGroup): + sex = State() + commentary = State() + name = State() + need_partner_sex = State() + age = State() + city = State() + nationality = State() + education = State() + town = State() + car = State() + own_home = State() + hobbies = State() + child = State() + marital = State() + photo = State() + + +class RegData(StatesGroup): + sex = State() + commentary = State() + name = State() + need_partner_sex = State() + age = State() + nationality = State() + education = State() + town = State() + car = State() + own_home = State() + hobbies = State() + child = State() + marital = State() + photo = State() diff --git a/utils/statistics.py b/deprecated/statistics.py similarity index 93% rename from utils/statistics.py rename to deprecated/statistics.py index 93dafab..3ce6c32 100644 --- a/utils/statistics.py +++ b/deprecated/statistics.py @@ -2,15 +2,8 @@ Message, ) -from loader import ( - _, -) -from utils.db_api import ( - db_commands, -) - -async def get_statistics(message: Message): +async def get_statistics(message: Message, db_commands=None, _=None): user = await db_commands.select_user(telegram_id=message.from_user.id) user_city = user.city users_gender_m = await db_commands.count_all_users_kwarg(sex="Мужской") diff --git a/functions/event/templates_messages.py b/deprecated/templates_messages.py similarity index 85% rename from functions/event/templates_messages.py rename to deprecated/templates_messages.py index 3aaad2e..060f0ca 100644 --- a/functions/event/templates_messages.py +++ b/deprecated/templates_messages.py @@ -1,8 +1,3 @@ -from typing import ( - Optional, - Union, -) - from aiogram import ( Bot, ) @@ -10,21 +5,18 @@ CallbackQuery, ) -from keyboards.inline.poster_inline import ( +from src.tgbot.keyboards.inline.poster_inline import ( cancel_event_keyboard, create_moderate_ik, event_settings_keyboard, view_event_keyboard, ) -from loader import ( - _, -) class TemplateEvent: def __init__(self) -> None: - self.message_for_event = _( - "{} \n" + "Когда: {} \n" + "Где: {} \n\n" + "{}" + self.message_for_event = ( + "{} \n" + "Когда: {} \n" + "Где: {} \n\n" + "{}" ) def template_event(self) -> str: @@ -32,11 +24,11 @@ def template_event(self) -> str: async def send_event_message( self, - text: dict[str, Union[str, str, int]], + text: dict[str, str | str | int], bot: Bot, chat_id: int, moderate: bool = False, - call: Optional[CallbackQuery] = None, + call: CallbackQuery | None = None, view_event: bool = False, ) -> None: msg = self.template_event().format( @@ -71,7 +63,7 @@ async def send_event_message( async def send_event_list( self, - text: dict[str, Union[str, str, int]], + text: dict[str, str | str | int], call: CallbackQuery, telegram_id: int, bot: Bot, diff --git a/django_app.py b/django_app.py deleted file mode 100644 index e1590e9..0000000 --- a/django_app.py +++ /dev/null @@ -1,5 +0,0 @@ -from django_project.telegrambot.manage import ( - main, -) - -main() diff --git a/django_project/telegrambot/common/admin.py b/django_project/telegrambot/common/admin.py deleted file mode 100644 index e69de29..0000000 diff --git a/django_project/telegrambot/common/apps.py b/django_project/telegrambot/common/apps.py deleted file mode 100644 index 80b93d2..0000000 --- a/django_project/telegrambot/common/apps.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.apps import ( - AppConfig, -) - - -class CommonConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "django_project.telegrambot.common" diff --git a/django_project/telegrambot/common/mixins.py b/django_project/telegrambot/common/mixins.py deleted file mode 100644 index e69de29..0000000 diff --git a/django_project/telegrambot/manage.py b/django_project/telegrambot/manage.py deleted file mode 100644 index fbddbf7..0000000 --- a/django_project/telegrambot/manage.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -import os -import sys - - -def main(): - os.environ.setdefault( - "DJANGO_SETTINGS_MODULE", "django_project.telegrambot.telegrambot.settings" - ) - try: - from django.core.management import ( - execute_from_command_line, - ) - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == "__main__": - main() diff --git a/django_project/telegrambot/telegrambot/asgi.py b/django_project/telegrambot/telegrambot/asgi.py deleted file mode 100644 index 3963f2b..0000000 --- a/django_project/telegrambot/telegrambot/asgi.py +++ /dev/null @@ -1,9 +0,0 @@ -import os - -from django.core.asgi import ( - get_asgi_application, -) - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "telegrambot.settings") - -application = get_asgi_application() diff --git a/django_project/telegrambot/telegrambot/settings.py b/django_project/telegrambot/telegrambot/settings.py deleted file mode 100644 index 442a9d9..0000000 --- a/django_project/telegrambot/telegrambot/settings.py +++ /dev/null @@ -1,98 +0,0 @@ -import os -from pathlib import ( - Path, -) - -from data.config import ( - load_config, -) - -BASE_DIR = Path(__file__).resolve().parent.parent - -SECRET_KEY = load_config().misc.secret_key - -DEBUG = True - -ALLOWED_HOSTS = [] - -INSTALLED_APPS = [ - 'jazzmin', - 'django_project.telegrambot.common', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - "django_project.telegrambot.usersmanage", -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'django_project.telegrambot.telegrambot.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.join(BASE_DIR, "frontend/build"), - ], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'django_project.telegrambot.telegrambot.wsgi.application' - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': load_config().db.database, - 'USER': load_config().db.user, - 'PASSWORD': load_config().db.password, - 'HOST': load_config().db.host, - "PORT": load_config().db.port - } -} - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -LANGUAGE_CODE = 'ru-ru' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - -STATIC_URL = '/static/' diff --git a/django_project/telegrambot/telegrambot/urls.py b/django_project/telegrambot/telegrambot/urls.py deleted file mode 100644 index ee6e353..0000000 --- a/django_project/telegrambot/telegrambot/urls.py +++ /dev/null @@ -1,15 +0,0 @@ -from django.contrib import ( - admin, -) -from django.urls import ( - path, -) - -from django_project.telegrambot.usersmanage import ( - views, -) - -urlpatterns = [ - path("admin/", admin.site.urls), - path("export/", views.export_users_csv), -] diff --git a/django_project/telegrambot/telegrambot/wsgi.py b/django_project/telegrambot/telegrambot/wsgi.py deleted file mode 100644 index 240753b..0000000 --- a/django_project/telegrambot/telegrambot/wsgi.py +++ /dev/null @@ -1,9 +0,0 @@ -import os - -from django.core.wsgi import ( - get_wsgi_application, -) - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "telegrambot.settings") - -application = get_wsgi_application() diff --git a/django_project/telegrambot/usersmanage/admin.py b/django_project/telegrambot/usersmanage/admin.py deleted file mode 100644 index 281661e..0000000 --- a/django_project/telegrambot/usersmanage/admin.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.contrib import ( - admin, -) - -from django_project.telegrambot.usersmanage.models.meetings import ( - UserMeetings, -) -from django_project.telegrambot.usersmanage.models.necessary_link import ( - NecessaryLink, -) -from django_project.telegrambot.usersmanage.models.settings_models import ( - SettingModel, -) -from django_project.telegrambot.usersmanage.models.user import ( - User, -) - - -@admin.register(User) -class UserAdmin(admin.ModelAdmin): - list_display = ("id", "telegram_id", "username", "created_at") - - -@admin.register(UserMeetings) -class UserMeetingsAdmin(admin.ModelAdmin): - list_display = ("id", "telegram_id", "username", "created_at") - - -@admin.register(SettingModel) -class UserSettingsAdmin(admin.ModelAdmin): - list_display = ("telegram_id", "technical_works") - - -@admin.register(NecessaryLink) -class NecessaryLinkAdmin(admin.ModelAdmin): - list_display = ["id", "link", "telegram_link_id", "title"] - - search_fields = ( - "link__startswith", - "title__startswith", - "telegram_link_id__startswith", - ) diff --git a/django_project/telegrambot/usersmanage/apps.py b/django_project/telegrambot/usersmanage/apps.py deleted file mode 100644 index 3b28978..0000000 --- a/django_project/telegrambot/usersmanage/apps.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.apps import ( - AppConfig, -) - - -class UsersmanageConfig(AppConfig): - name = "django_project.telegrambot.usersmanage" diff --git a/django_project/telegrambot/usersmanage/migrations/0001_initial.py b/django_project/telegrambot/usersmanage/migrations/0001_initial.py deleted file mode 100644 index 35a164f..0000000 --- a/django_project/telegrambot/usersmanage/migrations/0001_initial.py +++ /dev/null @@ -1,124 +0,0 @@ -# Generated by Django 4.2 on 2023-08-09 20:47 - -import django.contrib.postgres.fields -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='NecessaryLink', - fields=[ - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('id', models.AutoField(primary_key=True, serialize=False)), - ('link', models.URLField(verbose_name='Обязательная ссылка')), - ('telegram_link_id', models.BigIntegerField(verbose_name='id КАНАЛА/ЧАТА - ОБЯЗАТЕЛЬНО')), - ('title', models.CharField(max_length=50, verbose_name='Название кнопки - ОБЯЗАТЕЛЬНО. Можно смайлики')), - ], - options={ - 'verbose_name': 'Необходимая ссылка', - 'verbose_name_plural': 'Необходимые ссылки', - }, - ), - migrations.CreateModel( - name='SettingModel', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('telegram_id', models.PositiveBigIntegerField(default=1, unique=True, verbose_name='ID пользователя Телеграм')), - ('technical_works', models.BooleanField(default=False, verbose_name='Технические работы')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='User', - fields=[ - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('id', models.AutoField(primary_key=True, serialize=False)), - ('telegram_id', models.PositiveBigIntegerField(default=1, unique=True, verbose_name='ID пользователя Телеграм')), - ('name', models.CharField(max_length=255, verbose_name='Имя пользователя')), - ('username', models.CharField(max_length=255, verbose_name='Username Telegram')), - ('sex', models.CharField(blank=True, max_length=30, null=True, verbose_name='Пол искателя')), - ('age', models.BigIntegerField(blank=True, null=True, verbose_name='Возраст искателя')), - ('city', models.CharField(blank=True, max_length=255, null=True, verbose_name='Город искателя')), - ('need_city', models.CharField(blank=True, max_length=255, null=True, verbose_name='Город партнера')), - ('need_distance', models.PositiveIntegerField(blank=True, null=True, verbose_name='Расстояние между партнерами')), - ('longitude', models.FloatField(blank=True, null=True, verbose_name='координаты пользователя')), - ('latitude', models.FloatField(blank=True, null=True, verbose_name='координаты пользователя')), - ('verification', models.BooleanField(default=False, verbose_name='Верификация')), - ('language', models.CharField(blank=True, max_length=10, null=True, verbose_name='Язык пользователя')), - ('varname', models.CharField(blank=True, max_length=100, null=True, verbose_name='Публичное имя пользователя')), - ('lifestyle', models.CharField(blank=True, max_length=100, null=True, verbose_name='Стиль жизни пользователя')), - ('is_banned', models.BooleanField(default=False, verbose_name='Забанен ли пользователь')), - ('photo_id', models.CharField(max_length=400, null=True, verbose_name='Photo_ID')), - ('commentary', models.CharField(blank=True, max_length=300, null=True, verbose_name='Комментарий пользователя')), - ('need_partner_sex', models.CharField(blank=True, max_length=50, null=True, verbose_name='Пол партнера')), - ('need_partner_age_min', models.PositiveIntegerField(default=16, verbose_name='Минимальный возраст партнера')), - ('need_partner_age_max', models.PositiveIntegerField(default=24, verbose_name='Максимальный возраст партнера')), - ('referrer_id', models.PositiveBigIntegerField(blank=True, null=True, verbose_name='реферал')), - ('phone_number', models.BigIntegerField(blank=True, null=True, verbose_name='Номер телефона')), - ('status', models.BooleanField(default=False, verbose_name='Статус анкеты')), - ('instagram', models.CharField(blank=True, max_length=200, null=True, verbose_name='Ник в инстаграме')), - ('events', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), default=list, size=None)), - ('id_of_events_seen', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=255), default=list, size=None)), - ], - options={ - 'verbose_name': ('Пользователь Знакомств',), - 'verbose_name_plural': 'Пользователи Знакомств', - }, - ), - migrations.CreateModel( - name='UserMeetings', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('telegram_id', models.PositiveBigIntegerField(default=1, unique=True, verbose_name='ID пользователя Телеграм')), - ('username', models.CharField(max_length=255, verbose_name='Username Telegram')), - ('commentary', models.CharField(max_length=50, null=True, verbose_name='Комментарий')), - ('time_event', models.CharField(max_length=10, null=True, verbose_name='Время проведения')), - ('venue', models.CharField(max_length=50, null=True, verbose_name='Место проведения')), - ('need_location', models.CharField(max_length=50, null=True)), - ('event_name', models.CharField(max_length=50, null=True, verbose_name='Название мероприятия')), - ('verification_status', models.BooleanField(default=False, verbose_name='Статус пользователя')), - ('moderation_process', models.BooleanField(default=True, verbose_name='Процесс модерации')), - ('is_premium', models.BooleanField(default=False, verbose_name='Премиум')), - ('photo_id', models.CharField(max_length=400, null=True, verbose_name='Photo_ID')), - ('is_admin', models.BooleanField(default=False)), - ('is_active', models.BooleanField(default=True)), - ], - options={ - 'verbose_name': ('Пользователь Мероприятий',), - 'verbose_name_plural': 'Пользователи Мероприятий', - }, - ), - migrations.CreateModel( - name='ViewedProfile', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('viewed_at', models.DateTimeField(auto_now_add=True)), - ('profile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to='usersmanage.user')), - ('viewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='viewer', to='usersmanage.user')), - ], - options={ - 'unique_together': {('viewer', 'profile')}, - }, - ), - migrations.AddField( - model_name='user', - name='viewed_profiles', - field=models.ManyToManyField(through='usersmanage.ViewedProfile', to='usersmanage.user'), - ), - ] diff --git a/django_project/telegrambot/usersmanage/models/__init__.py b/django_project/telegrambot/usersmanage/models/__init__.py deleted file mode 100644 index de5a973..0000000 --- a/django_project/telegrambot/usersmanage/models/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from .base import ( - TimeBasedModel, -) -from .meetings import ( - UserMeetings, -) -from .necessary_link import ( - NecessaryLink, -) -from .settings_models import ( - SettingModel, -) -from .user import ( - User, -) -from .viewed_profile import ( - ViewedProfile, -) diff --git a/django_project/telegrambot/usersmanage/models/base.py b/django_project/telegrambot/usersmanage/models/base.py deleted file mode 100644 index b17d6c7..0000000 --- a/django_project/telegrambot/usersmanage/models/base.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.db import ( - models, -) - - -class TimeBasedModel(models.Model): - id = models.AutoField( - primary_key=True, - ) - created_at = models.DateTimeField( - auto_now_add=True, - verbose_name="Дата создания", - ) - updated_at = models.DateTimeField( - auto_now=True, - verbose_name="Дата обновления", - ) - - class Meta: - abstract = True diff --git a/django_project/telegrambot/usersmanage/models/meetings.py b/django_project/telegrambot/usersmanage/models/meetings.py deleted file mode 100644 index 901ede0..0000000 --- a/django_project/telegrambot/usersmanage/models/meetings.py +++ /dev/null @@ -1,40 +0,0 @@ -from django.db import ( - models, -) - -from django_project.telegrambot.usersmanage.models.base import ( - TimeBasedModel, -) - - -class UserMeetings(TimeBasedModel): - class Meta: - verbose_name = ("Пользователь Мероприятий",) - verbose_name_plural = "Пользователи Мероприятий" - - telegram_id = models.PositiveBigIntegerField( - unique=True, default=1, verbose_name="ID пользователя Телеграм" - ) - username = models.CharField(max_length=255, verbose_name="Username Telegram") - commentary = models.CharField(max_length=50, verbose_name="Комментарий", null=True) - time_event = models.CharField( - max_length=10, verbose_name="Время проведения", null=True - ) - venue = models.CharField(max_length=50, verbose_name="Место проведения", null=True) - need_location = models.CharField(max_length=50, null=True) - event_name = models.CharField( - max_length=50, verbose_name="Название мероприятия", null=True - ) - verification_status = models.BooleanField( - verbose_name="Статус пользователя", default=False - ) - moderation_process = models.BooleanField( - verbose_name="Процесс модерации", default=False - ) - is_premium = models.BooleanField(verbose_name="Премиум", default=False) - photo_id = models.CharField(max_length=400, verbose_name="Photo_ID", null=True) - is_admin = models.BooleanField(default=False) - is_active = models.BooleanField(default=True) - - def __str__(self): - return f"№{self.id} ({self.telegram_id} - {self.username})" diff --git a/django_project/telegrambot/usersmanage/models/necessary_link.py b/django_project/telegrambot/usersmanage/models/necessary_link.py deleted file mode 100644 index 44dd7f6..0000000 --- a/django_project/telegrambot/usersmanage/models/necessary_link.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.db import ( - models, -) - -from django_project.telegrambot.usersmanage.models.base import ( - TimeBasedModel, -) - - -class NecessaryLink(TimeBasedModel): - class Meta: - verbose_name = "Необходимая ссылка" - verbose_name_plural = "Необходимые ссылки" - - id = models.AutoField(primary_key=True) - link = models.URLField(verbose_name="Обязательная ссылка") - telegram_link_id = models.BigIntegerField(verbose_name="id канала/чата") - title = models.CharField( - verbose_name="Название кнопки. Можно смайлики", max_length=50 - ) diff --git a/django_project/telegrambot/usersmanage/models/settings_models.py b/django_project/telegrambot/usersmanage/models/settings_models.py deleted file mode 100644 index 6869722..0000000 --- a/django_project/telegrambot/usersmanage/models/settings_models.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.db import ( - models, -) - -from django_project.telegrambot.usersmanage.models.base import ( - TimeBasedModel, -) - - -class SettingModel(TimeBasedModel): - telegram_id = models.PositiveBigIntegerField( - unique=True, default=1, verbose_name="ID пользователя Телеграм" - ) - technical_works = models.BooleanField( - default=False, verbose_name="Технические работы" - ) - - objects = models.Manager() diff --git a/django_project/telegrambot/usersmanage/models/user.py b/django_project/telegrambot/usersmanage/models/user.py deleted file mode 100644 index 7af3b06..0000000 --- a/django_project/telegrambot/usersmanage/models/user.py +++ /dev/null @@ -1,94 +0,0 @@ -from django.contrib.postgres.fields import ( - ArrayField, -) -from django.db import ( - models, -) - -from django_project.telegrambot.usersmanage.models.base import ( - TimeBasedModel, -) - - -class User(TimeBasedModel): - class Meta: - verbose_name = ("Пользователь Знакомств",) - verbose_name_plural = "Пользователи Знакомств" - - id = models.AutoField(primary_key=True) - telegram_id = models.PositiveBigIntegerField( - unique=True, default=1, verbose_name="ID пользователя Телеграм" - ) - name = models.CharField(max_length=255, verbose_name="Имя пользователя") - username = models.CharField(max_length=255, verbose_name="Username Telegram") - sex = models.CharField( - max_length=30, verbose_name="Пол искателя", null=True, blank=True - ) - age = models.BigIntegerField(verbose_name="Возраст искателя", null=True, blank=True) - city = models.CharField( - max_length=255, verbose_name="Город искателя", null=True, blank=True - ) - need_city = models.CharField( - max_length=255, verbose_name="Город партнера", null=True, blank=True - ) - need_distance = models.PositiveIntegerField( - verbose_name="Расстояние между партнерами", null=True, blank=True - ) - longitude = models.FloatField( - verbose_name="координаты пользователя", null=True, blank=True - ) - latitude = models.FloatField( - verbose_name="координаты пользователя", null=True, blank=True - ) - verification = models.BooleanField(verbose_name="Верификация", default=False) - language = models.CharField( - max_length=10, verbose_name="Язык пользователя", null=True, blank=True - ) - varname = models.CharField( - max_length=100, verbose_name="Публичное имя пользователя", null=True, blank=True - ) - lifestyle = models.CharField( - max_length=100, verbose_name="Стиль жизни пользователя", null=True, blank=True - ) - is_banned = models.BooleanField( - verbose_name="Забанен ли пользователь", default=False - ) - photo_id = models.CharField(max_length=400, verbose_name="Photo_ID", null=True) - commentary = models.CharField( - max_length=300, verbose_name="Комментарий пользователя", null=True, blank=True - ) - need_partner_sex = models.CharField( - max_length=50, verbose_name="Пол партнера", null=True, blank=True - ) - need_partner_age_min = models.PositiveIntegerField( - verbose_name="Минимальный возраст партнера", default=16 - ) - need_partner_age_max = models.PositiveIntegerField( - verbose_name="Максимальный возраст партнера", default=24 - ) - referrer_id = models.PositiveBigIntegerField( - verbose_name="реферал", null=True, blank=True - ) - phone_number = models.BigIntegerField( - verbose_name="Номер телефона", null=True, blank=True - ) - status = models.BooleanField(verbose_name="Статус анкеты", default=False) - instagram = models.CharField( - max_length=200, verbose_name="Ник в инстаграме", null=True, blank=True - ) - events = ArrayField(models.CharField(max_length=200), default=list) - id_of_events_seen = ArrayField(models.CharField(max_length=255), default=list) - viewed_profiles = models.ManyToManyField( - "self", through="ViewedProfile", symmetrical=False - ) - limit_of_views = models.PositiveIntegerField(default=10, null=True) - counter_of_report = models.PositiveIntegerField(default=0, null=True) - on_check_by_admin = models.BooleanField(default=False, null=True) - - def __str__(self): - return f"№{self.id} ({self.telegram_id}) - {self.name}" - - def remove_events(self, event_to_remove): - if event_to_remove in self.events: - self.events.remove(event_to_remove) - self.save() diff --git a/django_project/telegrambot/usersmanage/models/viewed_profile.py b/django_project/telegrambot/usersmanage/models/viewed_profile.py deleted file mode 100644 index 0c24b3e..0000000 --- a/django_project/telegrambot/usersmanage/models/viewed_profile.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.db import ( - models, -) - -from django_project.telegrambot.usersmanage.models.user import ( - User, -) - - -class ViewedProfile(models.Model): - viewer = models.ForeignKey(User, related_name="viewer", on_delete=models.CASCADE) - profile = models.ForeignKey(User, related_name="profile", on_delete=models.CASCADE) - viewed_at = models.DateTimeField(auto_now_add=True) - - class Meta: - unique_together = ("viewer", "profile") diff --git a/django_project/telegrambot/usersmanage/views.py b/django_project/telegrambot/usersmanage/views.py deleted file mode 100644 index 2ba86c8..0000000 --- a/django_project/telegrambot/usersmanage/views.py +++ /dev/null @@ -1,67 +0,0 @@ -import csv - -from django.http import ( - HttpResponse, -) - -from django_project.telegrambot.usersmanage.models.user import ( - User, -) - - -def export_users_csv(request): - response = HttpResponse(content_type="text/csv") - - writer = csv.writer(response) - writer.writerow([ - "id", - "telegram_id", - "name", - "username", - "sex", - "age", - "city", - "need_city", - "longitude", - "latitude", - "verification", - "language", - "varname", - "lifestyle", - "is_banned", - "photo_id", - "commentary", - "need_partner_sex", - "need_partner_age_min", - "need_partner_age_max", - "phone_number", - "status", - "instagram" - ]) - for user in User.objects.all().values_list("id", - "telegram_id", - "name", - "username", - "sex", - "age", - "city", - "need_city", - "longitude", - "latitude", - "verification", - "language", - "varname", - "lifestyle", - "is_banned", - "photo_id", - "commentary", - "need_partner_sex", - "need_partner_age_min", - "need_partner_age_max", - "phone_number", - "status", - "instagram"): - writer.writerow(user) - - response['Content-Disposition'] = 'attachment; filename="users.csv"' - return response diff --git a/docker-compose.yml b/docker-compose.yml index 08805b2..514716a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,6 @@ version: '3.1' services: - db: - container_name: database - image: postgres:14.1-alpine - env_file: - - ".env" - restart: always - ports: - - "5432:5432" - networks: - - botnet - volumes: - - ./postgres:/var/lib/postgresql - tgbot: container_name: bot build: @@ -27,21 +14,6 @@ services: - ".env" volumes: - .:/src - depends_on: - - db - django_migration: - container_name: migrations - build: - context: . - working_dir: "/src/" - command: sh -c "python3 django_app.py makemigrations && python3 django_app.py migrate" - networks: - - botnet - restart: "no" - depends_on: - - db - volumes: - - .:/src networks: botnet: diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index f343844..0faa6b5 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -7,7 +7,7 @@ - [Manually](#wheelchair-manually) - [requirements](#with-requirements) - [poetry](#with-poetry) - - [Localization](#globe_with_meridians-i18n) + - [Localization](#globe_with_meridians-i18n) - [Tests](#test_tube-tests) ## :construction_worker: Getting Started @@ -17,25 +17,15 @@ First, rename the file `.env.dist` to `.env`.\ Afterward, fill it with the required data. -| Variable | Type | Importance | Description | -|-------------------|------|------------|-----------------------------------------------------------------------------------------| -| BOT_TOKEN | str | True | Bot token | -| ADMINS | list | True | list of admins id | -| SUPPORTS | list | True | list of supports id | -| IP | str | True | ip for other services | -| TIMEZONE | str | True | your time zone for working with the scheduler | -| MODERATE_CHAT | str | True | telegram chat where the event will be moderated | -| POSTGRES_USER | str | True | username of the database owner | -| POSTGRES_PASSWORD | str | True | password from the database | -| DB_HOST | str | True | IP address of the database (Name of the service in the docker-compose.yml (User `db`)). | -| DB_PORT | str | True | the database port. Usually the db running on port `5432` | -| POSTGRES_DB | str | True | database name | -| SECRET_KEY | str | True | secret key for django | -| API_KEY | str | True | yandex api key for yandex map | -| QIWI_KEY | str | True | qiwi api key for receiving payments | -| PHONE_NUMBER | str | True | your phone number (need for qiwi) | -| SECRET_P2 | str | True | public p2 key which allows you to issue an invoice and open a transfer form | -| USE_REDIS | bool | False | Optional parameter | +| Variable | Type | Importance | Description | +|----------------------|------|------------|-------------------------------------------------| +| BOT_TOKEN | str | True | Bot token | +| ADMINS | list | True | list of admins id | +| SUPPORTS | list | True | list of supports id | +| TIMEZONE | str | True | your time zone for working with the scheduler | +| MODERATE_CHAT | str | True | telegram chat where the event will be moderated | +| SIGNATURE_SECRET_KEY | str | True | signature for login | +| USE_REDIS | bool | True | Use redis or default storage | Once done, run the following command: @@ -98,29 +88,6 @@ Then install Poetry dependencies: poetry install ``` -## :rocket: Usage - -Follow the same steps as described in the Docker section for setting up the .env file. But use `localhost` for `DB_HOST` - -### :green_book: Django - -To create a `SECRET_KEY`, use this site - [generate secret keys](https://djecrety.ir/) -and paste it into the `.env` file - -```dotenv -SECRET_KEY=jjv@^0qv^=aydunfjo$qpd_66j+)egm1#-c1iwt%mtjinm)ftj -``` - -Run the following commands to set up the Django application: -```sh -$ python django_app.py makemigrations -$ python django_app.py migrate -$ python django_app.py createsuperuser -$ python django_app.py makemigrations usersmanage -$ python django_app.py migrate usersmanage -$ python django_app.py runserver -``` - ## :globe_with_meridians: i18n ### Title - dating @@ -129,31 +96,31 @@ $ python django_app.py runserver 1. Extract texts from files (he finds it himself) ```sh - $ pybabel extract -F babel.cfg -o locales/dating.pot . + $ pybabel extract -F babel.cfg --input-dirs=. -o locales/messages.pot ``` 2. Create a folder for English translation ```sh - $ pybabel init -i locales/dating.pot -d locales -D dating -l en + $ pybabel init -i locales/messages.pot -d locales -D messages -l en ``` 3. For Russian translation ```sh - $ pybabel init -i locales/dating.pot -d locales -D dating -l ru + $ pybabel init -i locales/messages.pot -d locales -D messages -l ru ``` 4. Translate and compile ```sh - $ pybabel compile -d locales -D dating + $ pybabel compile -d locales -D messages ``` #### Updating translations 1. Extract texts from files, add text to translated versions ```sh - $ pybabel extract -F babel.cfg -o locales/dating.pot . - $ pybabel update -d locales -D dating -i locales/dating.pot + $ pybabel extract -F babel.cfg -o locales/messages.pot . + $ pybabel update -d locales -D dating -i locales/messages.pot ``` 2. Manually translate, then compile ```sh - $ pybabel compile -d locales -D dating + $ pybabel compile -d locales -D messages ``` ## :test_tube: Tests \ No newline at end of file diff --git a/filters/FiltersChat.py b/filters/FiltersChat.py deleted file mode 100644 index 56fa4db..0000000 --- a/filters/FiltersChat.py +++ /dev/null @@ -1,19 +0,0 @@ -from aiogram import ( - types, -) -from aiogram.dispatcher.filters import ( - BoundFilter, -) -from aiogram.types import ( - Message, -) - - -class IsPrivate(BoundFilter): - async def check(self, message: Message) -> bool: - return types.ChatType.PRIVATE == message.chat.type - - -class IsGroup(BoundFilter): - async def check(self, message: types.Message) -> bool: - return message.chat.type in (types.ChatType.GROUP, types.ChatType.SUPERGROUP) diff --git a/filters/IsAdminFilter.py b/filters/IsAdminFilter.py deleted file mode 100644 index c3191a8..0000000 --- a/filters/IsAdminFilter.py +++ /dev/null @@ -1,15 +0,0 @@ -from aiogram import ( - types, -) -from aiogram.dispatcher.filters import ( - BoundFilter, -) - -from data.config import ( - load_config, -) - - -class IsAdmin(BoundFilter): - async def check(self, message: types.Message) -> bool: - return message.from_user.id in load_config().tg_bot.admin_ids diff --git a/filters/__init__.py b/filters/__init__.py deleted file mode 100644 index a9b2cc3..0000000 --- a/filters/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from aiogram import ( - Dispatcher, -) - -from filters.FiltersChat import ( - IsPrivate, -) -from loader import ( - logger, -) - - -def setup(dp: Dispatcher): - logger.info("Подключение filters...") - text_messages = [ - dp.message_handlers, - dp.edited_message_handlers, - ] - logger.info(text_messages) - dp.filters_factory.bind(IsPrivate) diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs new file mode 100644 index 0000000..3e212e1 --- /dev/null +++ b/frontend/.eslintrc.cjs @@ -0,0 +1,21 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react/jsx-no-target-blank': 'off', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..63f8295 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,11 @@ +## Frontend + +### :alembic: Built With + +![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E) +![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB) +![Vite](https://img.shields.io/badge/vite-%23646CFF.svg?style=for-the-badge&logo=vite&logoColor=white) +![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white) +![ESLint](https://img.shields.io/badge/ESLint-4B3263?style=for-the-badge&logo=eslint&logoColor=white) +![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white) +![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge&logo=css3&logoColor=white) diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..b6ede01 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,14 @@ + + + + + + + Vite + React + + +
+ + + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..f3d4cd5 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,4511 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@reduxjs/toolkit": "^2.2.3", + "axios": "^1.6.8", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^9.1.1", + "react-router-dom": "^6.23.0" + }, + "devDependencies": { + "@types/react": "^18.2.66", + "@types/react-dom": "^18.2.22", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.57.0", + "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "vite": "^5.2.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.1.tgz", + "integrity": "sha512-kDJgnPujTmAZ/9q2CN4m2/lRsUUPDvsG3+tSHWUJIzMGTt5U/b/fwWd3RO3n+5mjLrsBrVa5eKFRVSQbi3dF1w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.1.tgz", + "integrity": "sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", + "integrity": "sha512-76dll9EnJXg4EVcI5YNxZA/9hSAmZsFqzMmNRHvIlzw2WS/twfcVX3ysYrWGJMClwEmChQFC4yRq74tn6fdzRA==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.0.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@remix-run/router": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz", + "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.4.tgz", + "integrity": "sha512-GkhjAaQ8oUTOKE4g4gsZ0u8K/IHU1+2WQSgS1TwTcYvL+sjbaQjNHFXbOJ6kgqGHIO1DfUhI/Sphi9GkRT9K+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.4.tgz", + "integrity": "sha512-Bvm6D+NPbGMQOcxvS1zUl8H7DWlywSXsphAeOnVeiZLQ+0J6Is8T7SrjGTH29KtYkiY9vld8ZnpV3G2EPbom+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.4.tgz", + "integrity": "sha512-i5d64MlnYBO9EkCOGe5vPR/EeDwjnKOGGdd7zKFhU5y8haKhQZTN2DgVtpODDMxUr4t2K90wTUJg7ilgND6bXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.4.tgz", + "integrity": "sha512-WZupV1+CdUYehaZqjaFTClJI72fjJEgTXdf4NbW69I9XyvdmztUExBtcI2yIIU6hJtYvtwS6pkTkHJz+k08mAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.4.tgz", + "integrity": "sha512-ADm/xt86JUnmAfA9mBqFcRp//RVRt1ohGOYF6yL+IFCYqOBNwy5lbEK05xTsEoJq+/tJzg8ICUtS82WinJRuIw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.4.tgz", + "integrity": "sha512-tJfJaXPiFAG+Jn3cutp7mCs1ePltuAgRqdDZrzb1aeE3TktWWJ+g7xK9SNlaSUFw6IU4QgOxAY4rA+wZUT5Wfg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.4.tgz", + "integrity": "sha512-7dy1BzQkgYlUTapDTvK997cgi0Orh5Iu7JlZVBy1MBURk7/HSbHkzRnXZa19ozy+wwD8/SlpJnOOckuNZtJR9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.4.tgz", + "integrity": "sha512-zsFwdUw5XLD1gQe0aoU2HVceI6NEW7q7m05wA46eUAyrkeNYExObfRFQcvA6zw8lfRc5BHtan3tBpo+kqEOxmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.4.tgz", + "integrity": "sha512-p8C3NnxXooRdNrdv6dBmRTddEapfESEUflpICDNKXpHvTjRRq1J82CbU5G3XfebIZyI3B0s074JHMWD36qOW6w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.4.tgz", + "integrity": "sha512-Lh/8ckoar4s4Id2foY7jNgitTOUQczwMWNYi+Mjt0eQ9LKhr6sK477REqQkmy8YHY3Ca3A2JJVdXnfb3Rrwkng==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.4.tgz", + "integrity": "sha512-1xwwn9ZCQYuqGmulGsTZoKrrn0z2fAur2ujE60QgyDpHmBbXbxLaQiEvzJWDrscRq43c8DnuHx3QorhMTZgisQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.4.tgz", + "integrity": "sha512-LuOGGKAJ7dfRtxVnO1i3qWc6N9sh0Em/8aZ3CezixSTM+E9Oq3OvTsvC4sm6wWjzpsIlOCnZjdluINKESflJLA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.4.tgz", + "integrity": "sha512-ch86i7KkJKkLybDP2AtySFTRi5fM3KXp0PnHocHuJMdZwu7BuyIKi35BE9guMlmTpwwBTB3ljHj9IQXnTCD0vA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.4.tgz", + "integrity": "sha512-Ma4PwyLfOWZWayfEsNQzTDBVW8PZ6TUUN1uFTBQbF2Chv/+sjenE86lpiEwj2FiviSmSZ4Ap4MaAfl1ciF4aSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.4.tgz", + "integrity": "sha512-9m/ZDrQsdo/c06uOlP3W9G2ENRVzgzbSXmXHT4hwVaDQhYcRpi9bgBT0FTG9OhESxwK0WjQxYOSfv40cU+T69w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.4.tgz", + "integrity": "sha512-YunpoOAyGLDseanENHmbFvQSfVL5BxW3k7hhy0eN4rb3gS/ct75dVD0EXOWIqFT/nE8XYW6LP6vz6ctKRi0k9A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.12", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "devOptional": true + }, + "node_modules/@types/react": { + "version": "18.2.79", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", + "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", + "devOptional": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", + "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "devOptional": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.747", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz", + "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.6.tgz", + "integrity": "sha512-NjGXdm7zgcKRkKMua34qVO9doI7VOxZ6ancSvBELJSSoX97jyndXcSoa8XBh69JoB31dNz3EEzlMcizZl7LaMA==", + "dev": true, + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", + "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/react-redux": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.1.tgz", + "integrity": "sha512-5ynfGDzxxsoV73+4czQM56qF43vsmgJsO22rmAvU5tZT2z5Xow/A2uhhxwXuGTxgdReF3zcp7A80gma2onRs1A==", + "dependencies": { + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25", + "react": "^18.0", + "react-native": ">=0.69", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.0.tgz", + "integrity": "sha512-wPMZ8S2TuPadH0sF5irFGjkNLIcRvOSaEe7v+JER8508dyJumm6XZB1u5kztlX0RVq6AzRVndzqcUh6sFIauzA==", + "dependencies": { + "@remix-run/router": "1.16.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.0.tgz", + "integrity": "sha512-Q9YaSYvubwgbal2c9DJKfx6hTNoBp3iJDsl+Duva/DwxoJH+OTXkxGpql4iUK2sla/8z4RpjAm6EWx1qUDuopQ==", + "dependencies": { + "@remix-run/router": "1.16.0", + "react-router": "6.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reselect": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz", + "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg==" + }, + "node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.16.4.tgz", + "integrity": "sha512-kuaTJSUbz+Wsb2ATGvEknkI12XV40vIiHmLuFlejoo7HtDok/O5eDDD0UpCVY5bBX5U5RYo8wWP83H7ZsqVEnA==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.16.4", + "@rollup/rollup-android-arm64": "4.16.4", + "@rollup/rollup-darwin-arm64": "4.16.4", + "@rollup/rollup-darwin-x64": "4.16.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.16.4", + "@rollup/rollup-linux-arm-musleabihf": "4.16.4", + "@rollup/rollup-linux-arm64-gnu": "4.16.4", + "@rollup/rollup-linux-arm64-musl": "4.16.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.16.4", + "@rollup/rollup-linux-riscv64-gnu": "4.16.4", + "@rollup/rollup-linux-s390x-gnu": "4.16.4", + "@rollup/rollup-linux-x64-gnu": "4.16.4", + "@rollup/rollup-linux-x64-musl": "4.16.4", + "@rollup/rollup-win32-arm64-msvc": "4.16.4", + "@rollup/rollup-win32-ia32-msvc": "4.16.4", + "@rollup/rollup-win32-x64-msvc": "4.16.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.1.tgz", + "integrity": "sha512-6MCBDr76UJmRpbF8pzP27uIoTocf3tITaMJ52mccgAhMJycuh5A/RL6mDZCTwTisj0Qfeq69FtjMCUX27U78oA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/vite": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.10.tgz", + "integrity": "sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==", + "dev": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..e2cb94d --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,30 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@reduxjs/toolkit": "^2.2.3", + "axios": "^1.6.8", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^9.1.1", + "react-router-dom": "^6.23.0" + }, + "devDependencies": { + "@types/react": "^18.2.66", + "@types/react-dom": "^18.2.22", + "@vitejs/plugin-react": "^4.2.1", + "eslint": "^8.57.0", + "eslint-plugin-react": "^7.34.1", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "vite": "^5.2.0" + } +} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 0000000..e7bc551 --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,20 @@ +import Header from "./components/Header/Header.jsx"; +import {Route, Routes} from "react-router-dom"; +import LoginForm from "./components/LoginForm/LoginForm.jsx"; +import React from "react"; + +function App() { + + return ( +
+
+
+ + }/> + +
+
+ ); +} + +export default App; diff --git a/frontend/src/components/Button/Button.css b/frontend/src/components/Button/Button.css new file mode 100644 index 0000000..29a3096 --- /dev/null +++ b/frontend/src/components/Button/Button.css @@ -0,0 +1,9 @@ +/*noinspection CssUnresolvedCustomProperty*/ +.button { + padding: 10px 15px; + background: var(--tg-theme-button-color); + color: var(--tg-theme-button-text-color); + border: none; + outline: none; + cursor: pointer; +} \ No newline at end of file diff --git a/frontend/src/components/Button/Button.jsx b/frontend/src/components/Button/Button.jsx new file mode 100644 index 0000000..c6b2e7c --- /dev/null +++ b/frontend/src/components/Button/Button.jsx @@ -0,0 +1,10 @@ +import './Button.css' + +const Button = (props) => { + return ( + // eslint-disable-next-line react/prop-types + + + {user?.username} + + + ) +} + +export default Header; \ No newline at end of file diff --git a/frontend/src/components/LoginForm/LoginForm.css b/frontend/src/components/LoginForm/LoginForm.css new file mode 100644 index 0000000..cc5ef75 --- /dev/null +++ b/frontend/src/components/LoginForm/LoginForm.css @@ -0,0 +1,49 @@ +.login-form { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + padding: 0 20px; + box-sizing: border-box; + margin: 0 auto; +} + +.login-form form { + display: flex; + flex-direction: column; + align-items: center; + background-color: #000000; + padding: 20px; + border-radius: 5px; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); +} + +.login-form label { + margin-bottom: 5px; + font-weight: bold; +} + +.login-form input { + margin-bottom: 15px; + padding: 5px; + border: 1px solid #ccc; + border-radius: 3px; +} + +.login-form button { + padding: 10px 20px; + background-color: #007BFF; + color: white; + border: none; + border-radius: 3px; + cursor: pointer; + transition: background-color 0.3s; +} + +.login-form button:hover { + background-color: #0056b3; +} + +.login-form__label { + margin-right: 20px; +} diff --git a/frontend/src/components/LoginForm/LoginForm.jsx b/frontend/src/components/LoginForm/LoginForm.jsx new file mode 100644 index 0000000..148771b --- /dev/null +++ b/frontend/src/components/LoginForm/LoginForm.jsx @@ -0,0 +1,56 @@ +import "./LoginForm.css" +import React, {useCallback, useEffect} from "react"; +import {useTelegram} from "../../hooks/UseTelegram.js"; + + +const LoginForm = () => { + + const [data, setData] = React.useState({login: "", password: ""}); + const {tg} = useTelegram(); + const handleData = (e, name) => { + setData({...data, [name]: e.target.value}); + } + + const onSendData = useCallback(() => { + tg.sendData(JSON.stringify(data)) + }, [tg, data]) + useEffect(() => { + tg.onEvent("mainButtonClicked", onSendData) + return () => { + tg.offEvent("mainButtonClicked", onSendData) + } + }, [tg, onSendData]) + + useEffect(() => { + tg.MainButton.setParams( + {text: 'Войти'} + ) + }, [tg]) + + useEffect(() => { + if (data.login === "" && data.password === "") { + tg.MainButton.hide(); + } else { + tg.MainButton.show(); + } + }) + + return ( +
+
+
+ + handleData(e, "login")}/> +
+
+ + handleData(e, "password")}/> +
+
+
+ ) +} + +export default LoginForm; diff --git a/frontend/src/configs/AxiosConfig.js b/frontend/src/configs/AxiosConfig.js new file mode 100644 index 0000000..f186c91 --- /dev/null +++ b/frontend/src/configs/AxiosConfig.js @@ -0,0 +1,48 @@ +import axios from "axios"; + +axios.defaults.withCredentials = true; + +// eslint-disable-next-line no-undef +const app = axios.create({ + withCredentials: true, + headers: { + "accept": "application/json", + "Content-Type": "application/x-www-form-urlencoded", + } +}); + +export const appJSON = axios.create({ + withCredentials: true, + headers: { + "accept": "application/json", + "Content-Type": "application/json", + } +}); + +export const appFiles = axios.create({ + withCredentials: true, + headers: { + "accept": "application/json", + "Content-Type": "multipart/form-data" + } +}); + + +app.interceptors.request.use((config) => { + return config; +}); + +/* + The below is required if you want your API to return + server message errors. Otherwise, you'll just get + generic status errors. + + If you use the interceptor below, then make sure you + return an "err" (or whatever you decide to name it) message + from your express route: + + res.status(404).json({ err: "You are not authorized to do that." }) + +*/ + +export default app; \ No newline at end of file diff --git a/frontend/src/hooks/UseTelegram.js b/frontend/src/hooks/UseTelegram.js new file mode 100644 index 0000000..226d724 --- /dev/null +++ b/frontend/src/hooks/UseTelegram.js @@ -0,0 +1,22 @@ +export function useTelegram() { + const tg = window.Telegram.WebApp; + const onClose = () => { + tg.close(); + }; + + const onToggleButton = () => { + if (tg.MainButton.isVisible) { + tg.MainButton.hide(); + } else { + tg.MainButton.show(); + } + }; + + return { + onClose, + onToggleButton, + tg, + user: tg.initDataUnsafe?.user, + }; + +} \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..be3d26c --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,93 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 100vw; + min-height: 100vh; + width: 100%; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +button:hover { + border-color: #646cff; +} + +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + + a:hover { + color: #747bff; + } + + button { + background-color: #f9f9f9; + } +} + +.login { + display: flex; + flex-direction: column; + align-items: center; + margin: 0 auto; + gap: 280px; +} + +.App { + min-width: 100vw; + min-height: 100vh; +} diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx new file mode 100644 index 0000000..c4414ad --- /dev/null +++ b/frontend/src/main.jsx @@ -0,0 +1,13 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.jsx' +import './index.css' +import {BrowserRouter} from "react-router-dom" + +ReactDOM.createRoot(document.getElementById('root')).render( + + + + + , +); diff --git a/frontend/vite.config.js b/frontend/vite.config.js new file mode 100644 index 0000000..5a33944 --- /dev/null +++ b/frontend/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/functions/dating/__init__.py b/functions/dating/__init__.py deleted file mode 100644 index 1f89ce8..0000000 --- a/functions/dating/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .reaction_strategies import ( - ChooseReportReason, - DislikeAction, - DislikeReciprocity, - GoBackToViewing, - LikeAction, - LikeReciprocity, - SendReport, - StartFindingFailure, - StartFindingReachLimit, - StartFindingSuccess, - StoppedAction, -) diff --git a/functions/dating/get_next_user_func.py b/functions/dating/get_next_user_func.py deleted file mode 100644 index 219eff7..0000000 --- a/functions/dating/get_next_user_func.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import ( - List, -) - -from async_lru import ( - alru_cache, -) - -from utils.db_api import ( - db_commands, -) - - -@alru_cache -async def get_next_user( - telegram_id: int, monitoring: bool = False, offset: int = 0, limit: int = 100 -) -> List[int]: - user = await db_commands.select_user_object(telegram_id=telegram_id) - viewed_profiles = user.viewed_profiles.all() - - if monitoring: - user_filter = await db_commands.search_users_all(offset, limit) - else: - user_filter = await db_commands.search_users( - user.need_partner_sex, - user.need_partner_age_min, - user.need_partner_age_max, - user.need_city, - offset, - limit, - ) - - viewed_profiles_ids = [profile.telegram_id for profile in viewed_profiles] - - user_list = [] - for i in user_filter: - if ( - int(i["telegram_id"]) != int(telegram_id) - and i["telegram_id"] not in viewed_profiles_ids - ): - user_list.append(i["telegram_id"]) - - if not user_list: - user_filter_2 = await db_commands.search_users_all(offset, limit) - for k in user_filter_2: - if ( - k not in user_filter - and int(k["telegram_id"]) != int(telegram_id) - and k["telegram_id"] not in viewed_profiles_ids - ): - user_list.append(k["telegram_id"]) - - return user_list diff --git a/functions/dating/reaction_strategies.py b/functions/dating/reaction_strategies.py deleted file mode 100644 index b3c1573..0000000 --- a/functions/dating/reaction_strategies.py +++ /dev/null @@ -1,252 +0,0 @@ -from abc import ( - ABC, - abstractmethod, -) -import asyncio -import random -import secrets - -from aiogram.dispatcher import ( - FSMContext, -) -from aiogram.types import ( - CallbackQuery, -) - -from data.config import ( - load_config, -) -from functions.dating.create_forms_funcs import ( - create_questionnaire, - create_questionnaire_reciprocity, - rand_user_list, -) -from functions.dating.get_next_user_func import ( - get_next_user, -) -from functions.main_app.auxiliary_tools import ( - get_report_reason, -) -from keyboards.inline.main_menu_inline import ( - start_keyboard, -) -from keyboards.inline.questionnaires_inline import ( - report_menu_keyboard, - user_link_keyboard, -) -from loader import ( - _, - bot, -) -from utils.db_api import ( - db_commands, -) - - -class ActionStrategy(ABC): - @abstractmethod - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - pass - - -class StartFindingSuccess(ActionStrategy): - async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): - await call.message.delete() - telegram_id = call.from_user.id - user_list = await get_next_user(telegram_id) - random_user = random.choice(user_list) - await create_questionnaire(form_owner=random_user, chat_id=telegram_id) - await state.set_state("finding") - - -class StartFindingFailure(ActionStrategy): - async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): - await call.answer(_("На данный момент у нас нет подходящих анкет для вас")) - - -class StartFindingReachLimit(ActionStrategy): - async def execute(self, call: CallbackQuery, state: FSMContext, **kwargs): - await call.answer( - text=_("У вас достигнут лимит на просмотры анкет"), show_alert=True - ) - - -class LikeAction(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - user = await db_commands.select_user_object(telegram_id=call.from_user.id) - text = _("Кому-то понравилась твоя анкета") - target_id = int(callback_data["target_id"]) - - await create_questionnaire( - form_owner=call.from_user.id, chat_id=target_id, add_text=text - ) - - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=None, - ) - - await db_commands.update_user_data( - telegram_id=call.from_user.id, limit_of_views=user.limit_of_views - 1 - ) - await create_questionnaire( - form_owner=(await rand_user_list(call)), chat_id=call.from_user.id - ) - - await state.reset_data() - - -class DislikeAction(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=None, - ) - await create_questionnaire( - form_owner=(await rand_user_list(call)), chat_id=call.from_user.id - ) - await state.reset_data() - - -class StoppedAction(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - text = _( - "Рад был помочь, {fullname}!\nНадеюсь, ты нашел кого-то благодаря мне" - ).format(fullname=call.from_user.full_name) - await call.answer(text, show_alert=True) - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=await start_keyboard(call), - ) - await state.reset_state() - - -class LikeReciprocity(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - user_for_like = int(callback_data["user_for_like"]) - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=None, - ) - await call.message.answer( - text=_("Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉"), - reply_markup=await user_link_keyboard(telegram_id=user_for_like), - ) - await create_questionnaire_reciprocity( - liker=call.from_user.id, chat_id=user_for_like, add_text="" - ) - await bot.send_message( - chat_id=user_for_like, - text="Есть взаимная симпатия! Начиная общаться 👉", - reply_markup=await user_link_keyboard(telegram_id=call.from_user.id), - ) - await state.reset_state() - - -class DislikeReciprocity(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=await start_keyboard(call), - ) - await state.reset_state() - - -class GoBackToViewing(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=None, - ) - - user_list = await get_next_user(call.from_user.id) - random_user = secrets.choice(user_list) - await state.set_state("finding") - try: - await create_questionnaire( - form_owner=random_user, chat_id=call.from_user.id - ) - await state.reset_data() - except IndexError: - await call.answer(_("На данный момент у нас нет подходящих анкет для вас")) - await state.reset_data() - - -class ChooseReportReason(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - await state.reset_state() - await bot.edit_message_reply_markup( - chat_id=call.from_user.id, - message_id=call.message.message_id, - reply_markup=None, - ) - target_id = int(callback_data["target_id"]) - await call.message.answer( - text=_("Выберите причину жалобы:"), - reply_markup=await report_menu_keyboard(telegram_id=target_id), - ) - - -class SendReport(ActionStrategy): - async def execute( - self, call: CallbackQuery, state: FSMContext, callback_data: dict[str, str] - ): - target_id = int(callback_data["target_id"]) - target_user = await db_commands.select_user(telegram_id=target_id) - - counter_of_report = target_user.counter_of_report - username = call.from_user.username - user_id = call.from_user.id - report_reason = await get_report_reason(call) - - text = _( - "Жалоба от пользователя: [@{username} | {tg_id}]\n\n" - "На пользователя: [{owner_id}]\n" - "Причина жалобы: {reason}\n" - "Количество жалоб на пользователя: {counter_of_report}" - ).format( - username=username, - tg_id=user_id, - owner_id=target_id, - reason=report_reason, - counter_of_report=counter_of_report, - ) - - await db_commands.update_user_data( - telegram_id=target_id, counter_of_report=counter_of_report + 1 - ) - - moderate_chat = load_config().tg_bot.moderate_chat - if counter_of_report >= 5 and not target_user.on_check_by_admin: - await db_commands.update_user_data( - telegram_id=target_id, on_check_by_admin=True - ) - await create_questionnaire( - form_owner=target_id, - chat_id=moderate_chat, - report_system=True, - add_text=text, - ) - await asyncio.sleep(0.5) diff --git a/functions/dating/send_form_func.py b/functions/dating/send_form_func.py deleted file mode 100644 index 37b76a2..0000000 --- a/functions/dating/send_form_func.py +++ /dev/null @@ -1,134 +0,0 @@ -from typing import ( - Optional, -) - -from aiogram.types import ( - InlineKeyboardMarkup, -) -from aiogram.utils.exceptions import ( - BadRequest, -) - -from keyboards.admin.inline.customers import ( - user_blocking_keyboard, -) -from keyboards.inline.questionnaires_inline import ( - questionnaires_keyboard, - reciprocity_keyboard, -) -from loader import ( - _, - bot, - logger, -) -from utils.db_api import ( - db_commands, -) - - -async def send_questionnaire( - chat_id: int, - owner_id: Optional[int] = None, - markup: Optional[InlineKeyboardMarkup] = None, - add_text: Optional[str] = None, - monitoring: bool = False, - report_system: bool = False, -) -> None: - user = await db_commands.select_user(owner_id) - text_template = _("{}, {} лет, {} {verification}\n\n") - user_verification = "✅" if user.verification else "" - - text_without_inst = _(text_template + "{commentary}").format( - user.varname, - user.age, - user.city, - commentary=user.commentary, - verification=user_verification, - ) - - text_with_inst_template = text_template + _( - "Инстаграм - {instagram}\n" - ) - text_with_inst = _(text_with_inst_template).format( - user.varname, - user.age, - user.city, - user.commentary, - verification=user_verification, - instagram=user.instagram, - ) - - caption_with_add_text = _("{}\n\n" + text_template + "{}").format( - add_text, - user.varname, - user.age, - user.city, - user.commentary, - verification=user_verification, - ) - - add_text_with_inst = _( - "{}\n\n" + text_template + "Инстаграм - {instagram}\n" - ).format( - add_text, - user.varname, - user.age, - user.city, - user.commentary, - verification=user_verification, - instagram=user.instagram, - ) - try: - if add_text is None and user.instagram is None: - await bot.send_photo( - chat_id=chat_id, - caption=text_without_inst, - photo=user.photo_id, - reply_markup=await questionnaires_keyboard( - target_id=owner_id, monitoring=monitoring - ), - ) - elif add_text is None: - await bot.send_photo( - chat_id=chat_id, - caption=text_with_inst, - photo=user.photo_id, - reply_markup=await questionnaires_keyboard( - target_id=owner_id, monitoring=monitoring - ), - ) - elif markup is None and user.instagram is None: - await bot.send_photo( - chat_id=chat_id, - caption=caption_with_add_text, - photo=user.photo_id, - ) - elif markup is None: - await bot.send_photo( - chat_id=chat_id, caption=add_text_with_inst, photo=user.photo_id - ) - elif user.instagram is None and not report_system: - await bot.send_photo( - chat_id=chat_id, - caption=caption_with_add_text, - photo=user.photo_id, - reply_markup=await reciprocity_keyboard(user_for_like=owner_id), - ) - elif report_system: - await bot.send_photo( - chat_id=chat_id, - caption=add_text, - photo=user.photo_id, - reply_markup=await user_blocking_keyboard( - user_id=owner_id, is_banned=user.is_banned - ), - ) - else: - await bot.send_photo( - chat_id=chat_id, - caption=add_text_with_inst, - photo=user.photo_id, - reply_markup=await reciprocity_keyboard(user_for_like=owner_id), - ) - except BadRequest as err: - logger.info(f"{err}. Error in the send_questionnaire function") diff --git a/functions/event/__init__.py b/functions/event/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/functions/event/extra_features.py b/functions/event/extra_features.py deleted file mode 100644 index d04ef07..0000000 --- a/functions/event/extra_features.py +++ /dev/null @@ -1,124 +0,0 @@ -from datetime import ( - datetime, -) -from typing import ( - List, - Optional, - Union, -) - -from aiogram.types import ( - CallbackQuery, -) -from aiogram.utils.exceptions import ( - BadRequest, -) - -from functions.event.templates_messages import ( - ME, -) -from loader import ( - _, - bot, -) -from utils.db_api import ( - db_commands, -) - - -async def add_events_to_user(call: CallbackQuery, event_id: int) -> None: - """Function that stores id's of events liked by a user.""" - user = await db_commands.select_user(telegram_id=call.from_user.id) - event_list = user.events - - if str(event_id) not in event_list: - await db_commands.update_user_events( - telegram_id=call.from_user.id, events_id=event_id - ) - - -async def check_availability_on_event() -> bool: - """Function that checks the availability of seats for an event.""" - ... - - -async def check_event_date(telegram_id: int) -> None: - """Function that checks whether an event has passed or not.""" - event = await db_commands.select_user_meetings(telegram_id) - event_time = event.time_event - if event_time is None: - return - event_datetime, now_datetime = ( - datetime.strptime(event_time, "%d-%m-%Y"), - datetime.now().date(), - ) - is_admin = True - verification_status = True - is_active = True - - if event_datetime.date() <= now_datetime: - is_admin = False - verification_status = False - is_active = False - await db_commands.update_user_meetings_data( - telegram_id=telegram_id, - is_admin=is_admin, - verification_status=verification_status, - is_active=is_active, - ) - - -async def create_form( - form_owner: int, chat_id: int, call: CallbackQuery, view: Union[bool, None] = True -) -> None: - """Function that fills the form with text.""" - try: - owner = await db_commands.select_user_meetings(telegram_id=form_owner) - document = { - "title": owner.event_name, - "date": owner.time_event, - "place": owner.venue, - "description": owner.commentary, - "photo_id": owner.photo_id, - "telegram_id": form_owner, - } - if view: - await ME.send_event_message( - text=document, bot=bot, chat_id=chat_id, view_event=True, call=call - ) - else: - await ME.send_event_list( - text=document, call=call, bot=bot, telegram_id=call.from_user.id - ) - except BadRequest: - await call.answer( - text=_("На данный момент у нас нет подходящих мероприятий для вас"), - show_alert=True, - ) - - -async def get_next_random_event_id(telegram_id: int) -> Optional[int]: - """Function that returns a random id of an event created by another user.""" - event_ids = await db_commands.search_event_forms() - - other_events_ids = [] - for e in event_ids: - if e["telegram_id"] != telegram_id: - other_events_ids.append(e["telegram_id"]) - - for event_id in other_events_ids: - if not await db_commands.check_returned_event_id( - telegram_id=telegram_id, id_of_events_seen=event_id - ): - await db_commands.add_returned_event_id( - telegram_id=telegram_id, id_of_events_seen=event_id - ) - return event_id - - raise ValueError("No more event ids") - - -async def get_next_registration(telegram_id: int) -> List[int]: - user = await db_commands.select_user(telegram_id=telegram_id) - events: list = user.events - return events diff --git a/functions/main_app/__init__.py b/functions/main_app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/functions/main_app/auxiliary_tools.py b/functions/main_app/auxiliary_tools.py deleted file mode 100644 index 9f46361..0000000 --- a/functions/main_app/auxiliary_tools.py +++ /dev/null @@ -1,403 +0,0 @@ -import asyncio -from contextlib import ( - suppress, -) -import datetime -import os -import pathlib -import random -import re -import shutil -from typing import ( - Optional, - Union, -) - -import aiofiles -from aiogram import ( - types, -) -from aiogram.dispatcher import ( - FSMContext, -) -from aiogram.types import ( - CallbackQuery, - InlineKeyboardMarkup, - InputFile, - Message, - ReplyKeyboardRemove, -) -from aiogram.utils.exceptions import ( - BadRequest, - MessageCantBeDeleted, - MessageToDeleteNotFound, -) -from asyncpg import ( - UniqueViolationError, -) - -from data.config import ( - load_config, -) -from functions.main_app.app_scheduler import ( - send_message_week, -) -from keyboards.inline.filters_inline import ( - dating_filters_keyboard, -) -from keyboards.inline.guide_inline import ( - create_pagination_keyboard, -) -from keyboards.inline.main_menu_inline import ( - start_keyboard, -) -from keyboards.inline.settings_menu import ( - information_keyboard, -) -from loader import ( - _, - bot, - logger, - scheduler, -) -from utils.db_api import ( - db_commands, -) -from utils.db_api.db_commands import ( - check_user_meetings_exists, -) - - -async def delete_message(message: Message) -> None: - with suppress(MessageCantBeDeleted, MessageToDeleteNotFound): - await message.delete() - - -async def choice_gender(call: CallbackQuery) -> None: - """Function that saves to the database the gender that the user has selected.""" - sex_mapping = {"male": "Мужской", "female": "Женский"} - - selected_sex = sex_mapping.get(call.data) - - if selected_sex: - try: - await db_commands.update_user_data( - telegram_id=call.from_user.id, need_partner_sex=selected_sex - ) - except UniqueViolationError: - pass - - -async def display_profile(call: CallbackQuery, markup: InlineKeyboardMarkup) -> None: - """Function for displaying the user profile.""" - user = await db_commands.select_user(telegram_id=call.from_user.id) - count_referrals = await db_commands.count_all_users_kwarg( - referrer_id=call.from_user.id - ) - user_verification = "✅" if user.verification else "" - - user_info_template = _( - "{name}, {age} лет, {city}, {verification}\n\n{commentary}\n\n" - "Партнерка:\nКоличество приглашенных друзей: {reff}\nРеферальная ссылка:\n {link}" - ) - info = await bot.get_me() - user_info = user_info_template.format( - name=user.varname, - age=user.age, - city=user.city, - verification=user_verification, - commentary=user.commentary, - reff=count_referrals, - link=f"https://t.me/{info.username}?start={call.from_user.id}", - ) - - await call.message.answer_photo( - caption=user_info, photo=user.photo_id, reply_markup=markup - ) - - -async def show_dating_filters(obj: Union[CallbackQuery, Message]) -> None: - user_id = obj.from_user.id - user = await db_commands.select_user(telegram_id=user_id) - markup = await dating_filters_keyboard() - - text = _( - "Фильтр по подбору партнеров:\n\n" - "🚻 Необходимы пол партнера: {}\n" - "🔞 Возрастной диапазон: {}-{} лет\n\n" - "🏙️ Город партнера: {}" - ).format( - user.need_partner_sex, - user.need_partner_age_min, - user.need_partner_age_max, - user.need_city, - ) - try: - await obj.message.edit_text(text, reply_markup=markup) - except AttributeError: - await obj.answer(text, reply_markup=markup) - - -async def registration_menu( - obj: Union[CallbackQuery, Message], -) -> None: - support = await db_commands.select_user( - telegram_id=load_config().tg_bot.support_ids[0] - ) - markup = await start_keyboard(obj) - heart = random.choice(["💙", "💚", "💛", "🧡", "💜", "🖤", "❤", "🤍", "💖", "💝"]) - text = _( - "Приветствую вас, {fullname}!!\n\n" - "{heart} Querendo - платформа для поиска новых знакомств.\n\n" - "🪧 Новости о проекте вы можете прочитать в нашем канале - " - "https://t.me/que_group \n\n" - "🤝 Сотрудничество: \n" - "Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " - "@{supports}\n\n" - ).format(fullname=obj.from_user.full_name, heart=heart, supports=support.username) - try: - await obj.message.edit_text(text=text, reply_markup=markup) - scheduler.add_job( - send_message_week, - trigger="interval", - weeks=1, - jitter=120, - args={obj.message}, - ) - except AttributeError: - await obj.answer(text=text, reply_markup=markup) - scheduler.add_job( - send_message_week, trigger="interval", weeks=1, jitter=120, args={obj} - ) - except BadRequest: - await delete_message(obj.message) - - await obj.message.answer(text=text, reply_markup=markup) - - -async def check_user_in_db(telegram_id: int, message: Message, username: str) -> None: - if not await db_commands.check_user_exists( - telegram_id - ) and not await check_user_meetings_exists(telegram_id): - user = await db_commands.select_user_object(telegram_id=telegram_id) - referrer_id = message.text[7:] - if referrer_id != "" and referrer_id != telegram_id: - await db_commands.add_user( - name=message.from_user.full_name, - telegram_id=telegram_id, - username=username, - referrer_id=referrer_id, - ) - await db_commands.update_user_data( - telegram_id=telegram_id, limit_of_views=user.limit_of_views + 15 - ) - await bot.send_message( - chat_id=referrer_id, - text=_( - "По вашей ссылке зарегистрировался пользователь {}!\n" - "Вы получаете дополнительных 15 ❤️" - ).format(message.from_user.username), - ) - else: - await db_commands.add_user( - name=message.from_user.full_name, - telegram_id=telegram_id, - username=username, - ) - await db_commands.add_meetings_user(telegram_id=telegram_id, username=username) - if telegram_id in load_config().tg_bot.admin_ids: - await db_commands.add_user_to_settings(telegram_id=telegram_id) - - -async def finished_registration( - state: FSMContext, telegram_id: int, message: Message -) -> None: - await state.finish() - await db_commands.update_user_data(telegram_id=telegram_id, status=True) - - user = await db_commands.select_user(telegram_id=telegram_id) - - markup = await start_keyboard(obj=message) - - text = _( - "Регистрация успешно завершена! \n\n " - "{}, " - "{} лет, " - "{}\n\n" - "О себе - {}" - ).format(user.varname, user.age, user.city, user.commentary) - - await message.answer_photo(caption=text, photo=user.photo_id, reply_markup=markup) - - -async def saving_normal_photo( - message: Message, telegram_id: int, file_id: str, state: FSMContext -) -> None: - """Функция, сохраняющая фотографию пользователя без цензуры.""" - try: - await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) - - await message.answer( - text=_("Фото принято!"), reply_markup=ReplyKeyboardRemove() - ) - except Exception as err: - logger.info(f"Ошибка в saving_normal_photo | err: {err}") - await message.answer( - text=_( - "Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" - "Если ошибка осталась, напишите агенту поддержки." - ) - ) - await finished_registration(state=state, telegram_id=telegram_id, message=message) - - -async def saving_censored_photo( - message: Message, - telegram_id: int, - state: FSMContext, - out_path: Union[str, pathlib.Path], - flag: Optional[str] = "registration", - markup: Union[InlineKeyboardMarkup, None] = None, -) -> None: - """.Функция, сохраняющая фотографию пользователя с цензурой.""" - photo = InputFile(out_path) - id_photo = await bot.send_photo( - chat_id=telegram_id, - photo=photo, - caption=_( - "Во время проверки вашего фото мы обнаружили подозрительный контент!\n" - "Поэтому мы чуть-чуть подкорректировали вашу фотографию" - ), - ) - file_id = id_photo["photo"][0]["file_id"] - await asyncio.sleep(1) - try: - await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) - - except Exception as err: - logger.info(f"Ошибка в saving_censored_photo | err: {err}") - await message.answer( - text=_( - "Произошла ошибка!" - " Попробуйте еще раз либо отправьте другую фотографию. \n" - "Если ошибка осталась, напишите агенту поддержки." - ) - ) - if flag == "change_datas": - await message.answer( - text=_("Фото принято!\n" "Выберите, что вы хотите изменить: "), - reply_markup=markup, - ) - await state.reset_state() - elif flag == "registration": - await finished_registration( - state=state, telegram_id=telegram_id, message=message - ) - - -async def update_normal_photo( - message: Message, - telegram_id: int, - file_id: str, - state: FSMContext, - markup -) -> None: - """Функция, которая обновляет фотографию пользователя.""" - try: - await db_commands.update_user_data(telegram_id=telegram_id, photo_id=file_id) - await message.answer( - text=_("Фото принято!"), reply_markup=ReplyKeyboardRemove() - ) - await asyncio.sleep(3) - await message.answer( - text=_("Выберите, что вы хотите изменить: "), reply_markup=markup - ) - await state.reset_state() - except Exception as err: - logger.info(f"Ошибка в update_normal_photo | err: {err}") - await message.answer( - text=_( - "Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" - "Если ошибка осталась, напишите агенту поддержки." - ) - ) - - -async def dump_users_to_file(): - async with aiofiles.open("users.txt", "w", encoding="utf-8") as file: - _text = "" - _users = await db_commands.select_all_users() - for user in _users: - _text += str(user) + "\n" - - await file.write(_text) - - return "users.txt" - - -async def backup_configs(): - shutil.make_archive("backup_data", "zip", "./logs/") - return "./backup_data.zip" - - -async def send_photo_with_caption( - call: CallbackQuery, - photo: str, - caption: str, - step: int, - total_steps: int, -) -> None: - markup = await create_pagination_keyboard(step, total_steps) - - await call.message.delete() - await call.message.answer_photo( - types.InputFile(photo), reply_markup=markup, caption=caption - ) - - -async def handle_guide_callback( - call: CallbackQuery, - callback_data: dict, -) -> None: - step = int(callback_data.get("value")) - - photo_path = f"brandbook/{step}_page.png" - caption = _("Руководство по боту: \nСтраница №{}").format(step) - await send_photo_with_caption( - call=call, - photo=photo_path, - caption=caption, - step=step, - total_steps=len(os.listdir("brandbook/")), - ) - - -async def information_menu(call: CallbackQuery) -> None: - start_date = datetime.datetime(2021, 8, 10, 14, 0) - now_date = datetime.datetime.now() - delta = now_date - start_date - count_users = await db_commands.count_users() - markup = await information_keyboard() - txt = _( - "Вы попали в раздел Информации бота, здесь вы можете посмотреть: статистику," - "изменить язык, а также посмотреть наш брендбук.\n\n" - "🌐 Дней работаем: {}\n" - "👤 Всего пользователей: {}\n" - ).format(delta.days, count_users) - try: - await call.message.edit_text(text=txt, reply_markup=markup) - except BadRequest: - await delete_message(call.message) - await call.message.answer(text=txt, reply_markup=markup) - - -async def get_report_reason(call: CallbackQuery) -> str: - match = re.search(r"report:(.*?):", call.data) - reason_key = match.group(1) - reason_mapping = { - "adults_only": "🔞 Развратный контент", - "drugs": "💊 Продажа наркотиков", - "scam": "💰 Мошенничество", - "another": "🦨 Другая причина", - } - return reason_mapping.get(reason_key, "Неизвестная причина") diff --git a/handlers/__init__.py b/handlers/__init__.py deleted file mode 100644 index 5ca811f..0000000 --- a/handlers/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from . import ( - errors, - admins, - groups, - users, - echo_handler, -) diff --git a/handlers/admins/advert/ref/__init__.py b/handlers/admins/advert/ref/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/handlers/admins/advert/requiredsub/__init__.py b/handlers/admins/advert/requiredsub/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/justfile b/justfile index 09527a4..0ecdc95 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,4 @@ -set shell := ["powershell.exe", "-c"] +# set shell := ["powershell.exe", "-c"] # Show help message PHONY: help @@ -27,7 +27,14 @@ isort: @echo "🔄 Running isort..." @poetry run isort $(git ls-files '*.py') +black: + @poetry run black $(git ls-files '*.py') + # Audit packages audit: @echo "🔍 Auditing packages..." - @pip-audit . \ No newline at end of file + @pip-audit . + +# Run pre-commit lint +lint: + @pre-commit run --all-files diff --git a/keyboards/__init__.py b/keyboards/__init__.py deleted file mode 100644 index fd9825f..0000000 --- a/keyboards/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from . import ( - default, - inline, -) diff --git a/keyboards/admin/__init__.py b/keyboards/admin/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/keyboards/admin/inline/__init__.py b/keyboards/admin/inline/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/keyboards/default/__init__.py b/keyboards/default/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/keyboards/inline/__init__.py b/keyboards/inline/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/loader.py b/loader.py deleted file mode 100644 index e5d12bd..0000000 --- a/loader.py +++ /dev/null @@ -1,52 +0,0 @@ -import logging -from typing import ( - Any, -) - -from aiogram import ( - Bot, - Dispatcher, - types, -) -from aiogram.contrib.fsm_storage.memory import ( - MemoryStorage, -) -from aiogram.contrib.fsm_storage.redis import ( - RedisStorage2, -) -from apscheduler.schedulers.asyncio import ( - AsyncIOScheduler, -) -from nudenet import ( - NudeDetector, -) - -from data.config import ( - load_config, -) -from functions.main_app.language_ware import ( - setup_middleware, -) -from utils.YandexMap.api import ( - Client, -) - -from utils.yoomoney import ( - YooMoneyWallet, -) - -bot = Bot(token=load_config().tg_bot.token, parse_mode=types.ParseMode.HTML) -storage = RedisStorage2() if load_config().tg_bot.use_redis else MemoryStorage() -dp = Dispatcher(bot, storage=storage) -client = Client(api_key=load_config().misc.yandex_api_key) -job_defaults = dict(coalesce=False, max_instances=3) -scheduler = AsyncIOScheduler( - timezone=load_config().tg_bot.timezone, job_defaults=job_defaults -) -wallet = YooMoneyWallet(access_token=load_config().misc.yoomoney_key) -detector = NudeDetector() - -i18n = setup_middleware(dp) -_: Any = i18n.gettext - -logger = logging.getLogger(__name__) diff --git a/locales/de/LC_MESSAGES/dating.po b/locales/de/LC_MESSAGES/dating.po deleted file mode 100644 index ef04a6b..0000000 --- a/locales/de/LC_MESSAGES/dating.po +++ /dev/null @@ -1,1418 +0,0 @@ -# German translations for PROJECT. -# Copyright (C) 2022 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2022. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-08-28 14:39+0300\n" -"PO-Revision-Date: 2023-08-24 00:07+0300\n" -"Last-Translator: \n" -"Language: de_ID\n" -"Language-Team: id_ID \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" - -#: functions/dating/reaction_strategies.py:46 -#: functions/dating/reaction_strategies.py:171 -msgid "На данный момент у нас нет подходящих анкет для вас" -msgstr "Wir haben derzeit keine geeigneten Profile für Sie" - -#: functions/dating/reaction_strategies.py:52 -msgid "У вас достигнут лимит на просмотры анкет" -msgstr "Sie haben Ihr Limit an Profilansichten erreicht" - -#: functions/dating/reaction_strategies.py:61 -msgid "Кому-то понравилась твоя анкета" -msgstr "Ihr Profil hat jemandem gefallen" - -#: functions/dating/reaction_strategies.py:103 handlers/users/view_event.py:51 -msgid "" -"Рад был помочь, {fullname}!\n" -"Надеюсь, ты нашел кого-то благодаря мне" -msgstr "" -"Es war mir eine Freude, {fullname} zu helfen!\n" -"Ich hoffe, Sie haben jemanden dank mir gefunden" - -#: functions/dating/reaction_strategies.py:126 -msgid "Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉" -msgstr "Toll! Ich hoffe, du hast eine gute Zeit ;) Chatten beginnen 👉" - -#: functions/dating/reaction_strategies.py:187 -msgid "Выберите причину жалобы:" -msgstr "" - -#: functions/dating/reaction_strategies.py:204 -msgid "" -"Жалоба от пользователя: [@{username} | {tg_id}]" -"\n" -"\n" -"На пользователя: [{owner_id}]\n" -"Причина жалобы: {reason}\n" -"Количество жалоб на пользователя: {counter_of_report}" -msgstr "" - -#: functions/dating/send_form_func.py:25 -msgid "" -"{}, {} лет, {} {verification}\n" -"\n" -msgstr "" -"{}, {} Jahre, {} {verification}\n" -"\n" - -#: functions/dating/send_form_func.py:28 -msgid "{commentary}" -msgstr "{commentary}" - -#: functions/dating/send_form_func.py:36 -msgid "Инстаграм - {instagram}\n" -msgstr "instagram - {instagram}\n" - -#: functions/dating/send_form_func.py:48 -msgid "" -"{}\n" -"\n" -"{}" -msgstr "" -"{}\n" -"\n" -"{}" - -#: functions/dating/send_form_func.py:57 -msgid "" -"{}\n" -"\n" -"Инстаграм - {instagram}\n" -msgstr "" -"{}\n" -"\n" -"Instagram - {instagram}\n" - -#: functions/event/extra_features.py:86 -msgid "На данный момент у нас нет подходящих мероприятий для вас" -msgstr "Derzeit haben wir keine passenden Veranstaltungen für Sie" - -#: functions/event/templates_messages.py:17 -msgid "" -"{} \n" -"Когда: {} \n" -"Где: {} \n" -"\n" -"{}" -msgstr "" -"{} \n" -"Wann: {} \n" -"Ort: {} \n" -"\n" -"{}" - -#: functions/main_app/app_scheduler.py:12 -msgid "Несколько {} из города {} хотят познакомиться с тобой прямо сейчас" -msgstr "Mehrere {} aus der Stadt {} möchten Sie jetzt treffen" - -#: functions/main_app/auxiliary_tools.py:71 -msgid "" -"{name}, {age} лет, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Партнерка:\n" -"Количество приглашенных друзей: {reff}\n" -"Реферальная ссылка:\n" -" {link}" -msgstr "" -"{name}, {age} Jahre, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Partner:.\n" -"Anzahl der eingeladenen Freunde: {reff}\n" -"Empfehlungslink:\n" -" {link}" - -#: functions/main_app/auxiliary_tools.py:96 -msgid "" -"Фильтр по подбору партнеров:\n" -"\n" -"🚻 Необходимы пол партнера: {}\n" -"🔞 Возрастной диапазон: {}-{} лет\n" -"\n" -"🏙️ Город партнера: {}" -msgstr "" -"Filter nach Partnerauswahl:\n" -"\n" -"🚻 Geschlecht des Partners erforderlich: {}\n" -"🔞 Altersbereich: {}-{} Jahre alt\n" -"\n" -"🏙️ Partnerstadt: {}" - -#: functions/main_app/auxiliary_tools.py:121 -msgid "" -"Приветствую вас, {fullname}!!\n" -"\n" -"{heart} QueDateBot - платформа для поиска новых знакомств.\n" -"\n" -"🪧 Новости о проекте вы можете прочитать в нашем канале - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Сотрудничество: \n" -"Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " -"@{supports}\n" -"\n" -msgstr "" -"Grüße, {fullname}!!!\n" -"\n" -"{heart} QueDateBot ist eine Plattform zum Finden neuer " -"Partnerschaften.\n" -"\n" -"🪧 Sie können Neuigkeiten über das Projekt in unserem Kanal lesen - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Zusammenarbeit: \n" -"Wenn Sie einen Vorschlag für eine Zusammenarbeit haben, schreiben Sie an " -"den Support-Agenten - @{supports}\n" -"\n" - -#: functions/main_app/auxiliary_tools.py:168 -msgid "" -"По вашей ссылке зарегистрировался пользователь {}!\n" -"Вы получаете дополнительных 15 ❤️" -msgstr "" -"Ihr Link wurde von einem Benutzer {} verfolgt!\n" -"Sie erhalten 15 zusätzliche ❤️" - -#: functions/main_app/auxiliary_tools.py:194 -msgid "" -"Регистрация успешно завершена! \n" -"\n" -" {}, {} лет, {}\n" -"\n" -"О себе - {}" -msgstr "" -"Registrierung erfolgreich abgeschlossen! \n" -"\n" -" {}, {} Jahre, {}\n" -"\n" -"Über mich {}" - -#: functions/main_app/auxiliary_tools.py:215 -#: functions/main_app/auxiliary_tools.py:281 -msgid "Фото принято!" -msgstr "Foto akzeptiert!" - -#: functions/main_app/auxiliary_tools.py:219 -#: functions/main_app/auxiliary_tools.py:254 -#: functions/main_app/auxiliary_tools.py:290 -msgid "" -"Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" -"Если ошибка осталась, напишите агенту поддержки." -msgstr "" -"Es ist ein Fehler aufgetreten! Bitte versuchen Sie es erneut oder senden " -"Sie ein anderes Foto.\n" -"Wenn der Fehler weiterhin besteht, schreiben Sie bitte unserem Support-" -"Agenten." - -#: functions/main_app/auxiliary_tools.py:242 -msgid "" -"Во время проверки вашего фото мы обнаружили подозрительный контент!\n" -"Поэтому мы чуть-чуть подкорректировали вашу фотографию" -msgstr "" -"Während der Überprüfung Ihres Fotos haben wir verdächtige Inhalte " -"festgestellt!\n" -"Deshalb haben wir Ihr Foto ein wenig angepasst" - -#: functions/main_app/auxiliary_tools.py:262 -#, fuzzy -msgid "" -"Фото принято!\n" -"Выберите, что вы хотите изменить: " -msgstr "Wählen Sie aus, was Sie ändern möchten: " - -#: functions/main_app/auxiliary_tools.py:285 -msgid "Выберите, что вы хотите изменить: " -msgstr "Wählen Sie aus, was Sie ändern möchten: " - -#: functions/main_app/auxiliary_tools.py:336 -msgid "" -"Руководство по боту: \n" -"Страница №{}" -msgstr "" -"Bot-Anleitung:\n" -"Seite Nr. {}" - -#: functions/main_app/auxiliary_tools.py:352 -msgid "" -"Вы попали в раздел Информации бота, здесь вы можете посмотреть: " -"статистику,изменить язык, а также посмотреть наш брендбук.\n" -"\n" -"🌐 Дней работаем: {}\n" -"👤 Всего пользователей: {}\n" -msgstr "" -"Sie befinden sich im Abschnitt Informationen des Bots. Hier können" -" Sie folgendes anzeigen: Statistiken, Sprache ändern und unseren " -"Markenleitfaden einsehen.\n" -"\n" -"🌐 Tage aktiv: {}\n" -"👤 Gesamtanzahl Benutzer: {}\n" - -#: functions/main_app/determin_location.py:32 -msgid "" -"Я нашел такой адрес:\n" -"{city}\n" -"Если все правильно, то подтвердите" -msgstr "" -"Ich habe diese Adresse gefunden:\n" -"{city}\n" -"Wenn alles korrekt ist, bestätigen Sie" - -#: handlers/echo_handler.py:13 -msgid "Эхо без состояния." -msgstr "Echo ohne Zustand." - -#: handlers/echo_handler.py:38 -msgid "Меню: " -msgstr "Menü: " - -#: handlers/admins/monitoring.py:14 -msgid "Чтобы начать мониторинг нажмите на кнопку ниже" -msgstr "Um die Überwachung zu starten, klicken Sie auf die Schaltfläche unten" - -#: handlers/admins/monitoring.py:32 -msgid "Анкета пользователя была заблокирована" -msgstr "Das Profil des Benutzers wurde blockiert" - -#: handlers/admins/advert/advertisement.py:21 -msgid "" -"📧 Рассылка\n" -"Пришлите текст для рассылки либо фото с текстом для рассылки! Чтобы " -"отредактировать, используйте встроенный редактор телеграма!\n" -msgstr "" -"📧 Newsletter\n" -"Senden Sie einen Text zum Versenden oder ein Foto mit Text zum Versenden!" -" Verwenden Sie zum Bearbeiten den eingebauten Telegramm-Editor!\n" - -#: handlers/admins/advert/mailing/create.py:34 -#: handlers/admins/advert/mailing/create.py:124 -#: handlers/admins/advert/mailing/create.py:267 -msgid "Начинаю рассылку!" -msgstr "Beginne mit der Massenversand!" - -#: handlers/admins/advert/mailing/create.py:49 -#: handlers/admins/advert/mailing/create.py:137 -#: handlers/admins/advert/mailing/create.py:192 -#: handlers/admins/advert/mailing/create.py:281 -msgid "" -"Сообщение не дошло в чат {chat} Причина: \n" -"{err}" -msgstr "" -"Die Nachricht wurde nicht an den Chat {chat} gesendet. Grund: \n" -"{err}" - -#: handlers/admins/advert/mailing/create.py:55 -#: handlers/admins/advert/mailing/create.py:143 -#: handlers/admins/advert/mailing/create.py:198 -#: handlers/admins/advert/mailing/create.py:287 -msgid "Рассылка проведена успешно! Ее получили: {count} чатов!\n" -msgstr "" -"Die Massenversand wurde erfolgreich durchgeführt! {count} Chats haben es " -"erhalten!\n" - -#: handlers/admins/advert/mailing/create.py:61 -msgid "Пришлите мне название кнопки!" -msgstr "Bitte senden Sie mir den Namen der Taste!" - -#: handlers/admins/advert/mailing/create.py:70 -msgid "Название кнопки принято! Теперь отправьте мне ссылку для этой кнопки!" -msgstr "" -"Der Name der Taste wurde akzeptiert! Bitte senden Sie mir jetzt den Link " -"für diese Taste!" - -#: handlers/admins/advert/mailing/create.py:90 -#: handlers/admins/advert/mailing/create.py:232 -msgid "" -"Вот так будет выглядеть сообщение: \n" -"\n" -"{text}\n" -"\n" -msgstr "" -"So wird die Nachricht aussehen: \n" -"\n" -"{text}\n" -"\n" - -#: handlers/admins/advert/mailing/create.py:97 -#: handlers/admins/advert/mailing/create.py:239 -msgid "Вы подтверждаете отправку?" -msgstr "Möchten Sie den Versand bestätigen?" - -#: handlers/admins/advert/mailing/create.py:104 -#: handlers/admins/advert/mailing/create.py:246 -msgid "" -"Произошла ошибка! Скорее всего, неправильно введена ссылка! Попробуйте " -"еще раз." -msgstr "" -"Es ist ein Fehler aufgetreten! Möglicherweise wurde der Link falsch " -"eingegeben! Versuchen Sie es erneut." - -#: handlers/admins/advert/mailing/create.py:157 -msgid "" -"Вот сообщение: \n" -"\n" -"{text}\n" -"\n" -" Вы подтверждаете отправку? Или хотите что-то добавить?" -msgstr "" -"Hier ist die Nachricht: \n" -"\n" -"{text}\n" -"\n" -" Bestätigen Sie die Übermittlung? Oder möchten Sie etwas hinzufügen?" - -#: handlers/admins/settings/tech_works.py:26 -msgid "Чтобы включить/выключить технические работы, нажмите на кнопку ниже" -msgstr "" -"Um Wartungsarbeiten ein- oder auszuschalten, klicken Sie auf die " -"Schaltfläche unten" - -#: handlers/admins/settings/tech_works.py:36 -msgid "Технические работы включены" -msgstr "Wartungsarbeiten sind aktiviert" - -#: handlers/admins/settings/tech_works.py:44 -msgid "Технические работы выключены" -msgstr "Wartungsarbeiten sind deaktiviert" - -#: handlers/groups/event_moderate.py:24 -msgid "Принято!" -msgstr "Akzeptiert!" - -#: handlers/groups/event_moderate.py:33 -msgid "Ваше мероприятие прошло модерацию" -msgstr "Ihre Veranstaltung wurde moderiert" - -#: handlers/groups/event_moderate.py:40 -msgid "Отклонено!" -msgstr "Abgelehnt!" - -#: handlers/groups/event_moderate.py:44 -msgid "К сожалению ваше мероприятие не прошло модерацию" -msgstr "Leider hat Ihre Veranstaltung die Moderation nicht bestanden" - -#: handlers/groups/start.py:12 -msgid "" -"Привет, я бот, проекта Que Group, для верификации анкет для " -"знакомств\n" -"\n" -msgstr "" -"Hallo, ich bin ein Bot des Que Group-Projekts zur Überprüfung von " -"Profilen für Dating\n" -"\n" - -#: handlers/users/back.py:43 -msgid "Вы забанены!" -msgstr "Sie sind gesperrt!" - -#: handlers/users/back.py:50 -msgid "Вы вернулись в меню фильтров" -msgstr "Sie sind zurück im Filtermenü" - -#: handlers/users/brandbook_handler.py:23 -msgid "" -"Руководство по боту: \n" -"Страница №1" -msgstr "" -"Bot-Anleitung:\n" -"Seite Nr. 1" - -#: handlers/users/buy_unban.py:17 -msgid "" -"💳 Сейчас вам нужно выбрать способ оплаты\n" -"\n" -"├Стоимость разблокировки - 99₽\n" -"├Оплата обычно приходить в течение 1-3 минут\n" -"├Если у вас нет Yoomoney или нет возможности\n" -"├оплатить, напишите агенту поддержки" -msgstr "" -"💳 Jetzt müssen Sie eine Zahlungsmethode auswählen\n" -"\n" -"├Entsperrkosten - 99₽\n" -"├Die Zahlung erfolgt normalerweise innerhalb von 1-3 Minuten\n" -"├Wenn Sie kein Yoomoney haben oder nicht in der Lage sind zu bezahlen,\n" -"├schreiben Sie dem Support-Agenten" - -#: handlers/users/buy_unban.py:38 -msgid "После оплаты нажмите 🔄 Проверить оплату" -msgstr "Nach der Zahlung klicken Sie auf 🔄 Zahlung bestätigen" - -#: handlers/users/buy_unban.py:57 -msgid "Поздравляем! Вы были разрабанены" -msgstr "Glückwunsch! Du wurdest entfreundet" - -#: handlers/users/buy_unban.py:65 -msgid "" -"Оплата не прошла! Подождите минут 10, а затем еще раз попробуйте нажать " -"кнопку ниже" -msgstr "" -"Zahlung fehlgeschlagen! Warten Sie etwa 10 Minuten und versuchen Sie es " -"dann noch einmal mit der Schaltfläche unten" - -#: handlers/users/change_datas.py:35 -msgid "Ваши данные: \n" -msgstr "Ihre Angaben: .\n" - -#: handlers/users/change_datas.py:40 -msgid "Введите новое имя" -msgstr "Geben Sie einen neuen Namen ein" - -#: handlers/users/change_datas.py:53 -#, fuzzy -msgid "" -"Ваше новое имя: {censored}\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"Daten erfolgreich geändert.\n" -"Wählen Sie aus, was Sie ändern möchten: " - -#: handlers/users/change_datas.py:63 -msgid "" -"Произошла неизвестная ошибка. Попробуйте ещё раз\n" -"Возможно, Ваше сообщение слишком большое" -msgstr "" -"Es ist ein unbekannter Fehler aufgetreten. Bitte versuchen Sie es erneut\n" -"Ihre Nachricht ist möglicherweise zu groß" - -#: handlers/users/change_datas.py:76 -msgid "Введите новый возраст" -msgstr "Neues Alter eingeben" - -#: handlers/users/change_datas.py:90 -#, fuzzy -msgid "" -"Ваш новый возраст: {messages}\n" -"Выберите, что вы хотите изменить: " -msgstr "Dein neues Alter: {messages}" - -#: handlers/users/change_datas.py:99 handlers/users/registration.py:163 -msgid "Вы ввели недопустимое число, попробуйте еще раз" -msgstr "Sie haben eine ungültige Zahl eingegeben. Bitte versuchen Sie es erneut" - -#: handlers/users/change_datas.py:104 -msgid "Вы ввели не число, попробуйте еще раз" -msgstr "Sie haben eine ungültige Zahl eingegeben. Bitte versuchen Sie es erneut" - -#: handlers/users/change_datas.py:112 -msgid "Введите новый город" -msgstr "Geben Sie eine neue Stadt ein" - -#: handlers/users/change_datas.py:124 -msgid "Мы не смогли найти город {city}. Попробуйте ещё раз" -msgstr "Wir konnten die Stadt {city} nicht finden. Erneut versuchen" - -#: handlers/users/change_datas.py:134 -msgid "" -"Данные успешно изменены.\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"Daten erfolgreich geändert.\n" -"Wählen Sie aus, was Sie ändern möchten: " - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♂️ Мужской" -msgstr "👱🏻‍♂️ Männlich" - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♀️ Женский" -msgstr "👱🏻‍♀️ Weiblich" - -#: handlers/users/change_datas.py:145 -msgid "Выберите новый пол: " -msgstr "Wählen Sie ein neues Geschlecht: " - -#: handlers/users/change_datas.py:155 -#, fuzzy -msgid "" -"Ваш новый пол: {}\n" -"Выберите, что вы хотите изменить: " -msgstr "Wählen Sie aus, was Sie ändern möchten: " - -#: handlers/users/change_datas.py:167 -msgid "Отправьте мне новую фотографию" -msgstr "Schicken Sie mir ein neues Foto" - -#: handlers/users/change_datas.py:191 handlers/users/registration.py:244 -msgid "Произошла ошибка, проверьте настройки конфиденциальности" -msgstr "" -"Es ist ein Fehler aufgetreten. Überprüfen Sie Ihre " -"Datenschutzeinstellungen" - -#: handlers/users/change_datas.py:232 -#, fuzzy -msgid "Отправьте сообщение о себе" -msgstr "Senden Sie mir eine Sprachnachricht" - -#: handlers/users/change_datas.py:247 -#, fuzzy -msgid "" -"Комментарий принят!\n" -"Выберите, что вы хотите изменить: " -msgstr "Kommentar angenommen! Wählen Sie, wen Sie suchen möchten: " - -#: handlers/users/change_datas.py:254 -msgid "" -"Произошла ошибка! Попробуйте еще раз изменить описание. Возможно, Ваше " -"сообщение слишком большое\n" -"Если ошибка осталась, напишите в поддержку." -msgstr "" -"Es ist ein Fehler aufgetreten! Versuchen Sie, die Beschreibung erneut zu " -"ändern. Ihre Nachricht ist möglicherweise zu groß.\n" -"Wenn der Fehler weiterhin besteht, wenden Sie sich bitte an den Support." - -#: handlers/users/change_datas.py:267 -msgid "" -"Напишите имя своего аккаунта\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" -"Schreiben Sie Ihren Kontonamen\n" -"\n" -"Beispiele:\n" -"@unknown\n" -"https://www.instagram.com/unknown" - -#: handlers/users/change_datas.py:289 -msgid "Ваш аккаунт успешно добавлен" -msgstr "Ihr Konto wurde erfolgreich hinzugefügt" - -#: handlers/users/change_datas.py:293 handlers/users/verification.py:45 -msgid "Вы были возвращены в меню" -msgstr "Sie wurden zum Menü zurückgeführt" - -#: handlers/users/change_datas.py:297 -msgid "" -"Вы ввели неправильную ссылку или имя аккаунта.\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" -"Sie haben einen falschen Link oder einen falschen Benutzernamen " -"eingegeben.\n" -"\n" -"Beispiele:\n" -"@unknown\n" -"https://www.instagram.com/unknown" - -#: handlers/users/change_datas.py:304 -msgid "Возникла ошибка. Попробуйте еще раз" -msgstr "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut" - -#: handlers/users/change_event_datas.py:16 -msgid "Вы перешли в меню изменения данных мероприятия" -msgstr "Sie haben das Menü zur Änderung der Veranstaltungsdaten aufgerufen" - -#: handlers/users/change_event_datas.py:23 -msgid "Напишите новое название вашего мероприятия" -msgstr "Geben Sie den neuen Namen Ihrer Veranstaltung ein" - -#: handlers/users/change_event_datas.py:35 -#: handlers/users/change_event_datas.py:53 -msgid "Данные изменены" -msgstr "Daten wurden geändert" - -#: handlers/users/change_event_datas.py:41 -msgid "Напишите новое описание вашего мероприятия" -msgstr "Geben Sie eine neue Beschreibung für Ihre Veranstaltung ein" - -#: handlers/users/event_handler.py:31 -msgid "Вы перешли в меню афиш" -msgstr "Sie haben das Menü für Plakate aufgerufen" - -#: handlers/users/event_handler.py:48 -msgid "Введите название мероприятие" -msgstr "Geben Sie den Namen der Veranstaltung ein" - -#: handlers/users/event_handler.py:55 -msgid "" -"Вы уже создали мероприятие, которое проходит модерацию. Дождитесь " -"проверки, пожалуйста" -msgstr "" -"Sie haben bereits eine Veranstaltung erstellt, die gerade moderiert wird." -" Bitte warten Sie auf die Überprüfung" - -#: handlers/users/event_handler.py:63 -msgid "" -"Прочитайте сообщение и не нажимайте на кнопку, пока ваше мероприятие не " -"пройдет модерацию" -msgstr "" -"Lesen Sie die Nachricht und drücken Sie nicht auf die Schaltfläche, bis " -"Ihre Veranstaltung moderiert wurde" - -#: handlers/users/event_handler.py:78 -msgid "Пожалуйста, выберите дату: " -msgstr "🕕 ein Datum festlegen: " - -#: handlers/users/event_handler.py:83 -msgid "" -"Длинна вашего сообщение превышает допустимую.\n" -"Попробуйте ещё раз" -msgstr "" -"Die Länge Ihrer Nachricht überschreitet die zulässige Länge.\n" -"Erneut versuchen" - -#: handlers/users/event_handler.py:99 -msgid "Вы не можете проводить мероприятие в прошлом" -msgstr "Sie können keine Veranstaltung in der Vergangenheit abhalten" - -#: handlers/users/event_handler.py:105 -msgid "Теперь напишите место проведения" -msgstr "Geben Sie jetzt den Veranstaltungsort ein" - -#: handlers/users/event_handler.py:126 -msgid "Вы ввели слишком длинное название городаПопробуйте ещё раз." -msgstr "Sie haben einen zu langen Städtenamen eingegebenVersuchen Sie es erneut." - -#: handlers/users/event_handler.py:132 -msgid "" -"Произошла неизвестная ошибка! Попробуйте еще раз.\n" -"Вероятнее всего вы ввели город неправильно" -msgstr "" -"Ein unbekannter Fehler ist aufgetreten! Versuchen Sie es erneut.\n" -"Sie haben wahrscheinlich die Stadt falsch eingegeben" - -#: handlers/users/event_handler.py:142 -msgid "Хорошо, теперь напишите короткое или длинное описание вашего мероприятия" -msgstr "" -"Ok, schreiben Sie jetzt eine kurze oder lange Beschreibung Ihrer " -"Veranstaltung" - -#: handlers/users/event_handler.py:158 -msgid "И напоследок, пришлите постер вашего мероприятия" -msgstr "Und zuletzt senden Sie das Plakat Ihrer Veranstaltung" - -#: handlers/users/event_handler.py:164 -msgid "Ваше сообщение слишком длинное.Попробуйте написать короче" -msgstr "Ihre Nachricht ist zu lang, versuchen Sie, sie kürzer zu schreiben" - -#: handlers/users/event_handler.py:178 -msgid "Фото принято" -msgstr "Foto angenommen" - -#: handlers/users/event_handler.py:200 -msgid "Ваше мероприятие отправлено на модерацию" -msgstr "Ihre Veranstaltung wurde zur Moderation gesendet" - -#: handlers/users/event_list.py:23 -msgid "На данный момент вы никуда не записались" -msgstr "Sie sind derzeit nirgendwo eingeschrieben" - -#: handlers/users/filters.py:23 handlers/users/filters.py:29 -msgid "Вы перешли в раздел с фильтрами" -msgstr "Sie haben den Abschnitt mit Filtern aufgerufen" - -#: handlers/users/filters.py:41 -msgid "Напишите минимальный возраст" -msgstr "Geben Sie das Mindestalter ein" - -#: handlers/users/filters.py:53 -msgid "Теперь введите максимальный возраст" -msgstr "Geben Sie nun das Höchstalter ein" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♂️ Парня" -msgstr "👱🏻‍♂️ Kerl" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♀️ Девушку" -msgstr "👱🏻‍♀️ Ein Mädchen" - -#: handlers/users/filters.py:76 -msgid "Выберите, кого вы хотите найти:" -msgstr "Wählen Sie, wen Sie suchen möchten:" - -#: handlers/users/filters.py:84 handlers/users/filters.py:111 -msgid "Данные сохранены" -msgstr "Daten wurden gespeichert" - -#: handlers/users/filters.py:92 -msgid "Напишите город вашего будущего партнера" -msgstr "Schreiben Sie die Stadt Ihres zukünftigen Partners" - -#: handlers/users/filters.py:103 handlers/users/filters.py:144 -msgid "Произошла ошибка, попробуйте еще раз" -msgstr "Es ist ein Fehler aufgetreten, bitte versuchen Sie es erneut" - -#: handlers/users/filters.py:124 -msgid "Вы перешли в меню настроек фильтров для мероприятий" -msgstr "" -"Sie haben das Menü für die Filtereinstellungen für Veranstaltungen " -"geöffnet" - -#: handlers/users/filters.py:132 -msgid "Напишите город, в котором бы хотели сходить куда-нибудь" -msgstr "Schreiben Sie die Stadt, in der Sie gerne etwas unternehmen möchten" - -#: handlers/users/registration.py:42 -msgid "Пройдите опрос, чтобы зарегистрироваться" -msgstr "Beantworten Sie die Fragen, um sich zu registrieren" - -#: handlers/users/registration.py:52 -msgid "" -"Вы уже зарегистрированы, если вам нужно изменить анкету, то нажмите на " -"кнопку ниже" -msgstr "" -"Sie sind bereits registriert. Wenn Sie Ihr Profil ändern möchten, klicken" -" Sie auf die folgende Schaltfläche" - -#: handlers/users/registration.py:66 -msgid "Выберите пол" -msgstr "Wählen Sie Ihr Geschlecht" - -#: handlers/users/registration.py:88 -msgid "Теперь расскажите о себе:\n" -msgstr "Jetzt erzählen Sie mir etwas über sich selbst:\n" - -#: handlers/users/registration.py:105 -msgid "Комментарий принят! Выберите, кого вы хотите найти: " -msgstr "Kommentar angenommen! Wählen Sie, wen Sie suchen möchten: " - -#: handlers/users/registration.py:111 -msgid "" -"Произошла неизвестная ошибка! Попробуйте изменить комментарий позже в " -"разделе \"Меню\"\n" -"\n" -"Выберите, кого вы хотите найти: " -msgstr "" -"Es ist ein unbekannter Fehler aufgetreten! Versuchen Sie, Ihren Kommentar" -" später im Abschnitt Menü zu ändern\n" -"\n" -"Wählen Sie aus, wen Sie suchen möchten: " - -#: handlers/users/registration.py:125 -msgid "Отлично! Теперь напишите мне ваше имя, которое будут все видеть в анкете" -msgstr "" -"Super! Schreiben Sie mir jetzt Ihren Namen, den alle in Ihrem Profil " -"sehen werden" - -#: handlers/users/registration.py:145 -msgid "Введите сколько вам лет:" -msgstr "Geben Sie an, wie alt Sie sind:" - -#: handlers/users/registration.py:170 -msgid "Вы ввели не число" -msgstr "Sie haben keine Zahl eingegeben" - -#: handlers/users/registration.py:175 -msgid "Нажмите на кнопку ниже, чтобы определить ваш местоположение!" -msgstr "Klicken Sie auf die Schaltfläche unten, um Ihren Standort zu finden!" - -#: handlers/users/registration.py:188 -msgid "Мы не смогли найти такой город, попробуйте еще раз" -msgstr "Wir konnten eine solche Stadt nicht finden, versuchen Sie es erneut" - -#: handlers/users/registration.py:211 handlers/users/registration.py:224 -msgid "" -"И напоследок, Пришлите мне вашу фотографию (отправлять надо сжатое " -"изображение, а не как документ)" -msgstr "" -"Und schließlich: Schicken Sie mir ein Foto von sich (als komprimiertes " -"Bild, nicht als Dokument)" - -#: handlers/users/sponsor.py:10 -msgid "" -"Наш проект работает на Open Source и мы будем рады,если вы нам " -"поможете развивать проект.\n" -"\n" -"С помощью кнопки 💰 Донат вы можете отправить своё пожертвование" -msgstr "" -"Unser Projekt basiert auf Open Source und wir wären dankbar, wenn " -"Sie uns helfen, das Projekt weiterzuentwickeln.\n" -"\n" -"Mit der Schaltfläche 💰 Spenden können Sie Ihre Spende senden" - -#: handlers/users/start_handler.py:27 -msgid "Вам необходимо зарегистрировать агента(ов) тех поддержки" -msgstr "Sie müssen Ihre(n) Support-Agent(en) registrieren" - -#: handlers/users/start_handler.py:36 -msgid "Вас нет в базе данной" -msgstr "Sie sind nicht in der Datenbank" - -#: handlers/users/start_handler.py:42 handlers/users/start_handler.py:47 -msgid "Выберите язык" -msgstr "Wählen Sie eine Sprache aus" - -#: handlers/users/start_handler.py:57 -msgid "Язык был успешно изменен. Введите команду /start" -msgstr "Die Sprache wurde erfolgreich geändert. Geben Sie den Befehl /start ein" - -#: handlers/users/start_handler.py:61 -msgid "Произошла какая-то ошибка. Введите команду /start и попробуйте еще раз" -msgstr "" -"Es ist eine Art Fehler aufgetreten. Geben Sie den Befehl /start ein und " -"versuchen Sie es erneut" - -#: handlers/users/support_handler.py:20 -msgid "Хотите связаться с тех поддержкой? Нажмите на кнопку ниже!" -msgstr "" -"Möchten Sie den technischen Support kontaktieren? Klicken Sie auf die " -"Schaltfläche unten!" - -#: handlers/users/support_handler.py:25 handlers/users/support_handler.py:52 -msgid "К сожалению, сейчас нет свободных операторов. Попробуйте позже." -msgstr "" -"Leider sind im Moment keine freien Operator verfügbar. Bitte versuchen " -"Sie es später erneut." - -#: handlers/users/support_handler.py:41 -msgid "Вы обратились в техническую поддержку. Ждем ответа от оператора!" -msgstr "" -"Sie haben sich an den technischen Support gewendet. Wir warten auf eine " -"Antwort vom Operator!" - -#: handlers/users/support_handler.py:64 -msgid "С вами хочет связаться пользователь {full_name}" -msgstr "Der Benutzer {full_name} möchte mit Ihnen Kontakt aufnehmen" - -#: handlers/users/support_handler.py:79 -msgid "К сожалению, пользователь уже передумал." -msgstr "Leider hat der Benutzer seine Meinung geändert." - -#: handlers/users/support_handler.py:91 -msgid "" -"Вы на связи с пользователем!\n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"Sie sind mit dem Benutzer verbunden!\n" -"Klicken Sie auf die Schaltfläche, um das Gespräch zu beenden." - -#: handlers/users/support_handler.py:100 -msgid "" -"Техподдержка на связи! Можете писать сюда свое сообщение. \n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"Der technische Support ist online! Sie können hier Ihre Nachricht " -"schreiben. \n" -"Klicken Sie auf die Schaltfläche, um das Gespräch zu beenden." - -#: handlers/users/support_handler.py:115 -msgid "Дождитесь ответа оператора или отмените сеанс" -msgstr "Warten Sie auf die Antwort des Operators oder brechen Sie die Sitzung ab" - -#: handlers/users/support_handler.py:131 -msgid "Пользователь завершил сеанс техподдержки" -msgstr "Der Benutzer hat die technische Support-Sitzung beendet" - -#: handlers/users/support_handler.py:135 -msgid "Вы завершили сеанс и были возвращены в главное меню" -msgstr "Sie haben die Sitzung beendet und sind zum Hauptmenü zurückgekehrt" - -#: handlers/users/user_profile.py:23 -msgid "" -"Ваша анкета удалена!\n" -"Я надеюсь вы кого-нибудь нашли" -msgstr "" -"Ihr Profil wurde gelöscht!\n" -"Ich hoffe, Sie haben jemanden gefunden" - -#: handlers/users/verification.py:17 -msgid "Чтобы пройти верификацию вам нужно отправить свой контакт" -msgstr "Um sich zu verifizieren, müssen Sie Ihre Kontaktdaten senden" - -#: handlers/users/verification.py:33 -msgid "" -"Спасибо, {contact_full_name}.\n" -"Ваш номер {contact_phone_number} был получен." -msgstr "" -"Danke, {contact_full_name}.\n" -"Ihre Telefonnummer {contact_phone_number} wurde empfangen." - -#: handlers/users/verification.py:50 -msgid "Ваш номер недействителен, попробуйте еще раз." -msgstr "Ihre Telefonnummer ist ungültig. Bitte versuchen Sie es erneut." - -#: handlers/users/view_event.py:27 -msgid "На данный момент вы просмотрели все существующие анкеты" -msgstr "Sie haben derzeit alle vorhandenen Profile angesehen" - -#: handlers/users/view_ques.py:73 -#, fuzzy -msgid "Жалоба успешно отправлена" -msgstr "Ihr Konto wurde erfolgreich hinzugefügt" - -#: handlers/users/view_ques.py:112 -msgid "" -"Слишком много ❤️ за сегодня.\n" -"\n" -"Пригласи друзей и получи больше ❤️\n" -"\n" -"https://t.me/{}?start={}" -msgstr "" -"Zu viele ❤️ für heute.\n" -"\n" -"Laden Sie Ihre Freunde ein und erhalten Sie mehr ❤️\n" -"\n" -"https://t.me/{}?start={}" - -#: keyboards/admin/inline/customers.py:12 -msgid "🔍 Найти пользователя" -msgstr "🔍 Benutzer finden" - -#: keyboards/admin/inline/customers.py:23 -msgid "🟢 Разблокировать" -msgstr "🟢 Freischalten" - -#: keyboards/admin/inline/customers.py:28 -msgid "🚫 Заблокировать" -msgstr "🚫 Freischalten" - -#: keyboards/admin/inline/mailing.py:8 -msgid "📧 Рассылка" -msgstr "📧 Verteiler" - -#: keyboards/admin/inline/mailing.py:16 keyboards/admin/inline/mailing.py:31 -#: keyboards/inline/admin_inline.py:9 -msgid "Подтвердить отправку" -msgstr "Senden bestätigen" - -#: keyboards/admin/inline/mailing.py:19 -msgid "Добавить кнопку" -msgstr "Schaltfläche hinzufügen" - -#: keyboards/admin/inline/mailing.py:21 keyboards/admin/inline/mailing.py:33 -#: keyboards/inline/cancel_inline.py:8 -msgid "Отмена" -msgstr "Abbrechen" - -#: keyboards/admin/inline/payments.py:9 -msgid "⚙️ Настройки" -msgstr "⚙️ Einstellungen" - -#: keyboards/admin/inline/payments.py:11 -msgid "📝 Статистика" -msgstr "📝 Statistik" - -#: keyboards/admin/inline/ref.py:8 -msgid "📈 Статистика" -msgstr "📝 Statistik" - -#: keyboards/admin/inline/ref.py:9 keyboards/admin/inline/setting.py:8 -msgid "*️⃣ Добавить" -msgstr "*️⃣ Hinzufügen" - -#: keyboards/admin/inline/ref.py:10 keyboards/admin/inline/setting.py:9 -msgid "❌ Удалить" -msgstr "❌ Löschen" - -#: keyboards/admin/inline/ref.py:11 keyboards/admin/inline/setting.py:10 -msgid "◀️ Назад" -msgstr "◀️ Zurück" - -#: keyboards/admin/inline/reply_menu.py:9 -msgid "🙅🏻‍♂️ Отменить" -msgstr "🙅🏻‍♂️ Abbrechen" - -#: keyboards/admin/inline/reply_menu.py:17 -msgid "👮‍♂️ Админ Состав" -msgstr "👮‍♂️ Admin-Team" - -#: keyboards/admin/inline/reply_menu.py:19 -msgid "📞 Сменить контакты" -msgstr "📞 Kontakte ändern" - -#: keyboards/admin/inline/reply_menu.py:29 -msgid "🗒 Выгрузить юзеров | .txt" -msgstr "🗒 Benutzer exportieren | .txt" - -#: keyboards/admin/inline/reply_menu.py:32 -msgid "🗒 Выгрузить конфиги и логи" -msgstr "🗒 Konfigurationen und Logs exportieren" - -#: keyboards/default/admin_default.py:8 -msgid "Рассылка" -msgstr "Verteiler" - -#: keyboards/default/admin_default.py:9 -msgid "Сообщение по id" -msgstr "Nachricht nach ID" - -#: keyboards/default/admin_default.py:10 -msgid "Посчитать людей и чаты" -msgstr "Zähle Personen und Chats" - -#: keyboards/default/admin_default.py:11 -msgid "Мониторинг" -msgstr "Überwachung" - -#: keyboards/default/admin_default.py:12 -msgid "Тех.Работа" -msgstr "Technische Arbeit" - -#: keyboards/default/get_contact_default.py:8 -msgid "📱 Отправить" -msgstr "📱 Senden" - -#: keyboards/default/get_location_default.py:9 -msgid "🗺 Определить автоматически" -msgstr "🗺 Automatisch ermitteln" - -#: keyboards/default/get_photo.py:8 -msgid "Взять из профиля" -msgstr "Aus dem Profil übernehmen" - -#: keyboards/inline/admin_inline.py:18 -msgid "Включить" -msgstr "Einschalten" - -#: keyboards/inline/admin_inline.py:21 -msgid "Выключить" -msgstr "Ausschalten" - -#: keyboards/inline/admin_inline.py:33 -msgid "Разблокировать" -msgstr "Freischalten" - -#: keyboards/inline/back_inline.py:8 -#: keyboards/inline/change_data_profile_inline.py:15 -#: keyboards/inline/filters_inline.py:42 keyboards/inline/language_inline.py:22 -#: keyboards/inline/poster_inline.py:31 keyboards/inline/poster_inline.py:49 -#: keyboards/inline/poster_inline.py:63 -#: keyboards/inline/registration_inline.py:12 -#: keyboards/inline/settings_menu.py:12 keyboards/inline/sponsor_inline.py:10 -#: keyboards/inline/sponsor_inline.py:21 -msgid "⏪️ Вернуться в меню" -msgstr "⏪️ Zurück zum Menü" - -#: keyboards/inline/cancel_inline.py:16 -#: keyboards/inline/change_data_profile_inline.py:28 -msgid "❌ Остановить" -msgstr "❌ Beenden" - -#: keyboards/inline/change_data_profile_inline.py:8 -msgid "👤 Имя" -msgstr "👤 Name" - -#: keyboards/inline/change_data_profile_inline.py:9 -msgid "⚧ Пол" -msgstr "⚧ Geschlecht" - -#: keyboards/inline/change_data_profile_inline.py:10 -msgid "📅 Возраст" -msgstr "📅 Alter" - -#: keyboards/inline/change_data_profile_inline.py:11 -msgid "🏙 Город" -msgstr "🏙 Stadt" - -#: keyboards/inline/change_data_profile_inline.py:12 -msgid "📷 Фото" -msgstr "📷 Foto" - -#: keyboards/inline/change_data_profile_inline.py:13 -msgid "📝 О себе" -msgstr "📝 Über mich" - -#: keyboards/inline/filters_inline.py:9 -msgid "🎉 Мероприятия" -msgstr "🎉 Veranstaltungen" - -#: keyboards/inline/filters_inline.py:12 -msgid "❤️ Знакомства" -msgstr "❤️ Dating" - -#: keyboards/inline/filters_inline.py:14 keyboards/inline/filters_inline.py:31 -#: keyboards/inline/guide_inline.py:15 -msgid "⏪️ Назад" -msgstr "⏪️ Zurück" - -#: keyboards/inline/filters_inline.py:23 -msgid "🏙️ Город партнера" -msgstr "🏙️ Stadt deines Partners" - -#: keyboards/inline/filters_inline.py:26 -msgid "🔞 Возр.диапазон" -msgstr "🔞 Altersgruppe" - -#: keyboards/inline/filters_inline.py:29 -msgid "🚻 Пол партнера" -msgstr "Geschlecht des partners" - -#: keyboards/inline/filters_inline.py:40 -msgid "🏙️ Город" -msgstr "🏙️ Stadt" - -#: keyboards/inline/guide_inline.py:21 -msgid "Вперед ➡️" -msgstr "Los ➡️" - -#: keyboards/inline/guide_inline.py:25 -msgid "❌ Закрыть" -msgstr "❌ Schließen" - -#: keyboards/inline/language_inline.py:13 -msgid "🇷🇺 Русский" -msgstr "🇷🇺 Russisch" - -#: keyboards/inline/language_inline.py:14 -msgid "🇩🇪 Немецкий" -msgstr "🇩🇪 Deutsch" - -#: keyboards/inline/language_inline.py:15 -msgid "🇬🇧 Английский" -msgstr "🇬🇧 Englisch" - -#: keyboards/inline/language_inline.py:16 -msgid "🇮🇩 Индонезийский" -msgstr "🇮🇩 Südseesprachen" - -#: keyboards/inline/main_menu_inline.py:26 -msgid "➕ Регистрация" -msgstr "➕ Registrierung" - -#: keyboards/inline/main_menu_inline.py:28 keyboards/inline/settings_menu.py:10 -msgid "🌐 Язык" -msgstr "🌐 Sprache" - -#: keyboards/inline/main_menu_inline.py:30 -msgid "👤 Моя анекта" -msgstr "👤 Mein Profil" - -#: keyboards/inline/main_menu_inline.py:32 -msgid "⚙️ Фильтры" -msgstr "⚙️ Filter" - -#: keyboards/inline/main_menu_inline.py:33 -msgid "💌 Найти пару" -msgstr "💌 finden ein Paar" - -#: keyboards/inline/main_menu_inline.py:34 -msgid "🗓️ Афиша" -msgstr "🗓️ Poster" - -#: keyboards/inline/main_menu_inline.py:35 -msgid "🆘 Поддержка" -msgstr "🆘 Support" - -#: keyboards/inline/main_menu_inline.py:37 -msgid "ℹ️ Информация" -msgstr "ℹ️ Informationen" - -#: keyboards/inline/menu_profile_inline.py:10 -msgid "✅ Верификация" -msgstr "✅ Richtigkeitsprüfung" - -#: keyboards/inline/menu_profile_inline.py:16 -msgid "🖊️ Изменить" -msgstr "🖊️ Ändern" - -#: keyboards/inline/menu_profile_inline.py:18 -msgid "🗑️ Удалить" -msgstr "🗑️ Löschen" - -#: keyboards/inline/menu_profile_inline.py:19 -msgid "⏪ Назад" -msgstr "⏪ Zurück" - -#: keyboards/inline/payments_inline.py:9 -msgid "💳 ЮMoney" -msgstr "💳 YouMoney" - -#: keyboards/inline/payments_inline.py:16 -msgid "💳 Оплатить" -msgstr "💳 Bezahlen" - -#: keyboards/inline/payments_inline.py:18 -msgid "🔄 Проверить оплату" -msgstr "🔄 Scheckzahlung" - -#: keyboards/inline/poster_inline.py:21 -msgid "✍️Создать афишу" -msgstr "Plakat erstellen" - -#: keyboards/inline/poster_inline.py:24 -msgid "🎭 Смотреть афиши" -msgstr "🎭 Poster beobachten" - -#: keyboards/inline/poster_inline.py:27 -msgid "📝 Мои записи" -msgstr "📝 Meine Aufzeichnungen" - -#: keyboards/inline/poster_inline.py:29 -msgid "📃 Моё событие" -msgstr "📃 Mein Ereignis" - -#: keyboards/inline/poster_inline.py:46 -msgid "✍️ Изменить" -msgstr "✍️ Ändern" - -#: keyboards/inline/poster_inline.py:58 -msgid "Название" -msgstr "Titel" - -#: keyboards/inline/poster_inline.py:60 -msgid "Описание" -msgstr "Beschreibung" - -#: keyboards/inline/poster_inline.py:73 -msgid "✅ Одобрить" -msgstr "✅ Genehmigen" - -#: keyboards/inline/poster_inline.py:76 -msgid "❌ Отклонить" -msgstr "Ablehnen" - -#: keyboards/inline/poster_inline.py:85 -msgid "Пойду!" -msgstr "Ich gehe hin!" - -#: keyboards/inline/poster_inline.py:88 -msgid "Не интересно" -msgstr "Nicht interessiert" - -#: keyboards/inline/poster_inline.py:91 keyboards/inline/poster_inline.py:103 -#: keyboards/inline/poster_inline.py:112 -msgid "⏪️ Остановить" -msgstr "⏪️ Stoppen" - -#: keyboards/inline/poster_inline.py:101 -msgid "❌ Отменить запись" -msgstr "❌ Eintrag abbrechen" - -#: keyboards/inline/questionnaires_inline.py:30 -#, fuzzy -msgid "💤 Остановить" -msgstr "❌ Beenden" - -#: keyboards/inline/questionnaires_inline.py:34 -msgid "🚫 Забанить" -msgstr "🚫 Blockieren" - -#: keyboards/inline/questionnaires_inline.py:38 -msgid "Следующий" -msgstr "Nächste Person" - -#: keyboards/inline/questionnaires_inline.py:74 -msgid "🚀 Смотреть" -msgstr "🚀 Ansehen" - -#: keyboards/inline/questionnaires_inline.py:82 -msgid "👉 Перейти в чат" -msgstr "👉 Zum Chat gehen" - -#: keyboards/inline/questionnaires_inline.py:89 -msgid "⏪️ Вернуться к просмотру анкет" -msgstr "⏪️ Zurück zur Profilansicht" - -#: keyboards/inline/registration_inline.py:9 -msgid "🖌️ Пройти опрос в боте" -msgstr "🖌️ Durchgehen Umfrage im Bot" - -#: keyboards/inline/registration_inline.py:21 -msgid "✅ Да все хорошо!" -msgstr "✅ Ja, alles ist gut!" - -#: keyboards/inline/settings_menu.py:8 -msgid "📚 Брендбук" -msgstr "📚 Markenbuch" - -#: keyboards/inline/settings_menu.py:9 -msgid "📞 Контакты" -msgstr "📞 Kontakte" - -#: keyboards/inline/support_inline.py:37 -msgid "Ответить пользователю" -msgstr "Dem Benutzer antworten" - -#: keyboards/inline/support_inline.py:45 -msgid "Написать оператору" -msgstr "Schreiben Sie an den Betreiber" - -#: keyboards/inline/support_inline.py:60 keyboards/inline/support_inline.py:72 -msgid "Завершить сеанс" -msgstr "Sitzung beenden" - -#: middlewares/BanCheck.py:44 -msgid "😢 Вы заблокированы!" -msgstr "😢 Sie sind blockiert!" - -#: middlewares/IsMaintenanceCheck.py:26 -msgid "Ведутся технические работы" -msgstr "Technische Arbeiten sind im Gange" - -#: middlewares/LinkCheck.py:38 -msgid "" -"Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " -"подпишитесь! Ссылки ниже: " -msgstr "" -"Sie haben nicht alle Kanäle abonniert! Um den Bot weiterhin zu nutzen, " -"abonnieren Sie bitte! Links unten: " - -#: utils/notify_admins.py:24 -msgid "Оповещение администрации..." -msgstr "" - -#: utils/notify_admins.py:28 -msgid "Бот был успешно запущен" -msgstr "" - -#: utils/statistics.py:16 -msgid "" -"📊 Статистика: \n" -"\n" -"└Сейчас в нашем боте {count_users} пользователей\n" -"└Из них:\n" -" ├{users_gender_m} пользователей мужского пола\n" -" ├{users_gender_f} пользователей женского пола\n" -" ├{users_city} пользователей из города {user_city}\n" -" ├{cs_uy} пользователей из других городов\n" -" ├{users_verified} верифицированных пользователей\n" -" ├{users_status} пользователей, создавшие анкету\n" -"└Дата создания бота - 10.08.2021" -msgstr "" -"📊 Statistik: \n" -"\n" -"└Derzeit sind {count_users} Benutzer in unserem Bot registriert.\n" -"└Davon:\n" -" ├{users_gender_m} männliche Benutzer\n" -" ├{users_gender_f} weibliche Benutzer\n" -" ├{users_city} Benutzer aus der Stadt {user_city}\n" -" ├{cs_uy} Benutzer aus anderen Städten\n" -" ├{users_verified} verifizierte Benutzer\n" -" ├{users_status} Benutzer, die ein Profil erstellt haben\n" -"└Bot-Erstellungsdatum - 10.08.2021" - -#~ msgid "🗒 Логи" -#~ msgstr "🗒 Logs" - -#~ msgid "Ваше новое имя: {censored}" -#~ msgstr "Ihr neuer Name ist {censored}" - -#~ msgid "Ваш новый пол: {}" -#~ msgstr "Dein neues Geschlecht: {}" - -#~ msgid "Отправьте мне новое описание анкеты:" -#~ msgstr "Senden Sie mir eine neue Profilbeschreibung:" - -#~ msgid "Комментарий принят!" -#~ msgstr "Kommentar akzeptiert!" - -#~ msgid "🫂 Пользователи" -#~ msgstr "🫂 Benutzer" - -#~ msgid "📊 Реклама" -#~ msgstr "📊 Werbung" - -#~ msgid "👀 Мониторинг" -#~ msgstr "👀 Überwachung" - -#~ msgid "🛑 Тех.Работа" -#~ msgstr "🛑 Tech.Arbeit" - -#~ msgid "Чат с админом не найден" -#~ msgstr "" - diff --git a/locales/en/LC_MESSAGES/dating.po b/locales/en/LC_MESSAGES/dating.po deleted file mode 100644 index c185a24..0000000 --- a/locales/en/LC_MESSAGES/dating.po +++ /dev/null @@ -1,1422 +0,0 @@ -# English translations for PROJECT. -# Copyright (C) 2022 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2022. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-08-28 14:39+0300\n" -"PO-Revision-Date: 2023-08-21 16:03+0300\n" -"Last-Translator: \n" -"Language: en\n" -"Language-Team: en \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" - -#: functions/dating/reaction_strategies.py:46 -#: functions/dating/reaction_strategies.py:171 -msgid "На данный момент у нас нет подходящих анкет для вас" -msgstr "At the moment we don't have any suitable questionnaires for you" - -#: functions/dating/reaction_strategies.py:52 -msgid "У вас достигнут лимит на просмотры анкет" -msgstr "You have reached the limit for profile views" - -#: functions/dating/reaction_strategies.py:61 -msgid "Кому-то понравилась твоя анкета" -msgstr "Someone liked your profile" - -#: functions/dating/reaction_strategies.py:103 handlers/users/view_event.py:51 -msgid "" -"Рад был помочь, {fullname}!\n" -"Надеюсь, ты нашел кого-то благодаря мне" -msgstr "" -"Glad to help, {fullname}!\n" -"I hope you found someone thanks to me" - -#: functions/dating/reaction_strategies.py:126 -msgid "Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉" -msgstr "Great! Hope you have a good time ;) Start chatting 👉" - -#: functions/dating/reaction_strategies.py:187 -msgid "Выберите причину жалобы:" -msgstr "" - -#: functions/dating/reaction_strategies.py:204 -msgid "" -"Жалоба от пользователя: [@{username} | {tg_id}]" -"\n" -"\n" -"На пользователя: [{owner_id}]\n" -"Причина жалобы: {reason}\n" -"Количество жалоб на пользователя: {counter_of_report}" -msgstr "" - -#: functions/dating/send_form_func.py:25 -msgid "" -"{}, {} лет, {} {verification}\n" -"\n" -msgstr "" -"{}, {} years old, {} {verification}\n" -"\n" - -#: functions/dating/send_form_func.py:28 -msgid "{commentary}" -msgstr "" - -#: functions/dating/send_form_func.py:36 -msgid "Инстаграм - {instagram}\n" -msgstr "Instagram - {instagram}\n" - -#: functions/dating/send_form_func.py:48 -msgid "" -"{}\n" -"\n" -"{}" -msgstr "" - -#: functions/dating/send_form_func.py:57 -msgid "" -"{}\n" -"\n" -"Инстаграм - {instagram}\n" -msgstr "" -"{}\n" -"\n" -"Instagram - {instagram}\n" - -#: functions/event/extra_features.py:86 -msgid "На данный момент у нас нет подходящих мероприятий для вас" -msgstr "We currently have no suitable events for you" - -#: functions/event/templates_messages.py:17 -msgid "" -"{} \n" -"Когда: {} \n" -"Где: {} \n" -"\n" -"{}" -msgstr "" -"{} \n" -"When: {} \n" -"Where: {} \n" -"\n" -"{}" - -#: functions/main_app/app_scheduler.py:12 -msgid "Несколько {} из города {} хотят познакомиться с тобой прямо сейчас" -msgstr "Several {} from {} want to meet you right now" - -#: functions/main_app/auxiliary_tools.py:71 -msgid "" -"{name}, {age} лет, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Партнерка:\n" -"Количество приглашенных друзей: {reff}\n" -"Реферальная ссылка:\n" -" {link}" -msgstr "" -"{name}, {age} years old, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Affiliate program:\n" -"Number of invited friends: {reff}\n" -"Referral link:\n" -" {link}" - -#: functions/main_app/auxiliary_tools.py:96 -msgid "" -"Фильтр по подбору партнеров:\n" -"\n" -"🚻 Необходимы пол партнера: {}\n" -"🔞 Возрастной диапазон: {}-{} лет\n" -"\n" -"🏙️ Город партнера: {}" -msgstr "" -"Partner Selection Filter:\n" -"\n" -"🚻 The gender of the partner is required: {}\n" -"🔞 Age range: {}-{} лет\n" -"\n" -"🏙️ Partner's city: {}" - -#: functions/main_app/auxiliary_tools.py:121 -msgid "" -"Приветствую вас, {fullname}!!\n" -"\n" -"{heart} QueDateBot - платформа для поиска новых знакомств.\n" -"\n" -"🪧 Новости о проекте вы можете прочитать в нашем канале - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Сотрудничество: \n" -"Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " -"@{supports}\n" -"\n" -msgstr "" -"Welcome you, {fullname}!!\n" -"\n" -"{heart} QueDateBot - a platform for finding new acquaintances.\n" -"\n" -"🪧 You can read the news about the project in our channel " -"-https://t.me/QueDateGroup \n" -"\n" -"🤝 Cooperation: \n" -"If you have a cooperation offer, write to the support agent - @{supports}" -"\n" -"\n" - -#: functions/main_app/auxiliary_tools.py:168 -msgid "" -"По вашей ссылке зарегистрировался пользователь {}!\n" -"Вы получаете дополнительных 15 ❤️" -msgstr "" -"A user {} has registered using your link!\n" -"You receive an additional 15 ❤️" - -#: functions/main_app/auxiliary_tools.py:194 -msgid "" -"Регистрация успешно завершена! \n" -"\n" -" {}, {} лет, {}\n" -"\n" -"О себе - {}" -msgstr "" -"Registration completed successfully!\n" -"\n" -"{}, {} years old, {}\n" -"\n" -"About Me - {}" - -#: functions/main_app/auxiliary_tools.py:215 -#: functions/main_app/auxiliary_tools.py:281 -msgid "Фото принято!" -msgstr "Photo taken!" - -#: functions/main_app/auxiliary_tools.py:219 -#: functions/main_app/auxiliary_tools.py:254 -#: functions/main_app/auxiliary_tools.py:290 -msgid "" -"Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" -"Если ошибка осталась, напишите агенту поддержки." -msgstr "" -"An error has occurred! Try again or send another photo. \n" -"If the error remains, write to the support agent." - -#: functions/main_app/auxiliary_tools.py:242 -msgid "" -"Во время проверки вашего фото мы обнаружили подозрительный контент!\n" -"Поэтому мы чуть-чуть подкорректировали вашу фотографию" -msgstr "" -"During the verification of your photo, we detected suspicious content!\n" -"That's why we slightly adjusted your photograph" - -#: functions/main_app/auxiliary_tools.py:262 -#, fuzzy -msgid "" -"Фото принято!\n" -"Выберите, что вы хотите изменить: " -msgstr "Choose what you want to change: " - -#: functions/main_app/auxiliary_tools.py:285 -msgid "Выберите, что вы хотите изменить: " -msgstr "Choose what you want to change: " - -#: functions/main_app/auxiliary_tools.py:336 -msgid "" -"Руководство по боту: \n" -"Страница №{}" -msgstr "" -"Bot Manual: \n" -"Page #1" - -#: functions/main_app/auxiliary_tools.py:352 -msgid "" -"Вы попали в раздел Информации бота, здесь вы можете посмотреть: " -"статистику,изменить язык, а также посмотреть наш брендбук.\n" -"\n" -"🌐 Дней работаем: {}\n" -"👤 Всего пользователей: {}\n" -msgstr "" -"You are in the Information section of the bot, where you can view:" -" statistics, change the language, and also view our brandbook.\n" -"\n" -"🌐 Days of operation: {}\n" -"👤 Total users: {}\n" - -#: functions/main_app/determin_location.py:32 -#, fuzzy -msgid "" -"Я нашел такой адрес:\n" -"{city}\n" -"Если все правильно, то подтвердите" -msgstr "" -"I found this address:\n" -"{city}\n" -"If everything is correct then confirm" - -#: handlers/echo_handler.py:13 -msgid "Эхо без состояния." -msgstr "Echo without condition." - -#: handlers/echo_handler.py:38 -msgid "Меню: " -msgstr "Menu: " - -#: handlers/admins/monitoring.py:14 -msgid "Чтобы начать мониторинг нажмите на кнопку ниже" -msgstr "To start monitoring, click on the button below" - -#: handlers/admins/monitoring.py:32 -msgid "Анкета пользователя была заблокирована" -msgstr "The user's profile has been blocked" - -#: handlers/admins/advert/advertisement.py:21 -msgid "" -"📧 Рассылка\n" -"Пришлите текст для рассылки либо фото с текстом для рассылки! Чтобы " -"отредактировать, используйте встроенный редактор телеграма!\n" -msgstr "" -"📧 Рассылка\n" -"Send the text for mailing or a photo with the text for mailing! To edit, " -"use the built-in telegram editor!\n" - -#: handlers/admins/advert/mailing/create.py:34 -#: handlers/admins/advert/mailing/create.py:124 -#: handlers/admins/advert/mailing/create.py:267 -msgid "Начинаю рассылку!" -msgstr "I'm starting the newsletter!" - -#: handlers/admins/advert/mailing/create.py:49 -#: handlers/admins/advert/mailing/create.py:137 -#: handlers/admins/advert/mailing/create.py:192 -#: handlers/admins/advert/mailing/create.py:281 -msgid "" -"Сообщение не дошло в чат {chat} Причина: \n" -"{err}" -msgstr "" -"The message did not reach the chat {chat} Reason: \n" -"{err}" - -#: handlers/admins/advert/mailing/create.py:55 -#: handlers/admins/advert/mailing/create.py:143 -#: handlers/admins/advert/mailing/create.py:198 -#: handlers/admins/advert/mailing/create.py:287 -msgid "Рассылка проведена успешно! Ее получили: {count} чатов!\n" -msgstr "" -"The mailing was carried out successfully! It was received: {count} chats!" -"\n" - -#: handlers/admins/advert/mailing/create.py:61 -msgid "Пришлите мне название кнопки!" -msgstr "Send me the button name!" - -#: handlers/admins/advert/mailing/create.py:70 -msgid "Название кнопки принято! Теперь отправьте мне ссылку для этой кнопки!" -msgstr "The name of the button is accepted! Now send me the link for this button!" - -#: handlers/admins/advert/mailing/create.py:90 -#: handlers/admins/advert/mailing/create.py:232 -msgid "" -"Вот так будет выглядеть сообщение: \n" -"\n" -"{text}\n" -"\n" -msgstr "" -"This is how the message will look like: \n" -"\n" -"{text}\n" -"\n" - -#: handlers/admins/advert/mailing/create.py:97 -#: handlers/admins/advert/mailing/create.py:239 -msgid "Вы подтверждаете отправку?" -msgstr "Do you confirm the shipment?" - -#: handlers/admins/advert/mailing/create.py:104 -#: handlers/admins/advert/mailing/create.py:246 -msgid "" -"Произошла ошибка! Скорее всего, неправильно введена ссылка! Попробуйте " -"еще раз." -msgstr "" -"An error has occurred! Most likely, the link was entered incorrectly! " -"Tryone more time." - -#: handlers/admins/advert/mailing/create.py:157 -msgid "" -"Вот сообщение: \n" -"\n" -"{text}\n" -"\n" -" Вы подтверждаете отправку? Или хотите что-то добавить?" -msgstr "" -"Here is the message: \n" -"\n" -"{text}\n" -"\n" -" Do you confirm the shipment? Or do you want to add something?" - -#: handlers/admins/settings/tech_works.py:26 -msgid "Чтобы включить/выключить технические работы, нажмите на кнопку ниже" -msgstr "To start monitoring, click on the button below" - -#: handlers/admins/settings/tech_works.py:36 -msgid "Технические работы включены" -msgstr "Technical works are enabled" - -#: handlers/admins/settings/tech_works.py:44 -msgid "Технические работы выключены" -msgstr "Technical works are disabled" - -#: handlers/groups/event_moderate.py:24 -msgid "Принято!" -msgstr "Accepted!" - -#: handlers/groups/event_moderate.py:33 -msgid "Ваше мероприятие прошло модерацию" -msgstr "Your event has passed moderation" - -#: handlers/groups/event_moderate.py:40 -msgid "Отклонено!" -msgstr "Rejected!" - -#: handlers/groups/event_moderate.py:44 -msgid "К сожалению ваше мероприятие не прошло модерацию" -msgstr "Unfortunately, your event did not pass moderation" - -#: handlers/groups/start.py:12 -msgid "" -"Привет, я бот, проекта Que Group, для верификации анкет для " -"знакомств\n" -"\n" -msgstr "" -"Hello, I am a bot from the Que Group project, for profile verification" -" for dating\n" -"\n" - -#: handlers/users/back.py:43 -msgid "Вы забанены!" -msgstr "You are banned!" - -#: handlers/users/back.py:50 -msgid "Вы вернулись в меню фильтров" -msgstr "You have returned to the filter menu" - -#: handlers/users/brandbook_handler.py:23 -msgid "" -"Руководство по боту: \n" -"Страница №1" -msgstr "" -"Bot Manual: \n" -"Page #1" - -#: handlers/users/buy_unban.py:17 -msgid "" -"💳 Сейчас вам нужно выбрать способ оплаты\n" -"\n" -"├Стоимость разблокировки - 99₽\n" -"├Оплата обычно приходить в течение 1-3 минут\n" -"├Если у вас нет Yoomoney или нет возможности\n" -"├оплатить, напишите агенту поддержки" -msgstr "" -"💳 Now you need to choose a payment method\n" -"\n" -"├ Unlocking cost - 99₽\n" -"├ Payment usually arrives within 1-3 minutes\n" -"├ If you don't have Yoomoney or the possibility to\n" -"├ pay, write to the support agent" - -#: handlers/users/buy_unban.py:38 -msgid "После оплаты нажмите 🔄 Проверить оплату" -msgstr "After payment, click 🔄 Check payment" - -#: handlers/users/buy_unban.py:57 -msgid "Поздравляем! Вы были разрабанены" -msgstr "Congratulations! You have been unbanned" - -#: handlers/users/buy_unban.py:65 -msgid "" -"Оплата не прошла! Подождите минут 10, а затем еще раз попробуйте нажать " -"кнопку ниже" -msgstr "" -"Payment didn't go through! Wait for 10 minutes and then try pressing the " -"button below again" - -#: handlers/users/change_datas.py:35 -msgid "Ваши данные: \n" -msgstr "Your datas: \n" - -#: handlers/users/change_datas.py:40 -msgid "Введите новое имя" -msgstr "Input new name" - -#: handlers/users/change_datas.py:53 -#, fuzzy -msgid "" -"Ваше новое имя: {censored}\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"The data has been successfully changed.\n" -"Choose what you want to modify: " - -#: handlers/users/change_datas.py:63 -msgid "" -"Произошла неизвестная ошибка. Попробуйте ещё раз\n" -"Возможно, Ваше сообщение слишком большое" -msgstr "" -"An unknown error has occurred. Try again\n" -"Perhaps your message is too large" - -#: handlers/users/change_datas.py:76 -msgid "Введите новый возраст" -msgstr "Input a new age" - -#: handlers/users/change_datas.py:90 -#, fuzzy -msgid "" -"Ваш новый возраст: {messages}\n" -"Выберите, что вы хотите изменить: " -msgstr "Your new age: {messages}" - -#: handlers/users/change_datas.py:99 handlers/users/registration.py:163 -msgid "Вы ввели недопустимое число, попробуйте еще раз" -msgstr "You entered an invalid number, try again" - -#: handlers/users/change_datas.py:104 -msgid "Вы ввели не число, попробуйте еще раз" -msgstr "You entered an invalid number, try again" - -#: handlers/users/change_datas.py:112 -msgid "Введите новый город" -msgstr "Input new city" - -#: handlers/users/change_datas.py:124 -msgid "Мы не смогли найти город {city}. Попробуйте ещё раз" -msgstr "We couldn't find the city {city}. Please try again" - -#: handlers/users/change_datas.py:134 -msgid "" -"Данные успешно изменены.\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"The data has been successfully changed.\n" -"Choose what you want to modify: " - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♂️ Мужской" -msgstr "👱🏻‍♂️ Male" - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♀️ Женский" -msgstr "👱🏻‍♀️ Female" - -#: handlers/users/change_datas.py:145 -msgid "Выберите новый пол: " -msgstr "Choose new gender: " - -#: handlers/users/change_datas.py:155 -#, fuzzy -msgid "" -"Ваш новый пол: {}\n" -"Выберите, что вы хотите изменить: " -msgstr "Choose what you want to change: " - -#: handlers/users/change_datas.py:167 -msgid "Отправьте мне новую фотографию" -msgstr "Send me a new photo" - -#: handlers/users/change_datas.py:191 handlers/users/registration.py:244 -msgid "Произошла ошибка, проверьте настройки конфиденциальности" -msgstr "An error occurred, please check your privacy settings" - -#: handlers/users/change_datas.py:232 -#, fuzzy -msgid "Отправьте сообщение о себе" -msgstr "Send a voice message" - -#: handlers/users/change_datas.py:247 -#, fuzzy -msgid "" -"Комментарий принят!\n" -"Выберите, что вы хотите изменить: " -msgstr "Comment accepted! Choose who you want to find: " - -#: handlers/users/change_datas.py:254 -msgid "" -"Произошла ошибка! Попробуйте еще раз изменить описание. Возможно, Ваше " -"сообщение слишком большое\n" -"Если ошибка осталась, напишите в поддержку." -msgstr "" -"An error has occurred! Try again or send another photo. \n" -"If the error remains, write to the support agent." - -#: handlers/users/change_datas.py:267 -msgid "" -"Напишите имя своего аккаунта\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" -"Write your account name\n" -"\n" -"Examples:\n" -"@unknown\n" -"https://www.instagram.com/unknown" - -#: handlers/users/change_datas.py:289 -msgid "Ваш аккаунт успешно добавлен" -msgstr "Your account has been successfully added" - -#: handlers/users/change_datas.py:293 handlers/users/verification.py:45 -msgid "Вы были возвращены в меню" -msgstr "You have been returned to the menu" - -#: handlers/users/change_datas.py:297 -msgid "" -"Вы ввели неправильную ссылку или имя аккаунта.\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" - -#: handlers/users/change_datas.py:304 -msgid "Возникла ошибка. Попробуйте еще раз" -msgstr "An error has occurred. Try again" - -#: handlers/users/change_event_datas.py:16 -msgid "Вы перешли в меню изменения данных мероприятия" -msgstr "You have entered the event data change menu" - -#: handlers/users/change_event_datas.py:23 -msgid "Напишите новое название вашего мероприятия" -msgstr "Write the new name of your event" - -#: handlers/users/change_event_datas.py:35 -#: handlers/users/change_event_datas.py:53 -msgid "Данные изменены" -msgstr "Data saved" - -#: handlers/users/change_event_datas.py:41 -msgid "Напишите новое описание вашего мероприятия" -msgstr "Write a new description for your event" - -#: handlers/users/event_handler.py:31 -msgid "Вы перешли в меню афиш" -msgstr "You have entered the event menu" - -#: handlers/users/event_handler.py:48 -msgid "Введите название мероприятие" -msgstr "Enter the name of the event" - -#: handlers/users/event_handler.py:55 -msgid "" -"Вы уже создали мероприятие, которое проходит модерацию. Дождитесь " -"проверки, пожалуйста" -msgstr "" -"You have already created an event that is under moderation. Please wait " -"for verification" - -#: handlers/users/event_handler.py:63 -msgid "" -"Прочитайте сообщение и не нажимайте на кнопку, пока ваше мероприятие не " -"пройдет модерацию" -msgstr "" -"Read the message and do not press the button until your event passes " -"moderation" - -#: handlers/users/event_handler.py:78 -msgid "Пожалуйста, выберите дату: " -msgstr "Select date: " - -#: handlers/users/event_handler.py:83 -msgid "" -"Длинна вашего сообщение превышает допустимую.\n" -"Попробуйте ещё раз" -msgstr "" - -#: handlers/users/event_handler.py:99 -msgid "Вы не можете проводить мероприятие в прошлом" -msgstr "You cannot hold an event in the past" - -#: handlers/users/event_handler.py:105 -msgid "Теперь напишите место проведения" -msgstr "Now write the venue" - -#: handlers/users/event_handler.py:126 -msgid "Вы ввели слишком длинное название городаПопробуйте ещё раз." -msgstr "You entered a city name that is too long. Please try again." - -#: handlers/users/event_handler.py:132 -msgid "" -"Произошла неизвестная ошибка! Попробуйте еще раз.\n" -"Вероятнее всего вы ввели город неправильно" -msgstr "" -"An unknown error has occurred! Try again.\n" -"Most likely you entered the city incorrectly" - -#: handlers/users/event_handler.py:142 -msgid "Хорошо, теперь напишите короткое или длинное описание вашего мероприятия" -msgstr "Alright, now write a short or long description of your event" - -#: handlers/users/event_handler.py:158 -msgid "И напоследок, пришлите постер вашего мероприятия" -msgstr "And finally, send me your photo" - -#: handlers/users/event_handler.py:164 -msgid "Ваше сообщение слишком длинное.Попробуйте написать короче" -msgstr "Your message is too long. Try to write shorter" - -#: handlers/users/event_handler.py:178 -msgid "Фото принято" -msgstr "Photo taken" - -#: handlers/users/event_handler.py:200 -msgid "Ваше мероприятие отправлено на модерацию" -msgstr "Your event has been submitted for moderation" - -#: handlers/users/event_list.py:23 -msgid "На данный момент вы никуда не записались" -msgstr "At the moment we don't have any suitable questionnaires for you" - -#: handlers/users/filters.py:23 handlers/users/filters.py:29 -msgid "Вы перешли в раздел с фильтрами" -msgstr "You have entered the section with filters" - -#: handlers/users/filters.py:41 -msgid "Напишите минимальный возраст" -msgstr "Write the minimum age" - -#: handlers/users/filters.py:53 -msgid "Теперь введите максимальный возраст" -msgstr "The data is saved, now enter the maximum age" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♂️ Парня" -msgstr "👱🏻‍♂️ Guy" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♀️ Девушку" -msgstr "👱🏻‍♀️ Girl" - -#: handlers/users/filters.py:76 -msgid "Выберите, кого вы хотите найти:" -msgstr "Choose who you want to find:" - -#: handlers/users/filters.py:84 handlers/users/filters.py:111 -msgid "Данные сохранены" -msgstr "Data saved" - -#: handlers/users/filters.py:92 -msgid "Напишите город вашего будущего партнера" -msgstr "Write the city of your future partner" - -#: handlers/users/filters.py:103 handlers/users/filters.py:144 -msgid "Произошла ошибка, попробуйте еще раз" -msgstr "An error has occurred, please try again" - -#: handlers/users/filters.py:124 -msgid "Вы перешли в меню настроек фильтров для мероприятий" -msgstr "You have entered the event filters settings menu" - -#: handlers/users/filters.py:132 -msgid "Напишите город, в котором бы хотели сходить куда-нибудь" -msgstr "Write the city where you would like to go somewhere" - -#: handlers/users/registration.py:42 -msgid "Пройдите опрос, чтобы зарегистрироваться" -msgstr "Take the survey to register" - -#: handlers/users/registration.py:52 -msgid "" -"Вы уже зарегистрированы, если вам нужно изменить анкету, то нажмите на " -"кнопку ниже" -msgstr "" - -#: handlers/users/registration.py:66 -msgid "Выберите пол" -msgstr "Choose a gender" - -#: handlers/users/registration.py:88 -msgid "Теперь расскажите о себе:\n" -msgstr "Now tell us about yourself:\n" - -#: handlers/users/registration.py:105 -msgid "Комментарий принят! Выберите, кого вы хотите найти: " -msgstr "Comment accepted! Choose who you want to find: " - -#: handlers/users/registration.py:111 -msgid "" -"Произошла неизвестная ошибка! Попробуйте изменить комментарий позже в " -"разделе \"Меню\"\n" -"\n" -"Выберите, кого вы хотите найти: " -msgstr "" -"An unknown error occurred! Try changing the comment later in the \"Menu\"" -" section\n" -"\n" -"Choose who you want to find: " - -#: handlers/users/registration.py:125 -msgid "Отлично! Теперь напишите мне ваше имя, которое будут все видеть в анкете" -msgstr "" -"Great! Now write me your name, which everyone will see in the " -"questionnaire" - -#: handlers/users/registration.py:145 -msgid "Введите сколько вам лет:" -msgstr "Input your age:" - -#: handlers/users/registration.py:170 -msgid "Вы ввели не число" -msgstr "You didn't input a number" - -#: handlers/users/registration.py:175 -msgid "Нажмите на кнопку ниже, чтобы определить ваш местоположение!" -msgstr "Press the button below to determine your location!" - -#: handlers/users/registration.py:188 -#, fuzzy -msgid "Мы не смогли найти такой город, попробуйте еще раз" -msgstr "We couldn't find the city {city}. Please try again" - -#: handlers/users/registration.py:211 handlers/users/registration.py:224 -msgid "" -"И напоследок, Пришлите мне вашу фотографию (отправлять надо сжатое " -"изображение, а не как документ)" -msgstr "" -"And finally, send me your photo (send a compressed image, not as a " -"document)" - -#: handlers/users/sponsor.py:10 -msgid "" -"Наш проект работает на Open Source и мы будем рады,если вы нам " -"поможете развивать проект.\n" -"\n" -"С помощью кнопки 💰 Донат вы можете отправить своё пожертвование" -msgstr "" -"Our project works on Open Source and we will be glad if you help " -"us develop the project.\n" -"\n" -"Using the button 💰 Donat you can send your donation" - -#: handlers/users/start_handler.py:27 -msgid "Вам необходимо зарегистрировать агента(ов) тех поддержки" -msgstr "You need to register support agent(s)" - -#: handlers/users/start_handler.py:36 -msgid "Вас нет в базе данной" -msgstr "You are not in the database" - -#: handlers/users/start_handler.py:42 handlers/users/start_handler.py:47 -msgid "Выберите язык" -msgstr "Select language" - -#: handlers/users/start_handler.py:57 -msgid "Язык был успешно изменен. Введите команду /start" -msgstr "The language has been successfully changed. Enter the /start command" - -#: handlers/users/start_handler.py:61 -msgid "Произошла какая-то ошибка. Введите команду /start и попробуйте еще раз" -msgstr "An error has occurred, please try again" - -#: handlers/users/support_handler.py:20 -msgid "Хотите связаться с тех поддержкой? Нажмите на кнопку ниже!" -msgstr "Do you want to contact technical support? Click on the button below!" - -#: handlers/users/support_handler.py:25 handlers/users/support_handler.py:52 -msgid "К сожалению, сейчас нет свободных операторов. Попробуйте позже." -msgstr "Unfortunately, there are no free operators right now. Try again later." - -#: handlers/users/support_handler.py:41 -msgid "Вы обратились в техническую поддержку. Ждем ответа от оператора!" -msgstr "" -"You have contacted technical support. We are waiting for a response from " -"the operator!" - -#: handlers/users/support_handler.py:64 -msgid "С вами хочет связаться пользователь {full_name}" -msgstr "The user {full_name} wants to contact you" - -#: handlers/users/support_handler.py:79 -msgid "К сожалению, пользователь уже передумал." -msgstr "Unfortunately, the user has already changed his mind." - -#: handlers/users/support_handler.py:91 -msgid "" -"Вы на связи с пользователем!\n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"You are in touch with the user!\n" -"To end the communication, click on the button." - -#: handlers/users/support_handler.py:100 -msgid "" -"Техподдержка на связи! Можете писать сюда свое сообщение. \n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"Technical support is in touch! You can write your message here. \n" -"To end the communication, click on the button." - -#: handlers/users/support_handler.py:115 -msgid "Дождитесь ответа оператора или отмените сеанс" -msgstr "Wait for the operator's response or cancel the session" - -#: handlers/users/support_handler.py:131 -msgid "Пользователь завершил сеанс техподдержки" -msgstr "The user has completed the technical support session" - -#: handlers/users/support_handler.py:135 -msgid "Вы завершили сеанс и были возвращены в главное меню" -msgstr "You have completed the session and have been returned to the main menu" - -#: handlers/users/user_profile.py:23 -msgid "" -"Ваша анкета удалена!\n" -"Я надеюсь вы кого-нибудь нашли" -msgstr "" -"Your profile has been deleted!\n" -"I hope you found someone" - -#: handlers/users/verification.py:17 -msgid "Чтобы пройти верификацию вам нужно отправить свой контакт" -msgstr "To pass verification, you need to send your contact" - -#: handlers/users/verification.py:33 -msgid "" -"Спасибо, {contact_full_name}.\n" -"Ваш номер {contact_phone_number} был получен." -msgstr "" -"Thank you, {contact_full_name}.\n" -"Your {contact_phone_number} number has been received." - -#: handlers/users/verification.py:50 -msgid "Ваш номер недействителен, попробуйте еще раз." -msgstr "Your number is invalid, try again." - -#: handlers/users/view_event.py:27 -msgid "На данный момент вы просмотрели все существующие анкеты" -msgstr "At the moment, you have viewed all existing profiles" - -#: handlers/users/view_ques.py:73 -#, fuzzy -msgid "Жалоба успешно отправлена" -msgstr "Your account has been successfully added" - -#: handlers/users/view_ques.py:112 -msgid "" -"Слишком много ❤️ за сегодня.\n" -"\n" -"Пригласи друзей и получи больше ❤️\n" -"\n" -"https://t.me/{}?start={}" -msgstr "" -"Too many ❤️ for today.\n" -"\n" -"Invite friends and get more ❤️\n" -"\n" -"https://t.me/{}?start={}" - -#: keyboards/admin/inline/customers.py:12 -#, fuzzy -msgid "🔍 Найти пользователя" -msgstr "Respond user" - -#: keyboards/admin/inline/customers.py:23 -#, fuzzy -msgid "🟢 Разблокировать" -msgstr "Unblock" - -#: keyboards/admin/inline/customers.py:28 -#, fuzzy -msgid "🚫 Заблокировать" -msgstr "Unblock" - -#: keyboards/admin/inline/mailing.py:8 -#, fuzzy -msgid "📧 Рассылка" -msgstr "Mailing" - -#: keyboards/admin/inline/mailing.py:16 keyboards/admin/inline/mailing.py:31 -#: keyboards/inline/admin_inline.py:9 -msgid "Подтвердить отправку" -msgstr "Confirm sending" - -#: keyboards/admin/inline/mailing.py:19 -msgid "Добавить кнопку" -msgstr "Add button" - -#: keyboards/admin/inline/mailing.py:21 keyboards/admin/inline/mailing.py:33 -#: keyboards/inline/cancel_inline.py:8 -msgid "Отмена" -msgstr "Cancel" - -#: keyboards/admin/inline/payments.py:9 -msgid "⚙️ Настройки" -msgstr "" - -#: keyboards/admin/inline/payments.py:11 -msgid "📝 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:8 -msgid "📈 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:9 keyboards/admin/inline/setting.py:8 -#, fuzzy -msgid "*️⃣ Добавить" -msgstr "🗑️ Delete" - -#: keyboards/admin/inline/ref.py:10 keyboards/admin/inline/setting.py:9 -#, fuzzy -msgid "❌ Удалить" -msgstr "🗑️ Delete" - -#: keyboards/admin/inline/ref.py:11 keyboards/admin/inline/setting.py:10 -#, fuzzy -msgid "◀️ Назад" -msgstr "⏪️ Back" - -#: keyboards/admin/inline/reply_menu.py:9 -#, fuzzy -msgid "🙅🏻‍♂️ Отменить" -msgstr "🖊️ Modify" - -#: keyboards/admin/inline/reply_menu.py:17 -msgid "👮‍♂️ Админ Состав" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:19 -#, fuzzy -msgid "📞 Сменить контакты" -msgstr "📞 Contacts" - -#: keyboards/admin/inline/reply_menu.py:29 -msgid "🗒 Выгрузить юзеров | .txt" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:32 -msgid "🗒 Выгрузить конфиги и логи" -msgstr "" - -#: keyboards/default/admin_default.py:8 -msgid "Рассылка" -msgstr "Mailing" - -#: keyboards/default/admin_default.py:9 -msgid "Сообщение по id" -msgstr "Message by id" - -#: keyboards/default/admin_default.py:10 -msgid "Посчитать людей и чаты" -msgstr "Count people and chats" - -#: keyboards/default/admin_default.py:11 -msgid "Мониторинг" -msgstr "Monitoring" - -#: keyboards/default/admin_default.py:12 -msgid "Тех.Работа" -msgstr "Tech.Works" - -#: keyboards/default/get_contact_default.py:8 -msgid "📱 Отправить" -msgstr "📱 Send" - -#: keyboards/default/get_location_default.py:9 -msgid "🗺 Определить автоматически" -msgstr "🗺 Detect automatically" - -#: keyboards/default/get_photo.py:8 -msgid "Взять из профиля" -msgstr "" - -#: keyboards/inline/admin_inline.py:18 -msgid "Включить" -msgstr "Enable" - -#: keyboards/inline/admin_inline.py:21 -msgid "Выключить" -msgstr "Disable" - -#: keyboards/inline/admin_inline.py:33 -msgid "Разблокировать" -msgstr "Unblock" - -#: keyboards/inline/back_inline.py:8 -#: keyboards/inline/change_data_profile_inline.py:15 -#: keyboards/inline/filters_inline.py:42 keyboards/inline/language_inline.py:22 -#: keyboards/inline/poster_inline.py:31 keyboards/inline/poster_inline.py:49 -#: keyboards/inline/poster_inline.py:63 -#: keyboards/inline/registration_inline.py:12 -#: keyboards/inline/settings_menu.py:12 keyboards/inline/sponsor_inline.py:10 -#: keyboards/inline/sponsor_inline.py:21 -msgid "⏪️ Вернуться в меню" -msgstr "⏪ Return to the menu" - -#: keyboards/inline/cancel_inline.py:16 -#: keyboards/inline/change_data_profile_inline.py:28 -#, fuzzy -msgid "❌ Остановить" -msgstr "⏪️ Stop" - -#: keyboards/inline/change_data_profile_inline.py:8 -msgid "👤 Имя" -msgstr "👤 Name" - -#: keyboards/inline/change_data_profile_inline.py:9 -msgid "⚧ Пол" -msgstr "⚧ Gender" - -#: keyboards/inline/change_data_profile_inline.py:10 -msgid "📅 Возраст" -msgstr "📅 Age" - -#: keyboards/inline/change_data_profile_inline.py:11 -msgid "🏙 Город" -msgstr "🏙 City" - -#: keyboards/inline/change_data_profile_inline.py:12 -msgid "📷 Фото" -msgstr "📷 Photo" - -#: keyboards/inline/change_data_profile_inline.py:13 -msgid "📝 О себе" -msgstr "📝 About me" - -#: keyboards/inline/filters_inline.py:9 -msgid "🎉 Мероприятия" -msgstr "🎉 Events" - -#: keyboards/inline/filters_inline.py:12 -msgid "❤️ Знакомства" -msgstr "❤️ Dating" - -#: keyboards/inline/filters_inline.py:14 keyboards/inline/filters_inline.py:31 -#: keyboards/inline/guide_inline.py:15 -msgid "⏪️ Назад" -msgstr "⏪️ Back" - -#: keyboards/inline/filters_inline.py:23 -msgid "🏙️ Город партнера" -msgstr "🏙️ Partner City" - -#: keyboards/inline/filters_inline.py:26 -msgid "🔞 Возр.диапазон" -msgstr "🔞 Age range" - -#: keyboards/inline/filters_inline.py:29 -msgid "🚻 Пол партнера" -msgstr "🚻 Partner's gender" - -#: keyboards/inline/filters_inline.py:40 -msgid "🏙️ Город" -msgstr "🏙️ City" - -#: keyboards/inline/guide_inline.py:21 -msgid "Вперед ➡️" -msgstr "Forward ➡️" - -#: keyboards/inline/guide_inline.py:25 -msgid "❌ Закрыть" -msgstr "❌ Close" - -#: keyboards/inline/language_inline.py:13 -msgid "🇷🇺 Русский" -msgstr "🇷🇺 Russian" - -#: keyboards/inline/language_inline.py:14 -msgid "🇩🇪 Немецкий" -msgstr "🇩🇪 Deutsche" - -#: keyboards/inline/language_inline.py:15 -msgid "🇬🇧 Английский" -msgstr "🇬🇧 English" - -#: keyboards/inline/language_inline.py:16 -msgid "🇮🇩 Индонезийский" -msgstr "🇮🇩 Indonesian" - -#: keyboards/inline/main_menu_inline.py:26 -msgid "➕ Регистрация" -msgstr "➕ Registration" - -#: keyboards/inline/main_menu_inline.py:28 keyboards/inline/settings_menu.py:10 -msgid "🌐 Язык" -msgstr "🌐 Language" - -#: keyboards/inline/main_menu_inline.py:30 -msgid "👤 Моя анекта" -msgstr "👤 My profile" - -#: keyboards/inline/main_menu_inline.py:32 -msgid "⚙️ Фильтры" -msgstr "⚙️ Filters" - -#: keyboards/inline/main_menu_inline.py:33 -msgid "💌 Найти пару" -msgstr "💌 Find date" - -#: keyboards/inline/main_menu_inline.py:34 -msgid "🗓️ Афиша" -msgstr "🗓️ Events" - -#: keyboards/inline/main_menu_inline.py:35 -msgid "🆘 Поддержка" -msgstr "🆘 Support" - -#: keyboards/inline/main_menu_inline.py:37 -msgid "ℹ️ Информация" -msgstr "ℹ️ Information" - -#: keyboards/inline/menu_profile_inline.py:10 -msgid "✅ Верификация" -msgstr "✅ Verification" - -#: keyboards/inline/menu_profile_inline.py:16 -msgid "🖊️ Изменить" -msgstr "🖊️ Modify" - -#: keyboards/inline/menu_profile_inline.py:18 -msgid "🗑️ Удалить" -msgstr "🗑️ Delete" - -#: keyboards/inline/menu_profile_inline.py:19 -msgid "⏪ Назад" -msgstr "⏪ Back" - -#: keyboards/inline/payments_inline.py:9 -msgid "💳 ЮMoney" -msgstr "💳 Yoomoney" - -#: keyboards/inline/payments_inline.py:16 -msgid "💳 Оплатить" -msgstr "💳 Pay" - -#: keyboards/inline/payments_inline.py:18 -msgid "🔄 Проверить оплату" -msgstr "🔄 Check payment" - -#: keyboards/inline/poster_inline.py:21 -msgid "✍️Создать афишу" -msgstr "✍️ Create event" - -#: keyboards/inline/poster_inline.py:24 -msgid "🎭 Смотреть афиши" -msgstr "🚀 View posters" - -#: keyboards/inline/poster_inline.py:27 -msgid "📝 Мои записи" -msgstr "📝 My records" - -#: keyboards/inline/poster_inline.py:29 -msgid "📃 Моё событие" -msgstr "📃 My event" - -#: keyboards/inline/poster_inline.py:46 -msgid "✍️ Изменить" -msgstr "✍️ Edit" - -#: keyboards/inline/poster_inline.py:58 -msgid "Название" -msgstr "Title" - -#: keyboards/inline/poster_inline.py:60 -msgid "Описание" -msgstr "Description" - -#: keyboards/inline/poster_inline.py:73 -msgid "✅ Одобрить" -msgstr "✅ Approve" - -#: keyboards/inline/poster_inline.py:76 -msgid "❌ Отклонить" -msgstr "❌ Reject" - -#: keyboards/inline/poster_inline.py:85 -msgid "Пойду!" -msgstr "I'm going!" - -#: keyboards/inline/poster_inline.py:88 -msgid "Не интересно" -msgstr "Not interested" - -#: keyboards/inline/poster_inline.py:91 keyboards/inline/poster_inline.py:103 -#: keyboards/inline/poster_inline.py:112 -msgid "⏪️ Остановить" -msgstr "⏪️ Stop" - -#: keyboards/inline/poster_inline.py:101 -msgid "❌ Отменить запись" -msgstr "❌ Cancel Reservation" - -#: keyboards/inline/questionnaires_inline.py:30 -#, fuzzy -msgid "💤 Остановить" -msgstr "⏪️ Stop" - -#: keyboards/inline/questionnaires_inline.py:34 -msgid "🚫 Забанить" -msgstr "🚫 Ban" - -#: keyboards/inline/questionnaires_inline.py:38 -msgid "Следующий" -msgstr "Next" - -#: keyboards/inline/questionnaires_inline.py:74 -msgid "🚀 Смотреть" -msgstr "🚀 View form" - -#: keyboards/inline/questionnaires_inline.py:82 -msgid "👉 Перейти в чат" -msgstr "👉 Go to Chat" - -#: keyboards/inline/questionnaires_inline.py:89 -msgid "⏪️ Вернуться к просмотру анкет" -msgstr "⏪️ Back to view forms" - -#: keyboards/inline/registration_inline.py:9 -msgid "🖌️ Пройти опрос в боте" -msgstr "🖌️ Pass a survey in a bot" - -#: keyboards/inline/registration_inline.py:21 -msgid "✅ Да все хорошо!" -msgstr "✅ All are good!" - -#: keyboards/inline/settings_menu.py:8 -msgid "📚 Брендбук" -msgstr "📚 Brand-book" - -#: keyboards/inline/settings_menu.py:9 -msgid "📞 Контакты" -msgstr "📞 Contacts" - -#: keyboards/inline/support_inline.py:37 -msgid "Ответить пользователю" -msgstr "Respond user" - -#: keyboards/inline/support_inline.py:45 -msgid "Написать оператору" -msgstr "Write operator" - -#: keyboards/inline/support_inline.py:60 keyboards/inline/support_inline.py:72 -msgid "Завершить сеанс" -msgstr "End session" - -#: middlewares/BanCheck.py:44 -msgid "😢 Вы заблокированы!" -msgstr "😢 You are banned!" - -#: middlewares/IsMaintenanceCheck.py:26 -msgid "Ведутся технические работы" -msgstr "Technical works are in progress" - -#: middlewares/LinkCheck.py:38 -msgid "" -"Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " -"подпишитесь! Ссылки ниже: " -msgstr "" -"You haven't subscribed to all channels! To continue using the bot, please" -" subscribe! Links below: " - -#: utils/notify_admins.py:24 -msgid "Оповещение администрации..." -msgstr "" - -#: utils/notify_admins.py:28 -msgid "Бот был успешно запущен" -msgstr "" - -#: utils/statistics.py:16 -msgid "" -"📊 Статистика: \n" -"\n" -"└Сейчас в нашем боте {count_users} пользователей\n" -"└Из них:\n" -" ├{users_gender_m} пользователей мужского пола\n" -" ├{users_gender_f} пользователей женского пола\n" -" ├{users_city} пользователей из города {user_city}\n" -" ├{cs_uy} пользователей из других городов\n" -" ├{users_verified} верифицированных пользователей\n" -" ├{users_status} пользователей, создавшие анкету\n" -"└Дата создания бота - 10.08.2021" -msgstr "" -"📊 Statistics: \n" -"\n" -"└There are currently {count_users} users in our bot\n" -"└Among them:\n" -" ├{users_gender_m} male users\n" -" ├{users_gender_f} female users\n" -" ├{users_city} users from {user_city}\n" -" ├{cs_uy} users from other cities\n" -" ├{users_verified} verified users\n" -" ├{users_status} users who created a profile\n" -"└Bot creation date - August 10, 2021" - -#~ msgid "" -#~ "Вы попали в раздел настроек бота," -#~ " здесь вы можете посмотреть: " -#~ "статистику,изменить язык, отключить уведомления, " -#~ "а также узнать информацию.\n" -#~ "\n" -#~ "🌐 Дней работаем: {}\n" -#~ "👤 Всего пользователей: {}\n" -#~ msgstr "" -#~ "You are in the settings section" -#~ " of the bot, where you can " -#~ "view: statistics, change the language, " -#~ "disable notifications, and also find " -#~ "information.\n" -#~ "\n" -#~ "🌐 Days of operation: {}\n" -#~ "👤 Total users: {}\n" - -#~ msgid "🇫🇷 Французский" -#~ msgstr "" - -#~ msgid "🟢 Запустить бота" -#~ msgstr "" - -#~ msgid "⚒ Админ-Меню" -#~ msgstr "" - -#~ msgid "🗒 Логи" -#~ msgstr "" - -#~ msgid "Ваше новое имя: {censored}" -#~ msgstr "Your new name: {censored}" - -#~ msgid "Ваш новый пол: {}" -#~ msgstr "Your new gender: {}" - -#~ msgid "Отправьте мне новое описание анкеты:" -#~ msgstr "Send me a new description of the questionnaire:" - -#~ msgid "Комментарий принят!" -#~ msgstr "Comment accepted!" - -#~ msgid "🫂 Пользователи" -#~ msgstr "Respond user" - -#~ msgid "📊 Реклама" -#~ msgstr "" - -#~ msgid "👀 Мониторинг" -#~ msgstr "Monitoring" - -#~ msgid "🛑 Тех.Работа" -#~ msgstr "Tech.Works" - -#~ msgid "Чат с админом не найден" -#~ msgstr "" - diff --git a/locales/in/LC_MESSAGES/dating.po b/locales/in/LC_MESSAGES/dating.po deleted file mode 100644 index 28a4e83..0000000 --- a/locales/in/LC_MESSAGES/dating.po +++ /dev/null @@ -1,1408 +0,0 @@ -# Indonesian (Indonesia) translations for PROJECT. -# Copyright (C) 2023 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2023. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-08-28 14:39+0300\n" -"PO-Revision-Date: 2023-08-21 16:49+0300\n" -"Last-Translator: \n" -"Language: id_ID\n" -"Language-Team: id_ID \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" - -#: functions/dating/reaction_strategies.py:46 -#: functions/dating/reaction_strategies.py:171 -msgid "На данный момент у нас нет подходящих анкет для вас" -msgstr "Saat ini kami tidak memiliki profil yang sesuai untuk Anda" - -#: functions/dating/reaction_strategies.py:52 -msgid "У вас достигнут лимит на просмотры анкет" -msgstr "Anda telah mencapai batas melihat profil" - -#: functions/dating/reaction_strategies.py:61 -msgid "Кому-то понравилась твоя анкета" -msgstr "Ada seseorang yang menyukai profil Anda" - -#: functions/dating/reaction_strategies.py:103 handlers/users/view_event.py:51 -msgid "" -"Рад был помочь, {fullname}!\n" -"Надеюсь, ты нашел кого-то благодаря мне" -msgstr "" -"Saya senang bisa membantu, {fullname}!\n" -"Saya harap Anda menemukan seseorang berkat bantuan saya" - -#: functions/dating/reaction_strategies.py:126 -msgid "Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉" -msgstr "Bagus! Saya harap Anda memiliki waktu yang baik ;) Mulailah berbicara 👉" - -#: functions/dating/reaction_strategies.py:187 -msgid "Выберите причину жалобы:" -msgstr "" - -#: functions/dating/reaction_strategies.py:204 -msgid "" -"Жалоба от пользователя: [@{username} | {tg_id}]" -"\n" -"\n" -"На пользователя: [{owner_id}]\n" -"Причина жалобы: {reason}\n" -"Количество жалоб на пользователя: {counter_of_report}" -msgstr "" - -#: functions/dating/send_form_func.py:25 -msgid "" -"{}, {} лет, {} {verification}\n" -"\n" -msgstr "" -"{}, {} tahun, {} {verification}\n" -"\n" - -#: functions/dating/send_form_func.py:28 -msgid "{commentary}" -msgstr "{commentary}" - -#: functions/dating/send_form_func.py:36 -msgid "Инстаграм - {instagram}\n" -msgstr "Instagram - {instagram}\n" - -#: functions/dating/send_form_func.py:48 -msgid "" -"{}\n" -"\n" -"{}" -msgstr "" -"{}\n" -"\n" -"{}" - -#: functions/dating/send_form_func.py:57 -msgid "" -"{}\n" -"\n" -"Инстаграм - {instagram}\n" -msgstr "" -"{}\n" -"\n" -"Instagram - {instagram}\n" - -#: functions/event/extra_features.py:86 -msgid "На данный момент у нас нет подходящих мероприятий для вас" -msgstr "Saat ini kami tidak memiliki acara yang cocok untuk Anda hadiri" - -#: functions/event/templates_messages.py:17 -msgid "" -"{} \n" -"Когда: {} \n" -"Где: {} \n" -"\n" -"{}" -msgstr "" -"{} \n" -"Ketika: {} \n" -"Di mana: {} \n" -"\n" -"{}" - -#: functions/main_app/app_scheduler.py:12 -msgid "Несколько {} из города {} хотят познакомиться с тобой прямо сейчас" -msgstr "Beberapa {} dari {} ingin bertemu dengan Anda sekarang" - -#: functions/main_app/auxiliary_tools.py:71 -msgid "" -"{name}, {age} лет, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Партнерка:\n" -"Количество приглашенных друзей: {reff}\n" -"Реферальная ссылка:\n" -" {link}" -msgstr "" -"{name}, {age} tahun, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Afiliasi:\n" -"Jumlah teman yang diundang: {reff}\n" -"Tautan referensi:\n" -" {link}" - -#: functions/main_app/auxiliary_tools.py:96 -msgid "" -"Фильтр по подбору партнеров:\n" -"\n" -"🚻 Необходимы пол партнера: {}\n" -"🔞 Возрастной диапазон: {}-{} лет\n" -"\n" -"🏙️ Город партнера: {}" -msgstr "" -"Filter pencarian pasangan:\n" -"\n" -"🚻 Jenis kelamin pasangan yang diinginkan: {}\n" -"🔞 Rentang usia: {}-{} tahun\n" -"\n" -"🏙️ Kota pasangan: {}" - -#: functions/main_app/auxiliary_tools.py:121 -msgid "" -"Приветствую вас, {fullname}!!\n" -"\n" -"{heart} QueDateBot - платформа для поиска новых знакомств.\n" -"\n" -"🪧 Новости о проекте вы можете прочитать в нашем канале - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Сотрудничество: \n" -"Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " -"@{supports}\n" -"\n" -msgstr "" -"Selamat datang, {fullname}!!\n" -"\n" -"{heart} QueDateBot - platform untuk mencari teman baru.\n" -"\n" -"🪧 Anda dapat membaca berita tentang proyek kami di saluran kami - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Kerjasama: \n" -"Jika Anda memiliki tawaran kerjasama, silakan hubungi agen dukungan - " -"@{supports}\n" -"\n" - -#: functions/main_app/auxiliary_tools.py:168 -msgid "" -"По вашей ссылке зарегистрировался пользователь {}!\n" -"Вы получаете дополнительных 15 ❤️" -msgstr "" -"Pengguna {} telah mendaftar melalui tautan Anda!\n" -"Anda mendapatkan 15 ❤️ tambahan" - -#: functions/main_app/auxiliary_tools.py:194 -msgid "" -"Регистрация успешно завершена! \n" -"\n" -" {}, {} лет, {}\n" -"\n" -"О себе - {}" -msgstr "" -"Registrasi berhasil! \n" -"\n" -" {}, {} tahun, {}\n" -"\n" -"Tentang Saya - {}" - -#: functions/main_app/auxiliary_tools.py:215 -#: functions/main_app/auxiliary_tools.py:281 -msgid "Фото принято!" -msgstr "Foto diterima!" - -#: functions/main_app/auxiliary_tools.py:219 -#: functions/main_app/auxiliary_tools.py:254 -#: functions/main_app/auxiliary_tools.py:290 -msgid "" -"Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" -"Если ошибка осталась, напишите агенту поддержки." -msgstr "" -"Terjadi kesalahan! Silakan coba lagi atau kirim foto lain. \n" -"Jika masalah masih berlanjut, hubungi agen dukungan." - -#: functions/main_app/auxiliary_tools.py:242 -msgid "" -"Во время проверки вашего фото мы обнаружили подозрительный контент!\n" -"Поэтому мы чуть-чуть подкорректировали вашу фотографию" -msgstr "" -"Selama pemeriksaan foto Anda, kami menemukan konten yang mencurigakan!\n" -"Kami melakukan sedikit perubahan pada foto Anda" - -#: functions/main_app/auxiliary_tools.py:262 -#, fuzzy -msgid "" -"Фото принято!\n" -"Выберите, что вы хотите изменить: " -msgstr "Pilih apa yang ingin Anda ubah: " - -#: functions/main_app/auxiliary_tools.py:285 -msgid "Выберите, что вы хотите изменить: " -msgstr "Pilih apa yang ingin Anda ubah: " - -#: functions/main_app/auxiliary_tools.py:336 -msgid "" -"Руководство по боту: \n" -"Страница №{}" -msgstr "" -"Panduan bot: \n" -"Halaman Nomor {}" - -#: functions/main_app/auxiliary_tools.py:352 -msgid "" -"Вы попали в раздел Информации бота, здесь вы можете посмотреть: " -"статистику,изменить язык, а также посмотреть наш брендбук.\n" -"\n" -"🌐 Дней работаем: {}\n" -"👤 Всего пользователей: {}\n" -msgstr "" -"Anda telah masuk ke bagian Informasi bot, di sini Anda dapat " -"melihat: statistik, mengubah bahasa, serta melihat brandbook kami.\n" -"\n" -"🌐 Hari bekerja: {}\n" -"👤 Jumlah pengguna: {}\n" - -#: functions/main_app/determin_location.py:32 -#, fuzzy -msgid "" -"Я нашел такой адрес:\n" -"{city}\n" -"Если все правильно, то подтвердите" -msgstr "" -"Saya menemukan alamat berikut:\n" -"{city}\n" -"Jika semuanya benar, silakan konfirmasi" - -#: handlers/echo_handler.py:13 -msgid "Эхо без состояния." -msgstr "" - -#: handlers/echo_handler.py:38 -msgid "Меню: " -msgstr "" - -#: handlers/admins/monitoring.py:14 -msgid "Чтобы начать мониторинг нажмите на кнопку ниже" -msgstr "" - -#: handlers/admins/monitoring.py:32 -msgid "Анкета пользователя была заблокирована" -msgstr "" - -#: handlers/admins/advert/advertisement.py:21 -msgid "" -"📧 Рассылка\n" -"Пришлите текст для рассылки либо фото с текстом для рассылки! Чтобы " -"отредактировать, используйте встроенный редактор телеграма!\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:34 -#: handlers/admins/advert/mailing/create.py:124 -#: handlers/admins/advert/mailing/create.py:267 -msgid "Начинаю рассылку!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:49 -#: handlers/admins/advert/mailing/create.py:137 -#: handlers/admins/advert/mailing/create.py:192 -#: handlers/admins/advert/mailing/create.py:281 -msgid "" -"Сообщение не дошло в чат {chat} Причина: \n" -"{err}" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:55 -#: handlers/admins/advert/mailing/create.py:143 -#: handlers/admins/advert/mailing/create.py:198 -#: handlers/admins/advert/mailing/create.py:287 -msgid "Рассылка проведена успешно! Ее получили: {count} чатов!\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:61 -msgid "Пришлите мне название кнопки!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:70 -msgid "Название кнопки принято! Теперь отправьте мне ссылку для этой кнопки!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:90 -#: handlers/admins/advert/mailing/create.py:232 -msgid "" -"Вот так будет выглядеть сообщение: \n" -"\n" -"{text}\n" -"\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:97 -#: handlers/admins/advert/mailing/create.py:239 -msgid "Вы подтверждаете отправку?" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:104 -#: handlers/admins/advert/mailing/create.py:246 -msgid "" -"Произошла ошибка! Скорее всего, неправильно введена ссылка! Попробуйте " -"еще раз." -msgstr "" - -#: handlers/admins/advert/mailing/create.py:157 -msgid "" -"Вот сообщение: \n" -"\n" -"{text}\n" -"\n" -" Вы подтверждаете отправку? Или хотите что-то добавить?" -msgstr "" - -#: handlers/admins/settings/tech_works.py:26 -msgid "Чтобы включить/выключить технические работы, нажмите на кнопку ниже" -msgstr "" - -#: handlers/admins/settings/tech_works.py:36 -msgid "Технические работы включены" -msgstr "" - -#: handlers/admins/settings/tech_works.py:44 -msgid "Технические работы выключены" -msgstr "" - -#: handlers/groups/event_moderate.py:24 -msgid "Принято!" -msgstr "" - -#: handlers/groups/event_moderate.py:33 -msgid "Ваше мероприятие прошло модерацию" -msgstr "Acara Anda telah melewati moderasi" - -#: handlers/groups/event_moderate.py:40 -msgid "Отклонено!" -msgstr "Ditolak" - -#: handlers/groups/event_moderate.py:44 -msgid "К сожалению ваше мероприятие не прошло модерацию" -msgstr "Maaf, acara Anda tidak melewati moderasi" - -#: handlers/groups/start.py:12 -msgid "" -"Привет, я бот, проекта Que Group, для верификации анкет для " -"знакомств\n" -"\n" -msgstr "" -"Halo, saya adalah bot dari proyek Que Group, untuk verifikasi profil " -"untuk kencan\n" -"\n" - -#: handlers/users/back.py:43 -msgid "Вы забанены!" -msgstr "Anda diblokir!" - -#: handlers/users/back.py:50 -msgid "Вы вернулись в меню фильтров" -msgstr "Anda kembali ke menu filter" - -#: handlers/users/brandbook_handler.py:23 -msgid "" -"Руководство по боту: \n" -"Страница №1" -msgstr "" -"Panduan bot: \n" -"Halaman №1" - -#: handlers/users/buy_unban.py:17 -msgid "" -"💳 Сейчас вам нужно выбрать способ оплаты\n" -"\n" -"├Стоимость разблокировки - 99₽\n" -"├Оплата обычно приходить в течение 1-3 минут\n" -"├Если у вас нет Yoomoney или нет возможности\n" -"├оплатить, напишите агенту поддержки" -msgstr "" -"💳 Sekarang Anda perlu memilih metode pembayaran\n" -"\n" -"├ Biaya pembukaan blokir - 99₽\n" -"├ Pembayaran biasanya diterima dalam 1-3 menit\n" -"├ Jika Anda tidak memiliki Yoomoney atau tidak dapat\n" -"├ melakukan pembayaran, hubungi agen dukungan" - -#: handlers/users/buy_unban.py:38 -msgid "После оплаты нажмите 🔄 Проверить оплату" -msgstr "Setelah pembayaran, tekan 🔄 Periksa Pembayaran" - -#: handlers/users/buy_unban.py:57 -msgid "Поздравляем! Вы были разрабанены" -msgstr "Selamat! Anda telah dibebaskan dari larangan" - -#: handlers/users/buy_unban.py:65 -msgid "" -"Оплата не прошла! Подождите минут 10, а затем еще раз попробуйте нажать " -"кнопку ниже" -msgstr "" -"Pembayaran tidak berhasil! Tunggu selama 10 menit, lalu coba lagi dengan " -"menekan tombol di bawah ini" - -#: handlers/users/change_datas.py:35 -msgid "Ваши данные: \n" -msgstr "Data Anda: \n" - -#: handlers/users/change_datas.py:40 -msgid "Введите новое имя" -msgstr "Masukkan nama baru Anda" - -#: handlers/users/change_datas.py:53 -#, fuzzy -msgid "" -"Ваше новое имя: {censored}\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"Data berhasil diubah.\n" -"Pilih apa yang ingin Anda ubah: " - -#: handlers/users/change_datas.py:63 -msgid "" -"Произошла неизвестная ошибка. Попробуйте ещё раз\n" -"Возможно, Ваше сообщение слишком большое" -msgstr "" -"Terjadi kesalahan yang tidak diketahui. Silakan coba lagi\n" -"Mungkin pesan Anda terlalu besar" - -#: handlers/users/change_datas.py:76 -msgid "Введите новый возраст" -msgstr "Masukkan usia baru Anda" - -#: handlers/users/change_datas.py:90 -#, fuzzy -msgid "" -"Ваш новый возраст: {messages}\n" -"Выберите, что вы хотите изменить: " -msgstr "Usia baru Anda: {messages}" - -#: handlers/users/change_datas.py:99 handlers/users/registration.py:163 -msgid "Вы ввели недопустимое число, попробуйте еще раз" -msgstr "Anda memasukkan angka yang tidak valid, coba lagi" - -#: handlers/users/change_datas.py:104 -msgid "Вы ввели не число, попробуйте еще раз" -msgstr "Anda tidak memasukkan angka, coba lagi" - -#: handlers/users/change_datas.py:112 -msgid "Введите новый город" -msgstr "Masukkan kota baru Anda" - -#: handlers/users/change_datas.py:124 -msgid "Мы не смогли найти город {city}. Попробуйте ещё раз" -msgstr "Kami tidak dapat menemukan kota {city}. Silakan coba lagi" - -#: handlers/users/change_datas.py:134 -msgid "" -"Данные успешно изменены.\n" -"Выберите, что вы хотите изменить: " -msgstr "" -"Data berhasil diubah.\n" -"Pilih apa yang ingin Anda ubah: " - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♂️ Мужской" -msgstr "👱🏻‍♂️ Pria" - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♀️ Женский" -msgstr "👱🏻‍♀️ Wanita" - -#: handlers/users/change_datas.py:145 -msgid "Выберите новый пол: " -msgstr "Pilih jenis kelamin baru Anda: " - -#: handlers/users/change_datas.py:155 -#, fuzzy -msgid "" -"Ваш новый пол: {}\n" -"Выберите, что вы хотите изменить: " -msgstr "Pilih apa yang ingin Anda ubah: " - -#: handlers/users/change_datas.py:167 -msgid "Отправьте мне новую фотографию" -msgstr "Kirimkan saya foto baru Anda" - -#: handlers/users/change_datas.py:191 handlers/users/registration.py:244 -msgid "Произошла ошибка, проверьте настройки конфиденциальности" -msgstr "Terjadi kesalahan, periksa pengaturan privasi Anda" - -#: handlers/users/change_datas.py:232 -#, fuzzy -msgid "Отправьте сообщение о себе" -msgstr "Kirimkan saya pesan suara" - -#: handlers/users/change_datas.py:247 -#, fuzzy -msgid "" -"Комментарий принят!\n" -"Выберите, что вы хотите изменить: " -msgstr "Komentar diterima! Pilih siapa yang ingin Anda temui:" - -#: handlers/users/change_datas.py:254 -msgid "" -"Произошла ошибка! Попробуйте еще раз изменить описание. Возможно, Ваше " -"сообщение слишком большое\n" -"Если ошибка осталась, напишите в поддержку." -msgstr "" -"Terjadi kesalahan! Coba lagi ubah deskripsi. Mungkin pesan Anda terlalu " -"besar\n" -"Jika masalah masih berlanjut, hubungi dukungan." - -#: handlers/users/change_datas.py:267 -msgid "" -"Напишите имя своего аккаунта\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" -"Tuliskan nama akun Anda\n" -"\n" -"Contoh:\n" -"@unknown\n" -"https://www.instagram.com/unknown" - -#: handlers/users/change_datas.py:289 -msgid "Ваш аккаунт успешно добавлен" -msgstr "Akun Anda berhasil ditambahkan" - -#: handlers/users/change_datas.py:293 handlers/users/verification.py:45 -msgid "Вы были возвращены в меню" -msgstr "Anda telah kembali ke menu" - -#: handlers/users/change_datas.py:297 -msgid "" -"Вы ввели неправильную ссылку или имя аккаунта.\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" -"Anda memasukkan tautan atau nama akun yang salah.\n" -"\n" -"Contoh:\n" -"@unknown\n" -"https://www.instagram.com/unknown" - -#: handlers/users/change_datas.py:304 -msgid "Возникла ошибка. Попробуйте еще раз" -msgstr "Terjadi kesalahan. Silakan coba lagi" - -#: handlers/users/change_event_datas.py:16 -msgid "Вы перешли в меню изменения данных мероприятия" -msgstr "Anda telah pindah ke menu pengubahan data acara" - -#: handlers/users/change_event_datas.py:23 -msgid "Напишите новое название вашего мероприятия" -msgstr "Tulis nama baru untuk acara Anda" - -#: handlers/users/change_event_datas.py:35 -#: handlers/users/change_event_datas.py:53 -msgid "Данные изменены" -msgstr "Data diubah" - -#: handlers/users/change_event_datas.py:41 -msgid "Напишите новое описание вашего мероприятия" -msgstr "Tulis deskripsi baru untuk acara Anda" - -#: handlers/users/event_handler.py:31 -msgid "Вы перешли в меню афиш" -msgstr "Anda telah pindah ke menu acara" - -#: handlers/users/event_handler.py:48 -msgid "Введите название мероприятие" -msgstr "Masukkan nama acara" - -#: handlers/users/event_handler.py:55 -msgid "" -"Вы уже создали мероприятие, которое проходит модерацию. Дождитесь " -"проверки, пожалуйста" -msgstr "" -"Anda telah membuat acara yang sedang dalam moderasi. Mohon tunggu hingga " -"diverifikasi" - -#: handlers/users/event_handler.py:63 -msgid "" -"Прочитайте сообщение и не нажимайте на кнопку, пока ваше мероприятие не " -"пройдет модерацию" -msgstr "Baca pesan dan jangan tekan tombol sampai acara Anda lulus moderasi" - -#: handlers/users/event_handler.py:78 -msgid "Пожалуйста, выберите дату: " -msgstr "Silakan pilih tanggal: " - -#: handlers/users/event_handler.py:83 -msgid "" -"Длинна вашего сообщение превышает допустимую.\n" -"Попробуйте ещё раз" -msgstr "" -"Panjang pesan Anda melebihi batas yang diizinkan.\n" -"Silakan coba lagi" - -#: handlers/users/event_handler.py:99 -msgid "Вы не можете проводить мероприятие в прошлом" -msgstr "Anda tidak dapat mengadakan acara di masa lalu" - -#: handlers/users/event_handler.py:105 -msgid "Теперь напишите место проведения" -msgstr "Sekarang tuliskan tempat acara" - -#: handlers/users/event_handler.py:126 -msgid "Вы ввели слишком длинное название городаПопробуйте ещё раз." -msgstr "Anda telah memasukkan nama kota yang terlalu panjang. Coba lagi." - -#: handlers/users/event_handler.py:132 -msgid "" -"Произошла неизвестная ошибка! Попробуйте еще раз.\n" -"Вероятнее всего вы ввели город неправильно" -msgstr "" -"Terjadi kesalahan yang tidak diketahui! Coba lagi.\n" -"Kemungkinan besar Anda telah memasukkan nama kota dengan salah" - -#: handlers/users/event_handler.py:142 -msgid "Хорошо, теперь напишите короткое или длинное описание вашего мероприятия" -msgstr "" -"Baiklah, sekarang tuliskan deskripsi pendek atau panjang tentang acara " -"Anda" - -#: handlers/users/event_handler.py:158 -msgid "И напоследок, пришлите постер вашего мероприятия" -msgstr "Dan terakhir, kirimkan poster acara Anda" - -#: handlers/users/event_handler.py:164 -msgid "Ваше сообщение слишком длинное.Попробуйте написать короче" -msgstr "Pesan Anda terlalu panjang. Coba tulis lebih singkat" - -#: handlers/users/event_handler.py:178 -msgid "Фото принято" -msgstr "Foto diterima" - -#: handlers/users/event_handler.py:200 -msgid "Ваше мероприятие отправлено на модерацию" -msgstr "Acara Anda dikirimkan untuk moderasi" - -#: handlers/users/event_list.py:23 -msgid "На данный момент вы никуда не записались" -msgstr "Saat ini Anda belum mendaftar ke mana-mana" - -#: handlers/users/filters.py:23 handlers/users/filters.py:29 -msgid "Вы перешли в раздел с фильтрами" -msgstr "Anda telah beralih ke bagian filter" - -#: handlers/users/filters.py:41 -msgid "Напишите минимальный возраст" -msgstr "Tulis usia minimum" - -#: handlers/users/filters.py:53 -msgid "Теперь введите максимальный возраст" -msgstr "Sekarang masukkan usia maksimum" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♂️ Парня" -msgstr "👱🏻‍♂️ Laki-laki" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♀️ Девушку" -msgstr "👱🏻‍♀️ Perempuan" - -#: handlers/users/filters.py:76 -msgid "Выберите, кого вы хотите найти:" -msgstr "Pilih siapa yang ingin Anda temui:" - -#: handlers/users/filters.py:84 handlers/users/filters.py:111 -msgid "Данные сохранены" -msgstr "Data disimpan" - -#: handlers/users/filters.py:92 -msgid "Напишите город вашего будущего партнера" -msgstr "Tuliskan kota calon pasangan Anda" - -#: handlers/users/filters.py:103 handlers/users/filters.py:144 -msgid "Произошла ошибка, попробуйте еще раз" -msgstr "Terjadi kesalahan, coba lagi" - -#: handlers/users/filters.py:124 -msgid "Вы перешли в меню настроек фильтров для мероприятий" -msgstr "Anda telah beralih ke menu pengaturan filter untuk acara" - -#: handlers/users/filters.py:132 -msgid "Напишите город, в котором бы хотели сходить куда-нибудь" -msgstr "Tuliskan kota tempat Anda ingin pergi" - -#: handlers/users/registration.py:42 -msgid "Пройдите опрос, чтобы зарегистрироваться" -msgstr "Lakukan survei untuk mendaftar" - -#: handlers/users/registration.py:52 -msgid "" -"Вы уже зарегистрированы, если вам нужно изменить анкету, то нажмите на " -"кнопку ниже" -msgstr "" - -#: handlers/users/registration.py:66 -msgid "Выберите пол" -msgstr "Pilih jenis kelamin" - -#: handlers/users/registration.py:88 -msgid "Теперь расскажите о себе:\n" -msgstr "Sekarang ceritakan tentang diri Anda:\n" - -#: handlers/users/registration.py:105 -msgid "Комментарий принят! Выберите, кого вы хотите найти: " -msgstr "Komentar diterima! Pilih siapa yang ingin Anda temui:" - -#: handlers/users/registration.py:111 -msgid "" -"Произошла неизвестная ошибка! Попробуйте изменить комментарий позже в " -"разделе \"Меню\"\n" -"\n" -"Выберите, кого вы хотите найти: " -msgstr "" -"Terjadi kesalahan yang tidak diketahui! Coba ubah komentar Anda nanti di " -"bagian \"Menu\"\n" -"\n" -"Pilih siapa yang ingin Anda temukan: " - -#: handlers/users/registration.py:125 -msgid "Отлично! Теперь напишите мне ваше имя, которое будут все видеть в анкете" -msgstr "" -"Baiklah! Sekarang tuliskan nama Anda yang akan dilihat semua orang di " -"profil" - -#: handlers/users/registration.py:145 -msgid "Введите сколько вам лет:" -msgstr "Tuliskan berapa usia Anda:" - -#: handlers/users/registration.py:170 -msgid "Вы ввели не число" -msgstr "Anda telah memasukkan bukan angka" - -#: handlers/users/registration.py:175 -msgid "Нажмите на кнопку ниже, чтобы определить ваш местоположение!" -msgstr "Klik tombol di bawah ini untuk menentukan lokasi Anda!" - -#: handlers/users/registration.py:188 -#, fuzzy -msgid "Мы не смогли найти такой город, попробуйте еще раз" -msgstr "Kami tidak dapat menemukan kota {city}. Silakan coba lagi" - -#: handlers/users/registration.py:211 handlers/users/registration.py:224 -msgid "" -"И напоследок, Пришлите мне вашу фотографию (отправлять надо сжатое " -"изображение, а не как документ)" -msgstr "Terakhir, Kirimkan foto Anda (kirim gambar yang dikompresi, bukan dokumen)" - -#: handlers/users/sponsor.py:10 -msgid "" -"Наш проект работает на Open Source и мы будем рады,если вы нам " -"поможете развивать проект.\n" -"\n" -"С помощью кнопки 💰 Донат вы можете отправить своё пожертвование" -msgstr "" - -#: handlers/users/start_handler.py:27 -msgid "Вам необходимо зарегистрировать агента(ов) тех поддержки" -msgstr "Anda perlu mendaftarkan agen pendukung" - -#: handlers/users/start_handler.py:36 -msgid "Вас нет в базе данной" -msgstr "Anda tidak ada dalam database ini" - -#: handlers/users/start_handler.py:42 handlers/users/start_handler.py:47 -msgid "Выберите язык" -msgstr "Pilih bahasa" - -#: handlers/users/start_handler.py:57 -msgid "Язык был успешно изменен. Введите команду /start" -msgstr "Bahasa berhasil diubah. Masukkan perintah /start" - -#: handlers/users/start_handler.py:61 -msgid "Произошла какая-то ошибка. Введите команду /start и попробуйте еще раз" -msgstr "Terjadi kesalahan. Masukkan perintah /start dan coba lagi" - -#: handlers/users/support_handler.py:20 -msgid "Хотите связаться с тех поддержкой? Нажмите на кнопку ниже!" -msgstr "Ingin menghubungi dukungan? Klik tombol di bawah ini!" - -#: handlers/users/support_handler.py:25 handlers/users/support_handler.py:52 -msgid "К сожалению, сейчас нет свободных операторов. Попробуйте позже." -msgstr "Sayangnya, saat ini tidak ada operator yang tersedia. Coba lagi nanti." - -#: handlers/users/support_handler.py:41 -msgid "Вы обратились в техническую поддержку. Ждем ответа от оператора!" -msgstr "" -"Anda telah menghubungi dukungan teknis. Kami menunggu jawaban dari " -"operator!" - -#: handlers/users/support_handler.py:64 -msgid "С вами хочет связаться пользователь {full_name}" -msgstr "Anda menerima pesan dari pengguna {full_name}" - -#: handlers/users/support_handler.py:79 -msgid "К сожалению, пользователь уже передумал." -msgstr "Sayangnya, pengguna sudah berubah pikiran." - -#: handlers/users/support_handler.py:91 -msgid "" -"Вы на связи с пользователем!\n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"Anda terhubung dengan pengguna!\n" -"Untuk mengakhiri sesi, klik tombol." - -#: handlers/users/support_handler.py:100 -msgid "" -"Техподдержка на связи! Можете писать сюда свое сообщение. \n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" -"Dukungan teknis sedang online! Anda dapat mengirim pesan di sini. \n" -"Untuk mengakhiri sesi, klik tombol." - -#: handlers/users/support_handler.py:115 -msgid "Дождитесь ответа оператора или отмените сеанс" -msgstr "Tunggu jawaban operator atau batalkan sesi" - -#: handlers/users/support_handler.py:131 -msgid "Пользователь завершил сеанс техподдержки" -msgstr "Pengguna telah mengakhiri sesi dukungan" - -#: handlers/users/support_handler.py:135 -msgid "Вы завершили сеанс и были возвращены в главное меню" -msgstr "Anda telah mengakhiri sesi dan kembali ke menu utama" - -#: handlers/users/user_profile.py:23 -msgid "" -"Ваша анкета удалена!\n" -"Я надеюсь вы кого-нибудь нашли" -msgstr "" -"Profil Anda dihapus!\n" -"Kami harap Anda menemukan seseorang" - -#: handlers/users/verification.py:17 -msgid "Чтобы пройти верификацию вам нужно отправить свой контакт" -msgstr "Untuk melakukan verifikasi, Anda perlu mengirimkan kontak Anda" - -#: handlers/users/verification.py:33 -msgid "" -"Спасибо, {contact_full_name}.\n" -"Ваш номер {contact_phone_number} был получен." -msgstr "" -"Terima kasih, {contact_full_name}.\n" -"Nomor Anda {contact_phone_number} telah diterima." - -#: handlers/users/verification.py:50 -msgid "Ваш номер недействителен, попробуйте еще раз." -msgstr "Nomor Anda tidak valid, coba lagi." - -#: handlers/users/view_event.py:27 -msgid "На данный момент вы просмотрели все существующие анкеты" -msgstr "Saat ini Anda telah melihat semua profil yang tersedia" - -#: handlers/users/view_ques.py:73 -#, fuzzy -msgid "Жалоба успешно отправлена" -msgstr "Akun Anda berhasil ditambahkan" - -#: handlers/users/view_ques.py:112 -msgid "" -"Слишком много ❤️ за сегодня.\n" -"\n" -"Пригласи друзей и получи больше ❤️\n" -"\n" -"https://t.me/{}?start={}" -msgstr "" -"Terlalu banyak ❤️ hari ini.\n" -"\n" -"Undang teman dan dapatkan lebih banyak ❤️\n" -"\n" -"https://t.me/{}?start={}" - -#: keyboards/admin/inline/customers.py:12 -#, fuzzy -msgid "🔍 Найти пользователя" -msgstr "Balas Pengguna" - -#: keyboards/admin/inline/customers.py:23 -#, fuzzy -msgid "🟢 Разблокировать" -msgstr "Buka Blokir" - -#: keyboards/admin/inline/customers.py:28 -#, fuzzy -msgid "🚫 Заблокировать" -msgstr "Buka Blokir" - -#: keyboards/admin/inline/mailing.py:8 -msgid "📧 Рассылка" -msgstr "" - -#: keyboards/admin/inline/mailing.py:16 keyboards/admin/inline/mailing.py:31 -#: keyboards/inline/admin_inline.py:9 -msgid "Подтвердить отправку" -msgstr "Konfirmasi Kirim" - -#: keyboards/admin/inline/mailing.py:19 -msgid "Добавить кнопку" -msgstr "Tambahkan Tombol" - -#: keyboards/admin/inline/mailing.py:21 keyboards/admin/inline/mailing.py:33 -#: keyboards/inline/cancel_inline.py:8 -msgid "Отмена" -msgstr "Batal" - -#: keyboards/admin/inline/payments.py:9 -msgid "⚙️ Настройки" -msgstr "" - -#: keyboards/admin/inline/payments.py:11 -msgid "📝 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:8 -msgid "📈 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:9 keyboards/admin/inline/setting.py:8 -#, fuzzy -msgid "*️⃣ Добавить" -msgstr "🗑️ Hapus" - -#: keyboards/admin/inline/ref.py:10 keyboards/admin/inline/setting.py:9 -#, fuzzy -msgid "❌ Удалить" -msgstr "🗑️ Hapus" - -#: keyboards/admin/inline/ref.py:11 keyboards/admin/inline/setting.py:10 -#, fuzzy -msgid "◀️ Назад" -msgstr "⏪️ Kembali" - -#: keyboards/admin/inline/reply_menu.py:9 -#, fuzzy -msgid "🙅🏻‍♂️ Отменить" -msgstr "🖊️ Ubah" - -#: keyboards/admin/inline/reply_menu.py:17 -msgid "👮‍♂️ Админ Состав" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:19 -#, fuzzy -msgid "📞 Сменить контакты" -msgstr "📞 Kontak" - -#: keyboards/admin/inline/reply_menu.py:29 -msgid "🗒 Выгрузить юзеров | .txt" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:32 -msgid "🗒 Выгрузить конфиги и логи" -msgstr "" - -#: keyboards/default/admin_default.py:8 -msgid "Рассылка" -msgstr "" - -#: keyboards/default/admin_default.py:9 -msgid "Сообщение по id" -msgstr "" - -#: keyboards/default/admin_default.py:10 -msgid "Посчитать людей и чаты" -msgstr "" - -#: keyboards/default/admin_default.py:11 -msgid "Мониторинг" -msgstr "" - -#: keyboards/default/admin_default.py:12 -msgid "Тех.Работа" -msgstr "" - -#: keyboards/default/get_contact_default.py:8 -msgid "📱 Отправить" -msgstr "📱 Kirim" - -#: keyboards/default/get_location_default.py:9 -msgid "🗺 Определить автоматически" -msgstr "🗺 Tentukan Otomatis" - -#: keyboards/default/get_photo.py:8 -msgid "Взять из профиля" -msgstr "Ambil dari Profil" - -#: keyboards/inline/admin_inline.py:18 -msgid "Включить" -msgstr "Hidupkan" - -#: keyboards/inline/admin_inline.py:21 -msgid "Выключить" -msgstr "Matikan" - -#: keyboards/inline/admin_inline.py:33 -msgid "Разблокировать" -msgstr "Buka Blokir" - -#: keyboards/inline/back_inline.py:8 -#: keyboards/inline/change_data_profile_inline.py:15 -#: keyboards/inline/filters_inline.py:42 keyboards/inline/language_inline.py:22 -#: keyboards/inline/poster_inline.py:31 keyboards/inline/poster_inline.py:49 -#: keyboards/inline/poster_inline.py:63 -#: keyboards/inline/registration_inline.py:12 -#: keyboards/inline/settings_menu.py:12 keyboards/inline/sponsor_inline.py:10 -#: keyboards/inline/sponsor_inline.py:21 -msgid "⏪️ Вернуться в меню" -msgstr "⏪️ Kembali ke Menu" - -#: keyboards/inline/cancel_inline.py:16 -#: keyboards/inline/change_data_profile_inline.py:28 -#, fuzzy -msgid "❌ Остановить" -msgstr "⏪ Berhenti" - -#: keyboards/inline/change_data_profile_inline.py:8 -msgid "👤 Имя" -msgstr "👤 Nama" - -#: keyboards/inline/change_data_profile_inline.py:9 -msgid "⚧ Пол" -msgstr "⚧ Jenis Kelamin" - -#: keyboards/inline/change_data_profile_inline.py:10 -msgid "📅 Возраст" -msgstr "📅 Usia" - -#: keyboards/inline/change_data_profile_inline.py:11 -msgid "🏙 Город" -msgstr "🏙 Kota" - -#: keyboards/inline/change_data_profile_inline.py:12 -msgid "📷 Фото" -msgstr "📷 Foto" - -#: keyboards/inline/change_data_profile_inline.py:13 -msgid "📝 О себе" -msgstr "📝 Tentang Saya" - -#: keyboards/inline/filters_inline.py:9 -msgid "🎉 Мероприятия" -msgstr "🎉 Acara" - -#: keyboards/inline/filters_inline.py:12 -msgid "❤️ Знакомства" -msgstr "❤️ Kenalan" - -#: keyboards/inline/filters_inline.py:14 keyboards/inline/filters_inline.py:31 -#: keyboards/inline/guide_inline.py:15 -msgid "⏪️ Назад" -msgstr "⏪️ Kembali" - -#: keyboards/inline/filters_inline.py:23 -msgid "🏙️ Город партнера" -msgstr "🏙️ Kota Pasangan" - -#: keyboards/inline/filters_inline.py:26 -msgid "🔞 Возр.диапазон" -msgstr "🔞 Rentang Usia" - -#: keyboards/inline/filters_inline.py:29 -msgid "🚻 Пол партнера" -msgstr "🚻 Jenis Kelamin Pasangan" - -#: keyboards/inline/filters_inline.py:40 -msgid "🏙️ Город" -msgstr "🏙️ Kota" - -#: keyboards/inline/guide_inline.py:21 -msgid "Вперед ➡️" -msgstr "Maju ➡️" - -#: keyboards/inline/guide_inline.py:25 -msgid "❌ Закрыть" -msgstr "❌ Tutup" - -#: keyboards/inline/language_inline.py:13 -msgid "🇷🇺 Русский" -msgstr "🇷🇺 Russia" - -#: keyboards/inline/language_inline.py:14 -msgid "🇩🇪 Немецкий" -msgstr "🇩🇪 Jerman" - -#: keyboards/inline/language_inline.py:15 -msgid "🇬🇧 Английский" -msgstr "🇬🇧 Inggris" - -#: keyboards/inline/language_inline.py:16 -msgid "🇮🇩 Индонезийский" -msgstr "🇮🇩 Indonesia" - -#: keyboards/inline/main_menu_inline.py:26 -msgid "➕ Регистрация" -msgstr "➕ Registrasi" - -#: keyboards/inline/main_menu_inline.py:28 keyboards/inline/settings_menu.py:10 -msgid "🌐 Язык" -msgstr "🌐 Bahasa" - -#: keyboards/inline/main_menu_inline.py:30 -msgid "👤 Моя анекта" -msgstr "👤 Profil Saya" - -#: keyboards/inline/main_menu_inline.py:32 -msgid "⚙️ Фильтры" -msgstr "⚙️ Filter" - -#: keyboards/inline/main_menu_inline.py:33 -msgid "💌 Найти пару" -msgstr "💌 Temukan Pasangan" - -#: keyboards/inline/main_menu_inline.py:34 -msgid "🗓️ Афиша" -msgstr "🗓️ Acara" - -#: keyboards/inline/main_menu_inline.py:35 -msgid "🆘 Поддержка" -msgstr "🆘 Bantuan" - -#: keyboards/inline/main_menu_inline.py:37 -msgid "ℹ️ Информация" -msgstr "ℹ️ Informasi" - -#: keyboards/inline/menu_profile_inline.py:10 -msgid "✅ Верификация" -msgstr "✅ Verifikasi" - -#: keyboards/inline/menu_profile_inline.py:16 -msgid "🖊️ Изменить" -msgstr "🖊️ Ubah" - -#: keyboards/inline/menu_profile_inline.py:18 -msgid "🗑️ Удалить" -msgstr "🗑️ Hapus" - -#: keyboards/inline/menu_profile_inline.py:19 -msgid "⏪ Назад" -msgstr "⏪ Kembali" - -#: keyboards/inline/payments_inline.py:9 -msgid "💳 ЮMoney" -msgstr "💳 Yandex.Money" - -#: keyboards/inline/payments_inline.py:16 -msgid "💳 Оплатить" -msgstr "💳 Bayar" - -#: keyboards/inline/payments_inline.py:18 -msgid "🔄 Проверить оплату" -msgstr "🔄 Periksa Pembayaran" - -#: keyboards/inline/poster_inline.py:21 -msgid "✍️Создать афишу" -msgstr "✍️ Buat Acara" - -#: keyboards/inline/poster_inline.py:24 -msgid "🎭 Смотреть афиши" -msgstr "🎭 Lihat Acara" - -#: keyboards/inline/poster_inline.py:27 -msgid "📝 Мои записи" -msgstr "📝 Catatan Saya" - -#: keyboards/inline/poster_inline.py:29 -msgid "📃 Моё событие" -msgstr "📃 Acara Saya" - -#: keyboards/inline/poster_inline.py:46 -msgid "✍️ Изменить" -msgstr "✍️ Ubah" - -#: keyboards/inline/poster_inline.py:58 -msgid "Название" -msgstr "Nama" - -#: keyboards/inline/poster_inline.py:60 -msgid "Описание" -msgstr "Deskripsi" - -#: keyboards/inline/poster_inline.py:73 -msgid "✅ Одобрить" -msgstr "✅ Setujui" - -#: keyboards/inline/poster_inline.py:76 -msgid "❌ Отклонить" -msgstr "❌ Tolak" - -#: keyboards/inline/poster_inline.py:85 -msgid "Пойду!" -msgstr "Akan Saya Hadiri!" - -#: keyboards/inline/poster_inline.py:88 -msgid "Не интересно" -msgstr "Tidak Tertarik" - -#: keyboards/inline/poster_inline.py:91 keyboards/inline/poster_inline.py:103 -#: keyboards/inline/poster_inline.py:112 -msgid "⏪️ Остановить" -msgstr "⏪ Berhenti" - -#: keyboards/inline/poster_inline.py:101 -msgid "❌ Отменить запись" -msgstr "❌ Batalkan Pendaftaran" - -#: keyboards/inline/questionnaires_inline.py:30 -#, fuzzy -msgid "💤 Остановить" -msgstr "⏪ Berhenti" - -#: keyboards/inline/questionnaires_inline.py:34 -msgid "🚫 Забанить" -msgstr "🚫 Blokir" - -#: keyboards/inline/questionnaires_inline.py:38 -msgid "Следующий" -msgstr "Selanjutnya" - -#: keyboards/inline/questionnaires_inline.py:74 -msgid "🚀 Смотреть" -msgstr "🚀 Lihat" - -#: keyboards/inline/questionnaires_inline.py:82 -msgid "👉 Перейти в чат" -msgstr "👉 Buka Obrolan" - -#: keyboards/inline/questionnaires_inline.py:89 -msgid "⏪️ Вернуться к просмотру анкет" -msgstr "⏪️ Kembali ke tampilan profil" - -#: keyboards/inline/registration_inline.py:9 -msgid "🖌️ Пройти опрос в боте" -msgstr "🖌️ Isi kuesioner di bot" - -#: keyboards/inline/registration_inline.py:21 -msgid "✅ Да все хорошо!" -msgstr "✅ Ya, semuanya baik!" - -#: keyboards/inline/settings_menu.py:8 -msgid "📚 Брендбук" -msgstr "📚 Brandbook" - -#: keyboards/inline/settings_menu.py:9 -msgid "📞 Контакты" -msgstr "📞 Kontak" - -#: keyboards/inline/support_inline.py:37 -msgid "Ответить пользователю" -msgstr "Balas Pengguna" - -#: keyboards/inline/support_inline.py:45 -msgid "Написать оператору" -msgstr "Tulis ke Operator" - -#: keyboards/inline/support_inline.py:60 keyboards/inline/support_inline.py:72 -msgid "Завершить сеанс" -msgstr "Akhiri Sesi" - -#: middlewares/BanCheck.py:44 -msgid "😢 Вы заблокированы!" -msgstr "😢 Anda telah diblokir!" - -#: middlewares/IsMaintenanceCheck.py:26 -msgid "Ведутся технические работы" -msgstr "Sedang dalam perawatan teknis" - -#: middlewares/LinkCheck.py:38 -msgid "" -"Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " -"подпишитесь! Ссылки ниже: " -msgstr "" -"Anda belum berlangganan di semua saluran! Untuk melanjutkan menggunakan " -"bot, berlanggananlah! Tautan di bawah ini: " - -#: utils/notify_admins.py:24 -msgid "Оповещение администрации..." -msgstr "" - -#: utils/notify_admins.py:28 -msgid "Бот был успешно запущен" -msgstr "" - -#: utils/statistics.py:16 -msgid "" -"📊 Статистика: \n" -"\n" -"└Сейчас в нашем боте {count_users} пользователей\n" -"└Из них:\n" -" ├{users_gender_m} пользователей мужского пола\n" -" ├{users_gender_f} пользователей женского пола\n" -" ├{users_city} пользователей из города {user_city}\n" -" ├{cs_uy} пользователей из других городов\n" -" ├{users_verified} верифицированных пользователей\n" -" ├{users_status} пользователей, создавшие анкету\n" -"└Дата создания бота - 10.08.2021" -msgstr "" -"📊 Statistik: \n" -"\n" -"└Saat ini bot kami memiliki {count_users} pengguna\n" -"└Diantara mereka:\n" -" ├{users_gender_m} pengguna berjenis kelamin pria\n" -" ├{users_gender_f} pengguna berjenis kelamin wanita\n" -" ├{users_city} pengguna berasal dari kota {user_city}\n" -" ├{cs_uy} pengguna berasal dari kota lain\n" -" ├{users_verified} pengguna terverifikasi\n" -" ├{users_status} pengguna telah membuat profil\n" -"└Bot dibuat pada tanggal 10 Agustus 2021" - -#~ msgid "" -#~ "Вы попали в раздел настроек бота," -#~ " здесь вы можете посмотреть: " -#~ "статистику,изменить язык, отключить уведомления, " -#~ "а также узнать информацию.\n" -#~ "\n" -#~ "🌐 Дней работаем: {}\n" -#~ "👤 Всего пользователей: {}\n" -#~ msgstr "" -#~ "Anda telah masuk ke bagian " -#~ "Pengaturan bot, di sini Anda " -#~ "dapat melihat: statistik, mengubah bahasa, " -#~ "mematikan pemberitahuan, serta mengetahui " -#~ "informasi.\n" -#~ "\n" -#~ "🌐 Hari bekerja: {}\n" -#~ "👤 Jumlah pengguna: {}\n" - -#~ msgid "🇫🇷 Французский" -#~ msgstr "" - -#~ msgid "🟢 Запустить бота" -#~ msgstr "" - -#~ msgid "⚒ Админ-Меню" -#~ msgstr "" - -#~ msgid "🗒 Логи" -#~ msgstr "" - -#~ msgid "Ваше новое имя: {censored}" -#~ msgstr "Nama baru Anda: {censored}" - -#~ msgid "Ваш новый пол: {}" -#~ msgstr "Jenis kelamin baru Anda: {}" - -#~ msgid "Отправьте мне новое описание анкеты:" -#~ msgstr "Kirimkan saya deskripsi profil baru:" - -#~ msgid "Комментарий принят!" -#~ msgstr "Komentar diterima!" - -#~ msgid "🫂 Пользователи" -#~ msgstr "Balas Pengguna" - -#~ msgid "📊 Реклама" -#~ msgstr "" - -#~ msgid "👀 Мониторинг" -#~ msgstr "" - -#~ msgid "🛑 Тех.Работа" -#~ msgstr "" - -#~ msgid "Чат с админом не найден" -#~ msgstr "" - diff --git a/locales/ru/LC_MESSAGES/dating.po b/locales/ru/LC_MESSAGES/dating.po deleted file mode 100644 index d4e9ef4..0000000 --- a/locales/ru/LC_MESSAGES/dating.po +++ /dev/null @@ -1,1511 +0,0 @@ -# Russian translations for PROJECT. -# Copyright (C) 2022 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2022. -# -msgid "" -msgstr "" -"Project-Id-Version: PROJECT VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2023-08-28 14:39+0300\n" -"PO-Revision-Date: 2022-12-15 21:01+0300\n" -"Last-Translator: FULL NAME \n" -"Language: ru\n" -"Language-Team: ru \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" - -#: functions/dating/reaction_strategies.py:46 -#: functions/dating/reaction_strategies.py:171 -msgid "На данный момент у нас нет подходящих анкет для вас" -msgstr "" - -#: functions/dating/reaction_strategies.py:52 -msgid "У вас достигнут лимит на просмотры анкет" -msgstr "" - -#: functions/dating/reaction_strategies.py:61 -msgid "Кому-то понравилась твоя анкета" -msgstr "" - -#: functions/dating/reaction_strategies.py:103 handlers/users/view_event.py:51 -msgid "" -"Рад был помочь, {fullname}!\n" -"Надеюсь, ты нашел кого-то благодаря мне" -msgstr "" - -#: functions/dating/reaction_strategies.py:126 -msgid "Отлично! Надеюсь вы хорошо проведете время ;) Начинай общаться 👉" -msgstr "" - -#: functions/dating/reaction_strategies.py:187 -msgid "Выберите причину жалобы:" -msgstr "" - -#: functions/dating/reaction_strategies.py:204 -msgid "" -"Жалоба от пользователя: [@{username} | {tg_id}]" -"\n" -"\n" -"На пользователя: [{owner_id}]\n" -"Причина жалобы: {reason}\n" -"Количество жалоб на пользователя: {counter_of_report}" -msgstr "" - -#: functions/dating/send_form_func.py:25 -msgid "" -"{}, {} лет, {} {verification}\n" -"\n" -msgstr "" - -#: functions/dating/send_form_func.py:28 -msgid "{commentary}" -msgstr "" - -#: functions/dating/send_form_func.py:36 -msgid "Инстаграм - {instagram}\n" -msgstr "" - -#: functions/dating/send_form_func.py:48 -msgid "" -"{}\n" -"\n" -"{}" -msgstr "" - -#: functions/dating/send_form_func.py:57 -msgid "" -"{}\n" -"\n" -"Инстаграм - {instagram}\n" -msgstr "" - -#: functions/event/extra_features.py:86 -msgid "На данный момент у нас нет подходящих мероприятий для вас" -msgstr "" - -#: functions/event/templates_messages.py:17 -msgid "" -"{} \n" -"Когда: {} \n" -"Где: {} \n" -"\n" -"{}" -msgstr "" - -#: functions/main_app/app_scheduler.py:12 -msgid "Несколько {} из города {} хотят познакомиться с тобой прямо сейчас" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:71 -msgid "" -"{name}, {age} лет, {city}, {verification}\n" -"\n" -"{commentary}\n" -"\n" -"Партнерка:\n" -"Количество приглашенных друзей: {reff}\n" -"Реферальная ссылка:\n" -" {link}" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:96 -msgid "" -"Фильтр по подбору партнеров:\n" -"\n" -"🚻 Необходимы пол партнера: {}\n" -"🔞 Возрастной диапазон: {}-{} лет\n" -"\n" -"🏙️ Город партнера: {}" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:121 -msgid "" -"Приветствую вас, {fullname}!!\n" -"\n" -"{heart} QueDateBot - платформа для поиска новых знакомств.\n" -"\n" -"🪧 Новости о проекте вы можете прочитать в нашем канале - " -"https://t.me/QueDateGroup \n" -"\n" -"🤝 Сотрудничество: \n" -"Если у вас есть предложение о сотрудничестве, пишите агенту поддержки - " -"@{supports}\n" -"\n" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:168 -msgid "" -"По вашей ссылке зарегистрировался пользователь {}!\n" -"Вы получаете дополнительных 15 ❤️" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:194 -msgid "" -"Регистрация успешно завершена! \n" -"\n" -" {}, {} лет, {}\n" -"\n" -"О себе - {}" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:215 -#: functions/main_app/auxiliary_tools.py:281 -msgid "Фото принято!" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:219 -#: functions/main_app/auxiliary_tools.py:254 -#: functions/main_app/auxiliary_tools.py:290 -msgid "" -"Произошла ошибка! Попробуйте еще раз либо отправьте другую фотографию. \n" -"Если ошибка осталась, напишите агенту поддержки." -msgstr "" - -#: functions/main_app/auxiliary_tools.py:242 -msgid "" -"Во время проверки вашего фото мы обнаружили подозрительный контент!\n" -"Поэтому мы чуть-чуть подкорректировали вашу фотографию" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:262 -msgid "" -"Фото принято!\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: functions/main_app/auxiliary_tools.py:285 -msgid "Выберите, что вы хотите изменить: " -msgstr "" - -#: functions/main_app/auxiliary_tools.py:336 -msgid "" -"Руководство по боту: \n" -"Страница №{}" -msgstr "" - -#: functions/main_app/auxiliary_tools.py:352 -msgid "" -"Вы попали в раздел Информации бота, здесь вы можете посмотреть: " -"статистику,изменить язык, а также посмотреть наш брендбук.\n" -"\n" -"🌐 Дней работаем: {}\n" -"👤 Всего пользователей: {}\n" -msgstr "" - -#: functions/main_app/determin_location.py:32 -msgid "" -"Я нашел такой адрес:\n" -"{city}\n" -"Если все правильно, то подтвердите" -msgstr "" - -#: handlers/echo_handler.py:13 -msgid "Эхо без состояния." -msgstr "" - -#: handlers/echo_handler.py:38 -msgid "Меню: " -msgstr "" - -#: handlers/admins/monitoring.py:14 -msgid "Чтобы начать мониторинг нажмите на кнопку ниже" -msgstr "" - -#: handlers/admins/monitoring.py:32 -msgid "Анкета пользователя была заблокирована" -msgstr "" - -#: handlers/admins/advert/advertisement.py:21 -msgid "" -"📧 Рассылка\n" -"Пришлите текст для рассылки либо фото с текстом для рассылки! Чтобы " -"отредактировать, используйте встроенный редактор телеграма!\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:34 -#: handlers/admins/advert/mailing/create.py:124 -#: handlers/admins/advert/mailing/create.py:267 -msgid "Начинаю рассылку!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:49 -#: handlers/admins/advert/mailing/create.py:137 -#: handlers/admins/advert/mailing/create.py:192 -#: handlers/admins/advert/mailing/create.py:281 -msgid "" -"Сообщение не дошло в чат {chat} Причина: \n" -"{err}" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:55 -#: handlers/admins/advert/mailing/create.py:143 -#: handlers/admins/advert/mailing/create.py:198 -#: handlers/admins/advert/mailing/create.py:287 -msgid "Рассылка проведена успешно! Ее получили: {count} чатов!\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:61 -msgid "Пришлите мне название кнопки!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:70 -msgid "Название кнопки принято! Теперь отправьте мне ссылку для этой кнопки!" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:90 -#: handlers/admins/advert/mailing/create.py:232 -msgid "" -"Вот так будет выглядеть сообщение: \n" -"\n" -"{text}\n" -"\n" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:97 -#: handlers/admins/advert/mailing/create.py:239 -msgid "Вы подтверждаете отправку?" -msgstr "" - -#: handlers/admins/advert/mailing/create.py:104 -#: handlers/admins/advert/mailing/create.py:246 -msgid "" -"Произошла ошибка! Скорее всего, неправильно введена ссылка! Попробуйте " -"еще раз." -msgstr "" - -#: handlers/admins/advert/mailing/create.py:157 -msgid "" -"Вот сообщение: \n" -"\n" -"{text}\n" -"\n" -" Вы подтверждаете отправку? Или хотите что-то добавить?" -msgstr "" - -#: handlers/admins/settings/tech_works.py:26 -msgid "Чтобы включить/выключить технические работы, нажмите на кнопку ниже" -msgstr "" - -#: handlers/admins/settings/tech_works.py:36 -msgid "Технические работы включены" -msgstr "" - -#: handlers/admins/settings/tech_works.py:44 -msgid "Технические работы выключены" -msgstr "" - -#: handlers/groups/event_moderate.py:24 -msgid "Принято!" -msgstr "" - -#: handlers/groups/event_moderate.py:33 -msgid "Ваше мероприятие прошло модерацию" -msgstr "" - -#: handlers/groups/event_moderate.py:40 -msgid "Отклонено!" -msgstr "" - -#: handlers/groups/event_moderate.py:44 -msgid "К сожалению ваше мероприятие не прошло модерацию" -msgstr "" - -#: handlers/groups/start.py:12 -msgid "" -"Привет, я бот, проекта Que Group, для верификации анкет для " -"знакомств\n" -"\n" -msgstr "" - -#: handlers/users/back.py:43 -msgid "Вы забанены!" -msgstr "" - -#: handlers/users/back.py:50 -msgid "Вы вернулись в меню фильтров" -msgstr "" - -#: handlers/users/brandbook_handler.py:23 -msgid "" -"Руководство по боту: \n" -"Страница №1" -msgstr "" - -#: handlers/users/buy_unban.py:17 -msgid "" -"💳 Сейчас вам нужно выбрать способ оплаты\n" -"\n" -"├Стоимость разблокировки - 99₽\n" -"├Оплата обычно приходить в течение 1-3 минут\n" -"├Если у вас нет Yoomoney или нет возможности\n" -"├оплатить, напишите агенту поддержки" -msgstr "" - -#: handlers/users/buy_unban.py:38 -msgid "После оплаты нажмите 🔄 Проверить оплату" -msgstr "" - -#: handlers/users/buy_unban.py:57 -msgid "Поздравляем! Вы были разрабанены" -msgstr "" - -#: handlers/users/buy_unban.py:65 -msgid "" -"Оплата не прошла! Подождите минут 10, а затем еще раз попробуйте нажать " -"кнопку ниже" -msgstr "" - -#: handlers/users/change_datas.py:35 -msgid "Ваши данные: \n" -msgstr "" - -#: handlers/users/change_datas.py:40 -msgid "Введите новое имя" -msgstr "" - -#: handlers/users/change_datas.py:53 -msgid "" -"Ваше новое имя: {censored}\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: handlers/users/change_datas.py:63 -msgid "" -"Произошла неизвестная ошибка. Попробуйте ещё раз\n" -"Возможно, Ваше сообщение слишком большое" -msgstr "" - -#: handlers/users/change_datas.py:76 -msgid "Введите новый возраст" -msgstr "" - -#: handlers/users/change_datas.py:90 -msgid "" -"Ваш новый возраст: {messages}\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: handlers/users/change_datas.py:99 handlers/users/registration.py:163 -msgid "Вы ввели недопустимое число, попробуйте еще раз" -msgstr "" - -#: handlers/users/change_datas.py:104 -msgid "Вы ввели не число, попробуйте еще раз" -msgstr "" - -#: handlers/users/change_datas.py:112 -msgid "Введите новый город" -msgstr "" - -#: handlers/users/change_datas.py:124 -msgid "Мы не смогли найти город {city}. Попробуйте ещё раз" -msgstr "" - -#: handlers/users/change_datas.py:134 -msgid "" -"Данные успешно изменены.\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♂️ Мужской" -msgstr "" - -#: handlers/users/change_datas.py:143 handlers/users/registration.py:63 -msgid "👱🏻‍♀️ Женский" -msgstr "" - -#: handlers/users/change_datas.py:145 -msgid "Выберите новый пол: " -msgstr "" - -#: handlers/users/change_datas.py:155 -msgid "" -"Ваш новый пол: {}\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: handlers/users/change_datas.py:167 -msgid "Отправьте мне новую фотографию" -msgstr "" - -#: handlers/users/change_datas.py:191 handlers/users/registration.py:244 -msgid "Произошла ошибка, проверьте настройки конфиденциальности" -msgstr "" - -#: handlers/users/change_datas.py:232 -msgid "Отправьте сообщение о себе" -msgstr "" - -#: handlers/users/change_datas.py:247 -msgid "" -"Комментарий принят!\n" -"Выберите, что вы хотите изменить: " -msgstr "" - -#: handlers/users/change_datas.py:254 -msgid "" -"Произошла ошибка! Попробуйте еще раз изменить описание. Возможно, Ваше " -"сообщение слишком большое\n" -"Если ошибка осталась, напишите в поддержку." -msgstr "" - -#: handlers/users/change_datas.py:267 -msgid "" -"Напишите имя своего аккаунта\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" - -#: handlers/users/change_datas.py:289 -msgid "Ваш аккаунт успешно добавлен" -msgstr "" - -#: handlers/users/change_datas.py:293 handlers/users/verification.py:45 -msgid "Вы были возвращены в меню" -msgstr "" - -#: handlers/users/change_datas.py:297 -msgid "" -"Вы ввели неправильную ссылку или имя аккаунта.\n" -"\n" -"Примеры:\n" -"@unknown\n" -"https://www.instagram.com/unknown" -msgstr "" - -#: handlers/users/change_datas.py:304 -msgid "Возникла ошибка. Попробуйте еще раз" -msgstr "" - -#: handlers/users/change_event_datas.py:16 -msgid "Вы перешли в меню изменения данных мероприятия" -msgstr "" - -#: handlers/users/change_event_datas.py:23 -msgid "Напишите новое название вашего мероприятия" -msgstr "" - -#: handlers/users/change_event_datas.py:35 -#: handlers/users/change_event_datas.py:53 -msgid "Данные изменены" -msgstr "" - -#: handlers/users/change_event_datas.py:41 -msgid "Напишите новое описание вашего мероприятия" -msgstr "" - -#: handlers/users/event_handler.py:31 -msgid "Вы перешли в меню афиш" -msgstr "" - -#: handlers/users/event_handler.py:48 -msgid "Введите название мероприятие" -msgstr "" - -#: handlers/users/event_handler.py:55 -msgid "" -"Вы уже создали мероприятие, которое проходит модерацию. Дождитесь " -"проверки, пожалуйста" -msgstr "" - -#: handlers/users/event_handler.py:63 -msgid "" -"Прочитайте сообщение и не нажимайте на кнопку, пока ваше мероприятие не " -"пройдет модерацию" -msgstr "" - -#: handlers/users/event_handler.py:78 -msgid "Пожалуйста, выберите дату: " -msgstr "" - -#: handlers/users/event_handler.py:83 -msgid "" -"Длинна вашего сообщение превышает допустимую.\n" -"Попробуйте ещё раз" -msgstr "" - -#: handlers/users/event_handler.py:99 -msgid "Вы не можете проводить мероприятие в прошлом" -msgstr "" - -#: handlers/users/event_handler.py:105 -msgid "Теперь напишите место проведения" -msgstr "" - -#: handlers/users/event_handler.py:126 -msgid "Вы ввели слишком длинное название городаПопробуйте ещё раз." -msgstr "" - -#: handlers/users/event_handler.py:132 -msgid "" -"Произошла неизвестная ошибка! Попробуйте еще раз.\n" -"Вероятнее всего вы ввели город неправильно" -msgstr "" - -#: handlers/users/event_handler.py:142 -msgid "Хорошо, теперь напишите короткое или длинное описание вашего мероприятия" -msgstr "" - -#: handlers/users/event_handler.py:158 -msgid "И напоследок, пришлите постер вашего мероприятия" -msgstr "" - -#: handlers/users/event_handler.py:164 -msgid "Ваше сообщение слишком длинное.Попробуйте написать короче" -msgstr "" - -#: handlers/users/event_handler.py:178 -msgid "Фото принято" -msgstr "" - -#: handlers/users/event_handler.py:200 -msgid "Ваше мероприятие отправлено на модерацию" -msgstr "" - -#: handlers/users/event_list.py:23 -msgid "На данный момент вы никуда не записались" -msgstr "" - -#: handlers/users/filters.py:23 handlers/users/filters.py:29 -msgid "Вы перешли в раздел с фильтрами" -msgstr "" - -#: handlers/users/filters.py:41 -msgid "Напишите минимальный возраст" -msgstr "" - -#: handlers/users/filters.py:53 -msgid "Теперь введите максимальный возраст" -msgstr "" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♂️ Парня" -msgstr "" - -#: handlers/users/filters.py:73 handlers/users/registration.py:97 -msgid "👱🏻‍♀️ Девушку" -msgstr "" - -#: handlers/users/filters.py:76 -msgid "Выберите, кого вы хотите найти:" -msgstr "" - -#: handlers/users/filters.py:84 handlers/users/filters.py:111 -msgid "Данные сохранены" -msgstr "" - -#: handlers/users/filters.py:92 -msgid "Напишите город вашего будущего партнера" -msgstr "" - -#: handlers/users/filters.py:103 handlers/users/filters.py:144 -msgid "Произошла ошибка, попробуйте еще раз" -msgstr "" - -#: handlers/users/filters.py:124 -msgid "Вы перешли в меню настроек фильтров для мероприятий" -msgstr "" - -#: handlers/users/filters.py:132 -msgid "Напишите город, в котором бы хотели сходить куда-нибудь" -msgstr "" - -#: handlers/users/registration.py:42 -msgid "Пройдите опрос, чтобы зарегистрироваться" -msgstr "" - -#: handlers/users/registration.py:52 -msgid "" -"Вы уже зарегистрированы, если вам нужно изменить анкету, то нажмите на " -"кнопку ниже" -msgstr "" - -#: handlers/users/registration.py:66 -msgid "Выберите пол" -msgstr "" - -#: handlers/users/registration.py:88 -msgid "Теперь расскажите о себе:\n" -msgstr "" - -#: handlers/users/registration.py:105 -msgid "Комментарий принят! Выберите, кого вы хотите найти: " -msgstr "" - -#: handlers/users/registration.py:111 -msgid "" -"Произошла неизвестная ошибка! Попробуйте изменить комментарий позже в " -"разделе \"Меню\"\n" -"\n" -"Выберите, кого вы хотите найти: " -msgstr "" - -#: handlers/users/registration.py:125 -msgid "Отлично! Теперь напишите мне ваше имя, которое будут все видеть в анкете" -msgstr "" - -#: handlers/users/registration.py:145 -msgid "Введите сколько вам лет:" -msgstr "" - -#: handlers/users/registration.py:170 -msgid "Вы ввели не число" -msgstr "" - -#: handlers/users/registration.py:175 -msgid "Нажмите на кнопку ниже, чтобы определить ваш местоположение!" -msgstr "" - -#: handlers/users/registration.py:188 -msgid "Мы не смогли найти такой город, попробуйте еще раз" -msgstr "" - -#: handlers/users/registration.py:211 handlers/users/registration.py:224 -msgid "" -"И напоследок, Пришлите мне вашу фотографию (отправлять надо сжатое " -"изображение, а не как документ)" -msgstr "" - -#: handlers/users/sponsor.py:10 -msgid "" -"Наш проект работает на Open Source и мы будем рады,если вы нам " -"поможете развивать проект.\n" -"\n" -"С помощью кнопки 💰 Донат вы можете отправить своё пожертвование" -msgstr "" - -#: handlers/users/start_handler.py:27 -msgid "Вам необходимо зарегистрировать агента(ов) тех поддержки" -msgstr "" - -#: handlers/users/start_handler.py:36 -msgid "Вас нет в базе данной" -msgstr "" - -#: handlers/users/start_handler.py:42 handlers/users/start_handler.py:47 -msgid "Выберите язык" -msgstr "" - -#: handlers/users/start_handler.py:57 -msgid "Язык был успешно изменен. Введите команду /start" -msgstr "" - -#: handlers/users/start_handler.py:61 -msgid "Произошла какая-то ошибка. Введите команду /start и попробуйте еще раз" -msgstr "" - -#: handlers/users/support_handler.py:20 -msgid "Хотите связаться с тех поддержкой? Нажмите на кнопку ниже!" -msgstr "" - -#: handlers/users/support_handler.py:25 handlers/users/support_handler.py:52 -msgid "К сожалению, сейчас нет свободных операторов. Попробуйте позже." -msgstr "" - -#: handlers/users/support_handler.py:41 -msgid "Вы обратились в техническую поддержку. Ждем ответа от оператора!" -msgstr "" - -#: handlers/users/support_handler.py:64 -msgid "С вами хочет связаться пользователь {full_name}" -msgstr "" - -#: handlers/users/support_handler.py:79 -msgid "К сожалению, пользователь уже передумал." -msgstr "" - -#: handlers/users/support_handler.py:91 -msgid "" -"Вы на связи с пользователем!\n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" - -#: handlers/users/support_handler.py:100 -msgid "" -"Техподдержка на связи! Можете писать сюда свое сообщение. \n" -"Чтобы завершить общение нажмите на кнопку." -msgstr "" - -#: handlers/users/support_handler.py:115 -msgid "Дождитесь ответа оператора или отмените сеанс" -msgstr "" - -#: handlers/users/support_handler.py:131 -msgid "Пользователь завершил сеанс техподдержки" -msgstr "" - -#: handlers/users/support_handler.py:135 -msgid "Вы завершили сеанс и были возвращены в главное меню" -msgstr "" - -#: handlers/users/user_profile.py:23 -msgid "" -"Ваша анкета удалена!\n" -"Я надеюсь вы кого-нибудь нашли" -msgstr "" - -#: handlers/users/verification.py:17 -msgid "Чтобы пройти верификацию вам нужно отправить свой контакт" -msgstr "" - -#: handlers/users/verification.py:33 -msgid "" -"Спасибо, {contact_full_name}.\n" -"Ваш номер {contact_phone_number} был получен." -msgstr "" - -#: handlers/users/verification.py:50 -msgid "Ваш номер недействителен, попробуйте еще раз." -msgstr "" - -#: handlers/users/view_event.py:27 -msgid "На данный момент вы просмотрели все существующие анкеты" -msgstr "" - -#: handlers/users/view_ques.py:73 -msgid "Жалоба успешно отправлена" -msgstr "" - -#: handlers/users/view_ques.py:112 -msgid "" -"Слишком много ❤️ за сегодня.\n" -"\n" -"Пригласи друзей и получи больше ❤️\n" -"\n" -"https://t.me/{}?start={}" -msgstr "" - -#: keyboards/admin/inline/customers.py:12 -msgid "🔍 Найти пользователя" -msgstr "" - -#: keyboards/admin/inline/customers.py:23 -msgid "🟢 Разблокировать" -msgstr "" - -#: keyboards/admin/inline/customers.py:28 -msgid "🚫 Заблокировать" -msgstr "" - -#: keyboards/admin/inline/mailing.py:8 -msgid "📧 Рассылка" -msgstr "" - -#: keyboards/admin/inline/mailing.py:16 keyboards/admin/inline/mailing.py:31 -#: keyboards/inline/admin_inline.py:9 -msgid "Подтвердить отправку" -msgstr "" - -#: keyboards/admin/inline/mailing.py:19 -msgid "Добавить кнопку" -msgstr "" - -#: keyboards/admin/inline/mailing.py:21 keyboards/admin/inline/mailing.py:33 -#: keyboards/inline/cancel_inline.py:8 -msgid "Отмена" -msgstr "" - -#: keyboards/admin/inline/payments.py:9 -msgid "⚙️ Настройки" -msgstr "" - -#: keyboards/admin/inline/payments.py:11 -msgid "📝 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:8 -msgid "📈 Статистика" -msgstr "" - -#: keyboards/admin/inline/ref.py:9 keyboards/admin/inline/setting.py:8 -msgid "*️⃣ Добавить" -msgstr "" - -#: keyboards/admin/inline/ref.py:10 keyboards/admin/inline/setting.py:9 -msgid "❌ Удалить" -msgstr "" - -#: keyboards/admin/inline/ref.py:11 keyboards/admin/inline/setting.py:10 -msgid "◀️ Назад" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:9 -msgid "🙅🏻‍♂️ Отменить" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:17 -msgid "👮‍♂️ Админ Состав" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:19 -msgid "📞 Сменить контакты" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:29 -msgid "🗒 Выгрузить юзеров | .txt" -msgstr "" - -#: keyboards/admin/inline/reply_menu.py:32 -msgid "🗒 Выгрузить конфиги и логи" -msgstr "" - -#: keyboards/default/admin_default.py:8 -msgid "Рассылка" -msgstr "" - -#: keyboards/default/admin_default.py:9 -msgid "Сообщение по id" -msgstr "" - -#: keyboards/default/admin_default.py:10 -msgid "Посчитать людей и чаты" -msgstr "" - -#: keyboards/default/admin_default.py:11 -msgid "Мониторинг" -msgstr "" - -#: keyboards/default/admin_default.py:12 -msgid "Тех.Работа" -msgstr "" - -#: keyboards/default/get_contact_default.py:8 -msgid "📱 Отправить" -msgstr "" - -#: keyboards/default/get_location_default.py:9 -msgid "🗺 Определить автоматически" -msgstr "" - -#: keyboards/default/get_photo.py:8 -msgid "Взять из профиля" -msgstr "" - -#: keyboards/inline/admin_inline.py:18 -msgid "Включить" -msgstr "" - -#: keyboards/inline/admin_inline.py:21 -msgid "Выключить" -msgstr "" - -#: keyboards/inline/admin_inline.py:33 -msgid "Разблокировать" -msgstr "" - -#: keyboards/inline/back_inline.py:8 -#: keyboards/inline/change_data_profile_inline.py:15 -#: keyboards/inline/filters_inline.py:42 keyboards/inline/language_inline.py:22 -#: keyboards/inline/poster_inline.py:31 keyboards/inline/poster_inline.py:49 -#: keyboards/inline/poster_inline.py:63 -#: keyboards/inline/registration_inline.py:12 -#: keyboards/inline/settings_menu.py:12 keyboards/inline/sponsor_inline.py:10 -#: keyboards/inline/sponsor_inline.py:21 -msgid "⏪️ Вернуться в меню" -msgstr "" - -#: keyboards/inline/cancel_inline.py:16 -#: keyboards/inline/change_data_profile_inline.py:28 -msgid "❌ Остановить" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:8 -msgid "👤 Имя" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:9 -msgid "⚧ Пол" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:10 -msgid "📅 Возраст" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:11 -msgid "🏙 Город" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:12 -msgid "📷 Фото" -msgstr "" - -#: keyboards/inline/change_data_profile_inline.py:13 -msgid "📝 О себе" -msgstr "" - -#: keyboards/inline/filters_inline.py:9 -msgid "🎉 Мероприятия" -msgstr "" - -#: keyboards/inline/filters_inline.py:12 -msgid "❤️ Знакомства" -msgstr "" - -#: keyboards/inline/filters_inline.py:14 keyboards/inline/filters_inline.py:31 -#: keyboards/inline/guide_inline.py:15 -msgid "⏪️ Назад" -msgstr "" - -#: keyboards/inline/filters_inline.py:23 -msgid "🏙️ Город партнера" -msgstr "" - -#: keyboards/inline/filters_inline.py:26 -msgid "🔞 Возр.диапазон" -msgstr "" - -#: keyboards/inline/filters_inline.py:29 -msgid "🚻 Пол партнера" -msgstr "" - -#: keyboards/inline/filters_inline.py:40 -msgid "🏙️ Город" -msgstr "" - -#: keyboards/inline/guide_inline.py:21 -msgid "Вперед ➡️" -msgstr "" - -#: keyboards/inline/guide_inline.py:25 -msgid "❌ Закрыть" -msgstr "" - -#: keyboards/inline/language_inline.py:13 -msgid "🇷🇺 Русский" -msgstr "" - -#: keyboards/inline/language_inline.py:14 -msgid "🇩🇪 Немецкий" -msgstr "" - -#: keyboards/inline/language_inline.py:15 -msgid "🇬🇧 Английский" -msgstr "" - -#: keyboards/inline/language_inline.py:16 -msgid "🇮🇩 Индонезийский" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:26 -msgid "➕ Регистрация" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:28 keyboards/inline/settings_menu.py:10 -msgid "🌐 Язык" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:30 -msgid "👤 Моя анекта" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:32 -msgid "⚙️ Фильтры" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:33 -msgid "💌 Найти пару" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:34 -msgid "🗓️ Афиша" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:35 -msgid "🆘 Поддержка" -msgstr "" - -#: keyboards/inline/main_menu_inline.py:37 -msgid "ℹ️ Информация" -msgstr "" - -#: keyboards/inline/menu_profile_inline.py:10 -msgid "✅ Верификация" -msgstr "" - -#: keyboards/inline/menu_profile_inline.py:16 -msgid "🖊️ Изменить" -msgstr "" - -#: keyboards/inline/menu_profile_inline.py:18 -msgid "🗑️ Удалить" -msgstr "" - -#: keyboards/inline/menu_profile_inline.py:19 -msgid "⏪ Назад" -msgstr "" - -#: keyboards/inline/payments_inline.py:9 -msgid "💳 ЮMoney" -msgstr "" - -#: keyboards/inline/payments_inline.py:16 -msgid "💳 Оплатить" -msgstr "" - -#: keyboards/inline/payments_inline.py:18 -msgid "🔄 Проверить оплату" -msgstr "" - -#: keyboards/inline/poster_inline.py:21 -msgid "✍️Создать афишу" -msgstr "" - -#: keyboards/inline/poster_inline.py:24 -msgid "🎭 Смотреть афиши" -msgstr "" - -#: keyboards/inline/poster_inline.py:27 -msgid "📝 Мои записи" -msgstr "" - -#: keyboards/inline/poster_inline.py:29 -msgid "📃 Моё событие" -msgstr "" - -#: keyboards/inline/poster_inline.py:46 -msgid "✍️ Изменить" -msgstr "" - -#: keyboards/inline/poster_inline.py:58 -msgid "Название" -msgstr "" - -#: keyboards/inline/poster_inline.py:60 -msgid "Описание" -msgstr "" - -#: keyboards/inline/poster_inline.py:73 -msgid "✅ Одобрить" -msgstr "" - -#: keyboards/inline/poster_inline.py:76 -msgid "❌ Отклонить" -msgstr "" - -#: keyboards/inline/poster_inline.py:85 -msgid "Пойду!" -msgstr "" - -#: keyboards/inline/poster_inline.py:88 -msgid "Не интересно" -msgstr "" - -#: keyboards/inline/poster_inline.py:91 keyboards/inline/poster_inline.py:103 -#: keyboards/inline/poster_inline.py:112 -msgid "⏪️ Остановить" -msgstr "" - -#: keyboards/inline/poster_inline.py:101 -msgid "❌ Отменить запись" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:30 -msgid "💤 Остановить" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:34 -msgid "🚫 Забанить" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:38 -msgid "Следующий" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:74 -msgid "🚀 Смотреть" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:82 -msgid "👉 Перейти в чат" -msgstr "" - -#: keyboards/inline/questionnaires_inline.py:89 -msgid "⏪️ Вернуться к просмотру анкет" -msgstr "" - -#: keyboards/inline/registration_inline.py:9 -msgid "🖌️ Пройти опрос в боте" -msgstr "" - -#: keyboards/inline/registration_inline.py:21 -msgid "✅ Да все хорошо!" -msgstr "" - -#: keyboards/inline/settings_menu.py:8 -msgid "📚 Брендбук" -msgstr "" - -#: keyboards/inline/settings_menu.py:9 -msgid "📞 Контакты" -msgstr "" - -#: keyboards/inline/support_inline.py:37 -msgid "Ответить пользователю" -msgstr "" - -#: keyboards/inline/support_inline.py:45 -msgid "Написать оператору" -msgstr "" - -#: keyboards/inline/support_inline.py:60 keyboards/inline/support_inline.py:72 -msgid "Завершить сеанс" -msgstr "" - -#: middlewares/BanCheck.py:44 -msgid "😢 Вы заблокированы!" -msgstr "" - -#: middlewares/IsMaintenanceCheck.py:26 -msgid "Ведутся технические работы" -msgstr "" - -#: middlewares/LinkCheck.py:38 -msgid "" -"Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " -"подпишитесь! Ссылки ниже: " -msgstr "" - -#: utils/notify_admins.py:24 -msgid "Оповещение администрации..." -msgstr "" - -#: utils/notify_admins.py:28 -msgid "Бот был успешно запущен" -msgstr "" - -#: utils/statistics.py:16 -msgid "" -"📊 Статистика: \n" -"\n" -"└Сейчас в нашем боте {count_users} пользователей\n" -"└Из них:\n" -" ├{users_gender_m} пользователей мужского пола\n" -" ├{users_gender_f} пользователей женского пола\n" -" ├{users_city} пользователей из города {user_city}\n" -" ├{cs_uy} пользователей из других городов\n" -" ├{users_verified} верифицированных пользователей\n" -" ├{users_status} пользователей, создавшие анкету\n" -"└Дата создания бота - 10.08.2021" -msgstr "" - -#~ msgid "Вам необходимо зарегистрироваться, нажмите на кнопку ниже" -#~ msgstr "" - -#~ msgid "" -#~ "Описание анкеты пользователя.\n" -#~ "\n" -#~ "Мы не проверяем голосовые сообщения, " -#~ "поэтому советуем уменьшить громкость звука" -#~ msgstr "" - -#~ msgid "Описание вашей анкеты" -#~ msgstr "" - -#~ msgid "Вы вошли в админ панель!" -#~ msgstr "" - -#~ msgid "Количество людей внутри бота: {users}\n" -#~ msgstr "" - -#~ msgid "Отправьте мне id получателя!" -#~ msgstr "" - -#~ msgid "ID принят! Теперь введите текст!" -#~ msgstr "" - -#~ msgid "Сообщение успешно отправлено!" -#~ msgstr "" - -#~ msgid "" -#~ "Пришлите текст для рассылки либо фото" -#~ " с текстом для рассылки! Чтобы " -#~ "отредактировать, используйте встроенный редактор " -#~ "телеграма!\n" -#~ msgstr "" - -#~ msgid "" -#~ "Руководство по боту: \n" -#~ "Страница №2" -#~ msgstr "" - -#~ msgid "" -#~ "Руководство по боту: \n" -#~ "Страница №3" -#~ msgstr "" - -#~ msgid "" -#~ "Руководство по боту: \n" -#~ "Страница №4" -#~ msgstr "" - -#~ msgid "Теперь выберите, как вы хотите рассказать о себе:\n" -#~ msgstr "" - -#~ msgid "Запишите голосовое сообщение" -#~ msgstr "" - -#~ msgid "Отправьте сообщение о себе" -#~ msgstr "" - -#~ msgid "Парень" -#~ msgstr "" - -#~ msgid "Девушка" -#~ msgstr "" - -#~ msgid "💬 Руководство" -#~ msgstr "" - -#~ msgid "📈 Статистика" -#~ msgstr "" - -#~ msgid "💬 Текстом" -#~ msgstr "" - -#~ msgid "🎤 Голосовым" -#~ msgstr "" - -#~ msgid "🕴️ Спонсорство" -#~ msgstr "" - -#~ msgid "💰 Донат" -#~ msgstr "" - -#~ msgid "" -#~ "{}, {} лет, {} {}\n" -#~ "\n" -#~ "{}\n" -#~ "\n" -#~ "Партнерка:\n" -#~ "Количество приглашенных друзей: {}\n" -#~ "Реферальная ссылка: {}" -#~ msgstr "" - -#~ msgid "" -#~ "\n" -#~ "\n" -#~ "Инстаграм - {}\n" -#~ msgstr "" - -#~ msgid "" -#~ "У вас не установлен username, " -#~ "пожалуйста, зайдите в настройки аккаунта " -#~ "и создайте username.\n" -#~ "Без него вы не сможете пользоваться ботом\n" -#~ "\n" -#~ "Инструкция №1\n" -#~ "Инструкция №2" -#~ msgstr "" - -#~ msgid "" -#~ "Вами заинтересовался пользователь {varname_0}" -#~ msgstr "" - -#~ msgid "Ваша анкета отправлена другому пользователю" -#~ msgstr "" - -#~ msgid "👱🏻‍♂️ Парень" -#~ msgstr "" - -#~ msgid "👱🏻‍♀️ Девушка" -#~ msgstr "" - -#~ msgid "Изменить анкету" -#~ msgstr "" - -#~ msgid "📸 Instagram" -#~ msgstr "" - -#~ msgid "Удалить анкету" -#~ msgstr "" - -#~ msgid "Смотреть афиши" -#~ msgstr "" - -#~ msgid "🎭 Моё событие" -#~ msgstr "" - -#~ msgid "Вернуться к просмотру анкет" -#~ msgstr "" - -#~ msgid "" -#~ "Произошла ошибка! Попробуйте еще раз\n" -#~ "Если ошибка осталась, напишите агенту поддержки." -#~ msgstr "" - -#~ msgid "Под ваши фильтры нет пользователей" -#~ msgstr "" - -#~ msgid "" -#~ "{}, {} лет, {}, {} {}\n" -#~ "\n" -#~ "{}\n" -#~ "\n" -#~ "Партнерка:\n" -#~ "Количество приглашенных друзей: {}\n" -#~ "Реферальная ссылка: {}" -#~ msgstr "" - -#~ msgid "" -#~ "📧 Рассылка:\n" -#~ "Пришлите текст для рассылки либо фото" -#~ " с текстом для рассылки! Чтобы " -#~ "отредактировать, используйте встроенный редактор " -#~ "телеграма!\n" -#~ msgstr "" - -#~ msgid "" -#~ "💳 Стоимость разбана - 600\n" -#~ "├Чтобы проверить актуальность цен, нажмите на кнопку \n" -#~ "├🔄 Проверить цены\n" -#~ "├Если у вас нет Qiwi или нет возможности\n" -#~ "├оплатить с помощью киви, напишите агенту поддержки" -#~ msgstr "" - -#~ msgid "✔️ Цена актуальна" -#~ msgstr "" - -#~ msgid "" -#~ "После оплаты нажмите Проверить оплату\n" -#~ "Если не получается оплатить по странице ниже" -#~ msgstr "" - -#~ msgid "Оплата прошла успешно!" -#~ msgstr "" - -#~ msgid "Произошла неизвестная ошибка. Попробуйте ещё раз" -#~ msgstr "" - -#~ msgid "Ваш новый пол: Мужской" -#~ msgstr "" - -#~ msgid "Ваш новый пол: Женский" -#~ msgstr "" - -#~ msgid "" -#~ "Произошла ошибка! Попробуйте еще раз " -#~ "изменить описание. Возможно, Ваше сообщение" -#~ " слишком большое\n" -#~ "Если ошибка осталась, напишите системному администратору." -#~ msgstr "" - -#~ msgid "Произошла неизвестная ошибка! Попробуйте еще раз" -#~ msgstr "" - -#~ msgid "" -#~ "Введите город в котором проживаете.\n" -#~ "Для точного определения местоположения, можете нажать на кнопку ниже!" -#~ msgstr "" - -#~ msgid "И напоследок, Пришлите мне вашу фотографию" -#~ msgstr "" - -#~ msgid "Имя" -#~ msgstr "" - -#~ msgid "Пол" -#~ msgstr "" - -#~ msgid "Возраст" -#~ msgstr "" - -#~ msgid "Город" -#~ msgstr "" - -#~ msgid "Фото" -#~ msgstr "" - -#~ msgid "О себе" -#~ msgstr "" - -#~ msgid "✏️ Информация" -#~ msgstr "" - -#~ msgid "🖌️ Изменить" -#~ msgstr "" - -#~ msgid "💳 Qiwi" -#~ msgstr "" - -#~ msgid "🔄 Проверить цены" -#~ msgstr "" - -#~ msgid "Оплатить" -#~ msgstr "" - -#~ msgid "Проверить оплату" -#~ msgstr "" - -#~ msgid "💬 Брендбук" -#~ msgstr "" - -#~ msgid "" -#~ "Я нашел такой адрес:\n" -#~ "{city}\n" -#~ "Если все правильно то подтвердите" -#~ msgstr "" - -#~ msgid "" -#~ "Вы попали в раздел настроек бота," -#~ " здесь вы можете посмотреть: " -#~ "статистику,изменить язык, отключить уведомления, " -#~ "а также узнать информацию.\n" -#~ "\n" -#~ "🌐 Дней работаем: {}\n" -#~ "👤 Всего пользователей: {}\n" -#~ msgstr "" - -#~ msgid "🇫🇷 Французский" -#~ msgstr "" - -#~ msgid "🟢 Запустить бота" -#~ msgstr "" - -#~ msgid "⚒ Админ-Меню" -#~ msgstr "" - -#~ msgid "🗒 Логи" -#~ msgstr "" - -#~ msgid "Ваше новое имя: {censored}" -#~ msgstr "" - -#~ msgid "Ваш новый возраст: {messages}" -#~ msgstr "" - -#~ msgid "Ваш новый пол: {}" -#~ msgstr "" - -#~ msgid "Отправьте мне новое описание анкеты:" -#~ msgstr "" - -#~ msgid "Отправьте голосовое сообщение" -#~ msgstr "" - -#~ msgid "Комментарий принят!" -#~ msgstr "" - -#~ msgid "🫂 Пользователи" -#~ msgstr "" - -#~ msgid "📊 Реклама" -#~ msgstr "" - -#~ msgid "👀 Мониторинг" -#~ msgstr "" - -#~ msgid "🛑 Тех.Работа" -#~ msgstr "" - -#~ msgid "Чат с админом не найден" -#~ msgstr "" - diff --git a/locales/ru/LC_MESSAGES/messages.po b/locales/ru/LC_MESSAGES/messages.po new file mode 100644 index 0000000..e6de646 --- /dev/null +++ b/locales/ru/LC_MESSAGES/messages.po @@ -0,0 +1,100 @@ +# Russian translations for PROJECT. +# Copyright (C) 2024 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2024-05-07 10:01+0300\n" +"PO-Revision-Date: 2024-05-07 10:11+0300\n" +"Last-Translator: FULL NAME \n" +"Language: ru\n" +"Language-Team: ru \n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.15.0\n" + +#: src/tgbot/handlers/start.py:74 +msgid "Наша система полностью open-source" +msgstr "" + +#: src/tgbot/keyboards/inline.py:24 +msgid "👤 Мой профиль" +msgstr "" + +#: src/tgbot/keyboards/inline.py:27 +msgid "🔙 Выйти из аккаунта" +msgstr "" + +#: src/tgbot/keyboards/inline.py:36 +msgid "🚀 Активировать" +msgstr "" + +#: src/tgbot/keyboards/reply.py:16 +msgid "👤 Аккаунт" +msgstr "" + +#: src/tgbot/keyboards/reply.py:19 +msgid "💜 Знакомства" +msgstr "" + +#: src/tgbot/keyboards/reply.py:20 +msgid "🎭 Мероприятия" +msgstr "" + +#: src/tgbot/keyboards/reply.py:23 +msgid "ℹ️ О проекте" +msgstr "" + +#: src/tgbot/keyboards/reply.py:31 +msgid "📝 Создать аккаунт" +msgstr "" + +#: src/tgbot/keyboards/reply.py:32 +msgid "🔑 Войти в аккаунт" +msgstr "" + +#: src/tgbot/services/app/set_bot_commands.py:27 +msgid "🟢 Запустить бота" +msgstr "" + +#: src/tgbot/services/app/user.py:35 +msgid "🎉 Добро пожаловать, {username}! Вы создали новый аккаунт" +msgstr "" + +#: src/tgbot/services/app/user.py:36 +msgid "👋 Привет {username} вы вошли в аккаунт" +msgstr "" + +#: src/tgbot/services/app/user.py:37 +msgid "" +"🛑 К сожалению, ваш аккаунт был деактивирован, и доступ к приложению " +"ограничен.\n" +"Чтобы возобновить работу с нашим приложением, пожалуйста, активируйте " +"аккаунт.\n" +"Чтобы активировать аккаунт, используйте команду /reactivate." +msgstr "" + +#: src/tgbot/services/app/user.py:103 +msgid "" +"🔍 Извините, мы не смогли найти ваш аккаунт.\n" +"Если вы еще не зарегистрированы, вы можете создать новый аккаунт, нажав " +"на кнопку 'Создать аккаунт' ниже.\n" +"Если вы уже зарегистрированы, пожалуйста, войдите в свой аккаунт, " +"используя ваш логин и пароль." +msgstr "" + +#: src/tgbot/services/app/user.py:132 +msgid "С возвращением, {username}" +msgstr "" + +#: src/tgbot/services/app/user.py:136 +msgid "" +"🔐 Ой, кажется, вы ввели неправильный логин или пароль. Пожалуйста, " +"проверьте введенные данные и попробуйте снова." +msgstr "" diff --git a/middlewares/AgentSupport.py b/middlewares/AgentSupport.py deleted file mode 100644 index d1c2d94..0000000 --- a/middlewares/AgentSupport.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import ( - NoReturn, -) - -from aiogram import ( - Dispatcher, - types, -) -from aiogram.dispatcher.handler import ( - CancelHandler, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) - - -class SupportMiddleware(BaseMiddleware): - @staticmethod - async def on_pre_process_message(message: types.Message, data: dict) -> NoReturn: - dispatcher = Dispatcher.get_current() - state = dispatcher.current_state( - chat=message.from_user.id, user=message.from_user.id - ) - - state_str = str(await state.get_state()) - if state_str == "in_support": - data = await state.get_data() - second_id = data.get("second_id") - await message.copy_to(second_id) - - raise CancelHandler() diff --git a/middlewares/BanCheck.py b/middlewares/BanCheck.py deleted file mode 100644 index a8d7498..0000000 --- a/middlewares/BanCheck.py +++ /dev/null @@ -1,66 +0,0 @@ -from typing import ( - NoReturn, - Union, -) - -from aiogram import ( - types, -) -from aiogram.dispatcher.handler import ( - CancelHandler, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) - -from keyboards.inline.admin_inline import ( - unban_user_keyboard, -) -from loader import ( - _, -) -from utils.db_api import ( - db_commands, -) - - -class BanMiddleware(BaseMiddleware): - def __init__(self): - super(BanMiddleware, self).__init__() - - @staticmethod - async def is_banned(user): - try: - return user.is_banned - except AttributeError: - return False - - async def on_process_message(self, message: types.Message, data: dict) -> None: - await self.check_ban_user(obj=message) - - async def on_process_callback_query( - self, call: types.CallbackQuery, data: dict - ) -> None: - user = await db_commands.select_user(telegram_id=call.from_user.id) - if (user is not None and await self.is_banned(user=user)) and ( - call.data != "unban" - and call.data != "unban_menu" - and call.data != "yoomoney:check_payment" - and call.data != "cancel_payment" - and call.data != "yoomoney" - ): - await self.check_ban_user(obj=call) - - async def check_ban_user( - self, obj: Union[types.CallbackQuery, types.Message] - ) -> NoReturn: - user = await db_commands.select_user(telegram_id=obj.from_user.id) - - text = _("😢 Вы заблокированы!") - markup = await unban_user_keyboard() - if await self.is_banned(user=user): - try: - await obj.answer(text=text, reply_markup=markup) - except TypeError: - await obj.message.answer(text=text, reply_markup=markup) - raise CancelHandler() diff --git a/middlewares/IsMaintenanceCheck.py b/middlewares/IsMaintenanceCheck.py deleted file mode 100644 index 0861206..0000000 --- a/middlewares/IsMaintenanceCheck.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import ( - NoReturn, - Union, -) - -from aiogram import ( - types, -) -from aiogram.dispatcher.handler import ( - CancelHandler, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) - -from data.config import ( - load_config, -) -from loader import ( - _, -) -from utils.db_api import ( - db_commands, -) - - -class IsMaintenance(BaseMiddleware): - def __init__(self): - super(IsMaintenance, self).__init__() - - async def on_process_message(self, message: types.Message, data: dict): - await self.check_tech_works(obj=message) - - async def on_process_callback_query(self, call: types.CallbackQuery, data: dict): - await self.check_tech_works(obj=call) - - @staticmethod - async def check_tech_works( - obj: Union[types.CallbackQuery, types.Message] - ) -> NoReturn: - text = _("Ведутся технические работы") - try: - setting = await db_commands.select_setting_tech_work() - tech_works = setting.get("technical_works", False) - if tech_works and obj.from_user.id not in load_config().tg_bot.admin_ids: - try: - await obj.answer(text=text, show_alert=True) - except TypeError: - await obj.answer(text=text) - raise CancelHandler() - except AttributeError: - pass diff --git a/middlewares/LinkCheck.py b/middlewares/LinkCheck.py deleted file mode 100644 index d977a3d..0000000 --- a/middlewares/LinkCheck.py +++ /dev/null @@ -1,72 +0,0 @@ -import asyncio -from typing import ( - NoReturn, - Union, -) - -from aiogram import ( - types, -) -from aiogram.dispatcher.handler import ( - CancelHandler, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) - -from data.config import ( - load_config, -) -from keyboards.inline.necessary_links_inline import ( - necessary_links_keyboard, -) -from loader import ( - _, - bot, -) -from utils.db_api import ( - db_commands, -) - - -class LinkCheckMiddleware(BaseMiddleware): - async def on_process_message(self, message: types.Message, data: dict) -> None: - if isinstance(message.chat.type, types.ChatType): - await self._check_links_and_handle(message.from_user.id, obj=message) - - async def on_process_callback_query( - self, call: types.CallbackQuery, data: dict - ) -> None: - await self._check_links_and_handle(call.from_user.id, obj=call) - - @staticmethod - async def _check_links_and_handle( - user_id: int, obj: Union[types.CallbackQuery, types.Message] - ) -> NoReturn: - links_db = await db_commands.select_all_links() - subscribed_links = set() - - async def check_subscription(link_id): - check = await bot.get_chat_member(chat_id=link_id, user_id=user_id) - return check.status != "left" - - for link in links_db: - if await check_subscription(link["telegram_link_id"]): - subscribed_links.add(link["telegram_link_id"]) - text, markup = _( - "Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " - "подпишитесь! Ссылки ниже: " - ), await necessary_links_keyboard( - telegram_id=user_id, - links_db=links_db, - ) - if ( - len(subscribed_links) != len(links_db) - and obj.from_user.id not in load_config().tg_bot.admin_ids - ): - try: - await obj.answer(text=text, reply_markup=markup) - except TypeError: - await obj.message.answer(text=text, reply_markup=markup) - await asyncio.sleep(1) - raise CancelHandler() diff --git a/middlewares/Log.py b/middlewares/Log.py deleted file mode 100644 index a34dc75..0000000 --- a/middlewares/Log.py +++ /dev/null @@ -1,18 +0,0 @@ -from aiogram import ( - types, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) - -from loader import ( - logger, -) - - -class LogMiddleware(BaseMiddleware): - async def on_process_message(self, message: types.Message, data: dict): - logger.info(message) - - async def on_process_callback_query(self, call: types.CallbackQuery, data: dict): - logger.info(call) diff --git a/middlewares/Throttling.py b/middlewares/Throttling.py deleted file mode 100644 index 2a6a394..0000000 --- a/middlewares/Throttling.py +++ /dev/null @@ -1,66 +0,0 @@ -import asyncio -from typing import ( - NoReturn, -) - -from aiogram import ( - Dispatcher, - types, -) -from aiogram.dispatcher import ( - DEFAULT_RATE_LIMIT, -) -from aiogram.dispatcher.handler import ( - CancelHandler, - current_handler, -) -from aiogram.dispatcher.middlewares import ( - BaseMiddleware, -) -from aiogram.utils.exceptions import ( - Throttled, -) - - -class ThrottlingMiddleware(BaseMiddleware): - def __init__(self, limit=DEFAULT_RATE_LIMIT, key_prefix="antiflood_"): - self.rate_limit = limit - self.prefix = key_prefix - super(ThrottlingMiddleware, self).__init__() - - # noinspection PyUnusedLocal - async def on_process_message(self, message: types.Message, data: dict) -> NoReturn: - handler = current_handler.get() - dispatcher = Dispatcher.get_current() - if handler: - limit = getattr(handler, "throttling_rate_limit", self.rate_limit) - key = getattr( - handler, "throttling_key", f"{self.prefix}_{handler.__name__}" - ) - else: - limit = self.rate_limit - key = f"{self.prefix}_message" - try: - await dispatcher.throttle(key, rate=limit) - except Throttled as t: - await self.message_throttled(message, t) - raise CancelHandler() - - async def message_throttled( - self, message: types.Message, throttled: Throttled - ) -> None: - handler = current_handler.get() - dispatcher = Dispatcher.get_current() - if handler: - key = getattr( - handler, "throttling_key", f"{self.prefix}_{handler.__name__}" - ) - else: - key = f"{self.prefix}_message" - delta = throttled.rate - throttled.delta - if throttled.exceeded_count <= 2: - await message.reply("Too many requests! ") - await asyncio.sleep(delta) - thr = await dispatcher.check_key(key) - if thr.exceeded_count == throttled.exceeded_count: - await message.reply("Unlocked.") diff --git a/middlewares/__init__.py b/middlewares/__init__.py deleted file mode 100644 index 69228fb..0000000 --- a/middlewares/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -from loader import ( - dp, - scheduler, -) - -from .AgentSupport import ( - SupportMiddleware, -) -from .BanCheck import ( - BanMiddleware, -) -from .IsMaintenanceCheck import ( - IsMaintenance, -) -from .LinkCheck import ( - LinkCheckMiddleware, -) -from .Log import ( - LogMiddleware, -) -from .SchedulerWare import ( - SchedulerMiddleware, -) -from .Throttling import ( - ThrottlingMiddleware, -) - -if __name__ == "middlewares": - dp.middleware.setup(ThrottlingMiddleware()) - dp.middleware.setup(LinkCheckMiddleware()) - dp.middleware.setup(SupportMiddleware()) - dp.middleware.setup(IsMaintenance()) - dp.middleware.setup(SchedulerMiddleware(scheduler)) - dp.middleware.setup(BanMiddleware()) - dp.middleware.setup(LogMiddleware()) diff --git a/poetry.lock b/poetry.lock index 0eba968..a2817cc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiofiles" @@ -13,132 +13,145 @@ files = [ [[package]] name = "aiogram" -version = "2.25.1" -description = "Is a pretty simple and fully asynchronous framework for Telegram Bot API" +version = "3.8.0" +description = "Modern and fully asynchronous framework for Telegram Bot API" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "aiogram-3.8.0-py3-none-any.whl", hash = "sha256:7e30f53fb3c6420007a3a0085aeef79c00c6b788cff9f39d2198a98e599a609f"}, + {file = "aiogram-3.8.0.tar.gz", hash = "sha256:fc0737cffaf29d0f1ba1688914d42e99fc235b618185c22678a6c928e0100304"}, +] + +[package.dependencies] +aiofiles = ">=23.2.1,<23.3.0" +aiohttp = ">=3.9.0,<3.10.0" +certifi = ">=2023.7.22" +magic-filter = ">=1.0.12,<1.1" +pydantic = ">=2.4.1,<2.8" +typing-extensions = ">=4.7.0,<=5.0" + +[package.extras] +cli = ["aiogram-cli (>=1.0.3,<1.1.0)"] +dev = ["black (>=24.4.2,<24.5.0)", "isort (>=5.13.2,<5.14.0)", "motor-types (>=1.0.0b4,<1.1.0)", "mypy (>=1.10.0,<1.11.0)", "packaging (>=24.1,<25.0)", "pre-commit (>=3.5,<4.0)", "ruff (>=0.4.9,<0.5.0)", "toml (>=0.10.2,<0.11.0)"] +docs = ["furo (>=2023.9.10,<2023.10.0)", "markdown-include (>=0.8.1,<0.9.0)", "pygments (>=2.16.1,<2.17.0)", "pymdown-extensions (>=10.3,<11.0)", "sphinx (>=7.2.6,<7.3.0)", "sphinx-autobuild (>=2021.3.14,<2021.4.0)", "sphinx-copybutton (>=0.5.2,<0.6.0)", "sphinx-intl (>=2.1.0,<2.2.0)", "sphinx-substitution-extensions (>=2022.2.16,<2022.3.0)", "sphinxcontrib-towncrier (>=0.3.2a0,<0.4.0)", "towncrier (>=23.6.0,<23.7.0)"] +fast = ["aiodns (>=3.0.0)", "uvloop (>=0.17.0)"] +i18n = ["babel (>=2.13.0,<2.14.0)"] +mongo = ["motor (>=3.3.2,<3.4.0)"] +proxy = ["aiohttp-socks (>=0.8.3,<0.9.0)"] +redis = ["redis[hiredis] (>=5.0.1,<5.1.0)"] +test = ["aresponses (>=2.1.6,<2.2.0)", "pycryptodomex (>=3.19.0,<3.20.0)", "pytest (>=7.4.2,<7.5.0)", "pytest-aiohttp (>=1.0.5,<1.1.0)", "pytest-asyncio (>=0.21.1,<0.22.0)", "pytest-cov (>=4.1.0,<4.2.0)", "pytest-html (>=4.0.2,<4.1.0)", "pytest-lazy-fixture (>=0.6.3,<0.7.0)", "pytest-mock (>=3.12.0,<3.13.0)", "pytest-mypy (>=0.10.3,<0.11.0)", "pytz (>=2023.3,<2024.0)"] + +[[package]] +name = "aiogram-calendar" +version = "0.5.0" +description = "Simple Inline Calendar & Date Selection tool for Aiogram Telegram bots" +optional = false +python-versions = ">=3.8" files = [ - {file = "aiogram-2.25.1-py3-none-any.whl", hash = "sha256:7bb770cd0459f1dbaea00578bf13fb2e6a1812f22adf94a988c11a7c0d5f33e1"}, - {file = "aiogram-2.25.1.tar.gz", hash = "sha256:59ad78fc0ebbef1fd471c15778a4594b60117e0d7373bc2ce7bcd192074d527d"}, + {file = "aiogram_calendar-0.5.0-py3-none-any.whl", hash = "sha256:73b1f900b946aea51e54ba0049cdd308ec775d1cb028599fcebd89fd38a0ff61"}, + {file = "aiogram_calendar-0.5.0.tar.gz", hash = "sha256:49d76bd55ccfbc5d2c1cb0866636a626d57ea09052fdf10ce62dd39162aa4225"}, ] [package.dependencies] -aiohttp = ">=3.8.0,<3.9.0" -Babel = ">=2.9.1,<2.10.0" -certifi = ">=2021.10.8" -magic-filter = ">=1.0.9" +aiogram = ">=3" [package.extras] -fast = ["ujson (>=1.35)", "uvloop (>=0.16.0,<0.17.0)"] -proxy = ["aiohttp-socks (>=0.5.3,<0.6.0)"] +dev = ["pytest", "pytest-asyncio"] [[package]] name = "aiohttp" -version = "3.8.6" +version = "3.9.2" description = "Async http client/server framework (asyncio)" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1"}, - {file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566"}, - {file = "aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed"}, - {file = "aiohttp-3.8.6-cp310-cp310-win32.whl", hash = "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2"}, - {file = "aiohttp-3.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f"}, - {file = "aiohttp-3.8.6-cp311-cp311-win32.whl", hash = "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb"}, - {file = "aiohttp-3.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0"}, - {file = "aiohttp-3.8.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d25036d161c4fe2225d1abff2bd52c34ed0b1099f02c208cd34d8c05729882f0"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d791245a894be071d5ab04bbb4850534261a7d4fd363b094a7b9963e8cdbd31"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0cccd1de239afa866e4ce5c789b3032442f19c261c7d8a01183fd956b1935349"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f13f60d78224f0dace220d8ab4ef1dbc37115eeeab8c06804fec11bec2bbd07"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a9b5a0606faca4f6cc0d338359d6fa137104c337f489cd135bb7fbdbccb1e39"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:13da35c9ceb847732bf5c6c5781dcf4780e14392e5d3b3c689f6d22f8e15ae31"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:4d4cbe4ffa9d05f46a28252efc5941e0462792930caa370a6efaf491f412bc66"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:229852e147f44da0241954fc6cb910ba074e597f06789c867cb7fb0621e0ba7a"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:713103a8bdde61d13490adf47171a1039fd880113981e55401a0f7b42c37d071"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:45ad816b2c8e3b60b510f30dbd37fe74fd4a772248a52bb021f6fd65dff809b6"}, - {file = "aiohttp-3.8.6-cp36-cp36m-win32.whl", hash = "sha256:2b8d4e166e600dcfbff51919c7a3789ff6ca8b3ecce16e1d9c96d95dd569eb4c"}, - {file = "aiohttp-3.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:0912ed87fee967940aacc5306d3aa8ba3a459fcd12add0b407081fbefc931e53"}, - {file = "aiohttp-3.8.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e2a988a0c673c2e12084f5e6ba3392d76c75ddb8ebc6c7e9ead68248101cd446"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf3fd9f141700b510d4b190094db0ce37ac6361a6806c153c161dc6c041ccda"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3161ce82ab85acd267c8f4b14aa226047a6bee1e4e6adb74b798bd42c6ae1f80"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95fc1bf33a9a81469aa760617b5971331cdd74370d1214f0b3109272c0e1e3c"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c43ecfef7deaf0617cee936836518e7424ee12cb709883f2c9a1adda63cc460"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca80e1b90a05a4f476547f904992ae81eda5c2c85c66ee4195bb8f9c5fb47f28"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:90c72ebb7cb3a08a7f40061079817133f502a160561d0675b0a6adf231382c92"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bb54c54510e47a8c7c8e63454a6acc817519337b2b78606c4e840871a3e15349"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:de6a1c9f6803b90e20869e6b99c2c18cef5cc691363954c93cb9adeb26d9f3ae"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:a3628b6c7b880b181a3ae0a0683698513874df63783fd89de99b7b7539e3e8a8"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df"}, - {file = "aiohttp-3.8.6-cp37-cp37m-win32.whl", hash = "sha256:f8ef51e459eb2ad8e7a66c1d6440c808485840ad55ecc3cafefadea47d1b1ba2"}, - {file = "aiohttp-3.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b2fe42e523be344124c6c8ef32a011444e869dc5f883c591ed87f84339de5976"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e2ee0ac5a1f5c7dd3197de309adfb99ac4617ff02b0603fd1e65b07dc772e4b"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01770d8c04bd8db568abb636c1fdd4f7140b284b8b3e0b4584f070180c1e5c62"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3c68330a59506254b556b99a91857428cab98b2f84061260a67865f7f52899f5"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89341b2c19fb5eac30c341133ae2cc3544d40d9b1892749cdd25892bbc6ac951"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71783b0b6455ac8f34b5ec99d83e686892c50498d5d00b8e56d47f41b38fbe04"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f628dbf3c91e12f4d6c8b3f092069567d8eb17814aebba3d7d60c149391aee3a"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04691bc6601ef47c88f0255043df6f570ada1a9ebef99c34bd0b72866c217ae"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee912f7e78287516df155f69da575a0ba33b02dd7c1d6614dbc9463f43066e3"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9c19b26acdd08dd239e0d3669a3dddafd600902e37881f13fbd8a53943079dbc"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:99c5ac4ad492b4a19fc132306cd57075c28446ec2ed970973bbf036bcda1bcc6"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f0f03211fd14a6a0aed2997d4b1c013d49fb7b50eeb9ffdf5e51f23cfe2c77fa"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:8d399dade330c53b4106160f75f55407e9ae7505263ea86f2ccca6bfcbdb4921"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec4fd86658c6a8964d75426517dc01cbf840bbf32d055ce64a9e63a40fd7b771"}, - {file = "aiohttp-3.8.6-cp38-cp38-win32.whl", hash = "sha256:33164093be11fcef3ce2571a0dccd9041c9a93fa3bde86569d7b03120d276c6f"}, - {file = "aiohttp-3.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:bdf70bfe5a1414ba9afb9d49f0c912dc524cf60141102f3a11143ba3d291870f"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d52d5dc7c6682b720280f9d9db41d36ebe4791622c842e258c9206232251ab2b"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ac39027011414dbd3d87f7edb31680e1f430834c8cef029f11c66dad0670aa5"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3f5c7ce535a1d2429a634310e308fb7d718905487257060e5d4598e29dc17f0b"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b30e963f9e0d52c28f284d554a9469af073030030cef8693106d918b2ca92f54"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:918810ef188f84152af6b938254911055a72e0f935b5fbc4c1a4ed0b0584aed1"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:002f23e6ea8d3dd8d149e569fd580c999232b5fbc601c48d55398fbc2e582e8c"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fcf3eabd3fd1a5e6092d1242295fa37d0354b2eb2077e6eb670accad78e40e1"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:255ba9d6d5ff1a382bb9a578cd563605aa69bec845680e21c44afc2670607a95"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d67f8baed00870aa390ea2590798766256f31dc5ed3ecc737debb6e97e2ede78"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:86f20cee0f0a317c76573b627b954c412ea766d6ada1a9fcf1b805763ae7feeb"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:39a312d0e991690ccc1a61f1e9e42daa519dcc34ad03eb6f826d94c1190190dd"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e827d48cf802de06d9c935088c2924e3c7e7533377d66b6f31ed175c1620e05e"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd111d7fc5591ddf377a408ed9067045259ff2770f37e2d94e6478d0f3fc0c17"}, - {file = "aiohttp-3.8.6-cp39-cp39-win32.whl", hash = "sha256:caf486ac1e689dda3502567eb89ffe02876546599bbf915ec94b1fa424eeffd4"}, - {file = "aiohttp-3.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:3f0e27e5b733803333bb2371249f41cf42bae8884863e8e8965ec69bebe53132"}, - {file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"}, + {file = "aiohttp-3.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:772fbe371788e61c58d6d3d904268e48a594ba866804d08c995ad71b144f94cb"}, + {file = "aiohttp-3.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:edd4f1af2253f227ae311ab3d403d0c506c9b4410c7fc8d9573dec6d9740369f"}, + {file = "aiohttp-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cfee9287778399fdef6f8a11c9e425e1cb13cc9920fd3a3df8f122500978292b"}, + {file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc158466f6a980a6095ee55174d1de5730ad7dec251be655d9a6a9dd7ea1ff9"}, + {file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54ec82f45d57c9a65a1ead3953b51c704f9587440e6682f689da97f3e8defa35"}, + {file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abeb813a18eb387f0d835ef51f88568540ad0325807a77a6e501fed4610f864e"}, + {file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc91d07280d7d169f3a0f9179d8babd0ee05c79d4d891447629ff0d7d8089ec2"}, + {file = "aiohttp-3.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b65e861f4bebfb660f7f0f40fa3eb9f2ab9af10647d05dac824390e7af8f75b7"}, + {file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:04fd8ffd2be73d42bcf55fd78cde7958eeee6d4d8f73c3846b7cba491ecdb570"}, + {file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3d8d962b439a859b3ded9a1e111a4615357b01620a546bc601f25b0211f2da81"}, + {file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:8ceb658afd12b27552597cf9a65d9807d58aef45adbb58616cdd5ad4c258c39e"}, + {file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0e4ee4df741670560b1bc393672035418bf9063718fee05e1796bf867e995fad"}, + {file = "aiohttp-3.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2dec87a556f300d3211decf018bfd263424f0690fcca00de94a837949fbcea02"}, + {file = "aiohttp-3.9.2-cp310-cp310-win32.whl", hash = "sha256:3e1a800f988ce7c4917f34096f81585a73dbf65b5c39618b37926b1238cf9bc4"}, + {file = "aiohttp-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:ea510718a41b95c236c992b89fdfc3d04cc7ca60281f93aaada497c2b4e05c46"}, + {file = "aiohttp-3.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6aaa6f99256dd1b5756a50891a20f0d252bd7bdb0854c5d440edab4495c9f973"}, + {file = "aiohttp-3.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a27d8c70ad87bcfce2e97488652075a9bdd5b70093f50b10ae051dfe5e6baf37"}, + {file = "aiohttp-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:54287bcb74d21715ac8382e9de146d9442b5f133d9babb7e5d9e453faadd005e"}, + {file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb3d05569aa83011fcb346b5266e00b04180105fcacc63743fc2e4a1862a891"}, + {file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8534e7d69bb8e8d134fe2be9890d1b863518582f30c9874ed7ed12e48abe3c4"}, + {file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bd9d5b989d57b41e4ff56ab250c5ddf259f32db17159cce630fd543376bd96b"}, + {file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa6904088e6642609981f919ba775838ebf7df7fe64998b1a954fb411ffb4663"}, + {file = "aiohttp-3.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda42eb410be91b349fb4ee3a23a30ee301c391e503996a638d05659d76ea4c2"}, + {file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:193cc1ccd69d819562cc7f345c815a6fc51d223b2ef22f23c1a0f67a88de9a72"}, + {file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b9f1cb839b621f84a5b006848e336cf1496688059d2408e617af33e3470ba204"}, + {file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:d22a0931848b8c7a023c695fa2057c6aaac19085f257d48baa24455e67df97ec"}, + {file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4112d8ba61fbd0abd5d43a9cb312214565b446d926e282a6d7da3f5a5aa71d36"}, + {file = "aiohttp-3.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c4ad4241b52bb2eb7a4d2bde060d31c2b255b8c6597dd8deac2f039168d14fd7"}, + {file = "aiohttp-3.9.2-cp311-cp311-win32.whl", hash = "sha256:ee2661a3f5b529f4fc8a8ffee9f736ae054adfb353a0d2f78218be90617194b3"}, + {file = "aiohttp-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:4deae2c165a5db1ed97df2868ef31ca3cc999988812e82386d22937d9d6fed52"}, + {file = "aiohttp-3.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:6f4cdba12539215aaecf3c310ce9d067b0081a0795dd8a8805fdb67a65c0572a"}, + {file = "aiohttp-3.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:84e843b33d5460a5c501c05539809ff3aee07436296ff9fbc4d327e32aa3a326"}, + {file = "aiohttp-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8008d0f451d66140a5aa1c17e3eedc9d56e14207568cd42072c9d6b92bf19b52"}, + {file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61c47ab8ef629793c086378b1df93d18438612d3ed60dca76c3422f4fbafa792"}, + {file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc71f748e12284312f140eaa6599a520389273174b42c345d13c7e07792f4f57"}, + {file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a1c3a4d0ab2f75f22ec80bca62385db2e8810ee12efa8c9e92efea45c1849133"}, + {file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a87aa0b13bbee025faa59fa58861303c2b064b9855d4c0e45ec70182bbeba1b"}, + {file = "aiohttp-3.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2cc0d04688b9f4a7854c56c18aa7af9e5b0a87a28f934e2e596ba7e14783192"}, + {file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1956e3ac376b1711c1533266dec4efd485f821d84c13ce1217d53e42c9e65f08"}, + {file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:114da29f39eccd71b93a0fcacff178749a5c3559009b4a4498c2c173a6d74dff"}, + {file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3f17999ae3927d8a9a823a1283b201344a0627272f92d4f3e3a4efe276972fe8"}, + {file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:f31df6a32217a34ae2f813b152a6f348154f948c83213b690e59d9e84020925c"}, + {file = "aiohttp-3.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7a75307ffe31329928a8d47eae0692192327c599113d41b278d4c12b54e1bd11"}, + {file = "aiohttp-3.9.2-cp312-cp312-win32.whl", hash = "sha256:972b63d589ff8f305463593050a31b5ce91638918da38139b9d8deaba9e0fed7"}, + {file = "aiohttp-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:200dc0246f0cb5405c80d18ac905c8350179c063ea1587580e3335bfc243ba6a"}, + {file = "aiohttp-3.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:158564d0d1020e0d3fe919a81d97aadad35171e13e7b425b244ad4337fc6793a"}, + {file = "aiohttp-3.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:da1346cd0ccb395f0ed16b113ebb626fa43b7b07fd7344fce33e7a4f04a8897a"}, + {file = "aiohttp-3.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:eaa9256de26ea0334ffa25f1913ae15a51e35c529a1ed9af8e6286dd44312554"}, + {file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1543e7fb00214fb4ccead42e6a7d86f3bb7c34751ec7c605cca7388e525fd0b4"}, + {file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:186e94570433a004e05f31f632726ae0f2c9dee4762a9ce915769ce9c0a23d89"}, + {file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d52d20832ac1560f4510d68e7ba8befbc801a2b77df12bd0cd2bcf3b049e52a4"}, + {file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c45e4e815ac6af3b72ca2bde9b608d2571737bb1e2d42299fc1ffdf60f6f9a1"}, + {file = "aiohttp-3.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa906b9bdfd4a7972dd0628dbbd6413d2062df5b431194486a78f0d2ae87bd55"}, + {file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:68bbee9e17d66f17bb0010aa15a22c6eb28583edcc8b3212e2b8e3f77f3ebe2a"}, + {file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4c189b64bd6d9a403a1a3f86a3ab3acbc3dc41a68f73a268a4f683f89a4dec1f"}, + {file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:8a7876f794523123bca6d44bfecd89c9fec9ec897a25f3dd202ee7fc5c6525b7"}, + {file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:d23fba734e3dd7b1d679b9473129cd52e4ec0e65a4512b488981a56420e708db"}, + {file = "aiohttp-3.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b141753be581fab842a25cb319f79536d19c2a51995d7d8b29ee290169868eab"}, + {file = "aiohttp-3.9.2-cp38-cp38-win32.whl", hash = "sha256:103daf41ff3b53ba6fa09ad410793e2e76c9d0269151812e5aba4b9dd674a7e8"}, + {file = "aiohttp-3.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:328918a6c2835861ff7afa8c6d2c70c35fdaf996205d5932351bdd952f33fa2f"}, + {file = "aiohttp-3.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5264d7327c9464786f74e4ec9342afbbb6ee70dfbb2ec9e3dfce7a54c8043aa3"}, + {file = "aiohttp-3.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07205ae0015e05c78b3288c1517afa000823a678a41594b3fdc870878d645305"}, + {file = "aiohttp-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae0a1e638cffc3ec4d4784b8b4fd1cf28968febc4bd2718ffa25b99b96a741bd"}, + {file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d43302a30ba1166325974858e6ef31727a23bdd12db40e725bec0f759abce505"}, + {file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16a967685907003765855999af11a79b24e70b34dc710f77a38d21cd9fc4f5fe"}, + {file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fa3ee92cd441d5c2d07ca88d7a9cef50f7ec975f0117cd0c62018022a184308"}, + {file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b500c5ad9c07639d48615a770f49618130e61be36608fc9bc2d9bae31732b8f"}, + {file = "aiohttp-3.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c07327b368745b1ce2393ae9e1aafed7073d9199e1dcba14e035cc646c7941bf"}, + {file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cc7d6502c23a0ec109687bf31909b3fb7b196faf198f8cff68c81b49eb316ea9"}, + {file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:07be2be7071723c3509ab5c08108d3a74f2181d4964e869f2504aaab68f8d3e8"}, + {file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:122468f6fee5fcbe67cb07014a08c195b3d4c41ff71e7b5160a7bcc41d585a5f"}, + {file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:00a9abcea793c81e7f8778ca195a1714a64f6d7436c4c0bb168ad2a212627000"}, + {file = "aiohttp-3.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7a9825fdd64ecac5c670234d80bb52bdcaa4139d1f839165f548208b3779c6c6"}, + {file = "aiohttp-3.9.2-cp39-cp39-win32.whl", hash = "sha256:5422cd9a4a00f24c7244e1b15aa9b87935c85fb6a00c8ac9b2527b38627a9211"}, + {file = "aiohttp-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:7d579dcd5d82a86a46f725458418458fa43686f6a7b252f2966d359033ffc8ab"}, + {file = "aiohttp-3.9.2.tar.gz", hash = "sha256:b0ad0a5e86ce73f5368a164c10ada10504bf91869c05ab75d982c6048217fbf7"}, ] [package.dependencies] aiosignal = ">=1.1.2" -async-timeout = ">=4.0.0a3,<5.0" attrs = ">=17.3.0" -charset-normalizer = ">=2.0,<4.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "cchardet"] +speedups = ["Brotli", "aiodns", "brotlicffi"] [[package]] name = "aiosignal" @@ -154,6 +167,37 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.4.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, + {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + [[package]] name = "apscheduler" version = "3.10.4" @@ -182,31 +226,6 @@ tornado = ["tornado (>=4.3)"] twisted = ["twisted"] zookeeper = ["kazoo"] -[[package]] -name = "asgiref" -version = "3.7.2" -description = "ASGI specs, helper code, and adapters" -optional = false -python-versions = ">=3.7" -files = [ - {file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"}, - {file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"}, -] - -[package.extras] -tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] - -[[package]] -name = "async-lru" -version = "2.0.4" -description = "Simple LRU cache for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"}, - {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, -] - [[package]] name = "async-timeout" version = "4.0.3" @@ -218,63 +237,6 @@ files = [ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] -[[package]] -name = "asyncpg" -version = "0.29.0" -description = "An asyncio PostgreSQL driver" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "asyncpg-0.29.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169"}, - {file = "asyncpg-0.29.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385"}, - {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22"}, - {file = "asyncpg-0.29.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610"}, - {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397"}, - {file = "asyncpg-0.29.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb"}, - {file = "asyncpg-0.29.0-cp310-cp310-win32.whl", hash = "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449"}, - {file = "asyncpg-0.29.0-cp310-cp310-win_amd64.whl", hash = "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772"}, - {file = "asyncpg-0.29.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4"}, - {file = "asyncpg-0.29.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac"}, - {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870"}, - {file = "asyncpg-0.29.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f"}, - {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23"}, - {file = "asyncpg-0.29.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b"}, - {file = "asyncpg-0.29.0-cp311-cp311-win32.whl", hash = "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675"}, - {file = "asyncpg-0.29.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3"}, - {file = "asyncpg-0.29.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6011b0dc29886ab424dc042bf9eeb507670a3b40aece3439944006aafe023178"}, - {file = "asyncpg-0.29.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b544ffc66b039d5ec5a7454667f855f7fec08e0dfaf5a5490dfafbb7abbd2cfb"}, - {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d84156d5fb530b06c493f9e7635aa18f518fa1d1395ef240d211cb563c4e2364"}, - {file = "asyncpg-0.29.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54858bc25b49d1114178d65a88e48ad50cb2b6f3e475caa0f0c092d5f527c106"}, - {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bde17a1861cf10d5afce80a36fca736a86769ab3579532c03e45f83ba8a09c59"}, - {file = "asyncpg-0.29.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:37a2ec1b9ff88d8773d3eb6d3784dc7e3fee7756a5317b67f923172a4748a175"}, - {file = "asyncpg-0.29.0-cp312-cp312-win32.whl", hash = "sha256:bb1292d9fad43112a85e98ecdc2e051602bce97c199920586be83254d9dafc02"}, - {file = "asyncpg-0.29.0-cp312-cp312-win_amd64.whl", hash = "sha256:2245be8ec5047a605e0b454c894e54bf2ec787ac04b1cb7e0d3c67aa1e32f0fe"}, - {file = "asyncpg-0.29.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0009a300cae37b8c525e5b449233d59cd9868fd35431abc470a3e364d2b85cb9"}, - {file = "asyncpg-0.29.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cad1324dbb33f3ca0cd2074d5114354ed3be2b94d48ddfd88af75ebda7c43cc"}, - {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012d01df61e009015944ac7543d6ee30c2dc1eb2f6b10b62a3f598beb6531548"}, - {file = "asyncpg-0.29.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000c996c53c04770798053e1730d34e30cb645ad95a63265aec82da9093d88e7"}, - {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e0bfe9c4d3429706cf70d3249089de14d6a01192d617e9093a8e941fea8ee775"}, - {file = "asyncpg-0.29.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:642a36eb41b6313ffa328e8a5c5c2b5bea6ee138546c9c3cf1bffaad8ee36dd9"}, - {file = "asyncpg-0.29.0-cp38-cp38-win32.whl", hash = "sha256:a921372bbd0aa3a5822dd0409da61b4cd50df89ae85150149f8c119f23e8c408"}, - {file = "asyncpg-0.29.0-cp38-cp38-win_amd64.whl", hash = "sha256:103aad2b92d1506700cbf51cd8bb5441e7e72e87a7b3a2ca4e32c840f051a6a3"}, - {file = "asyncpg-0.29.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da"}, - {file = "asyncpg-0.29.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3"}, - {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090"}, - {file = "asyncpg-0.29.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83"}, - {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810"}, - {file = "asyncpg-0.29.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c"}, - {file = "asyncpg-0.29.0-cp39-cp39-win32.whl", hash = "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2"}, - {file = "asyncpg-0.29.0-cp39-cp39-win_amd64.whl", hash = "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8"}, - {file = "asyncpg-0.29.0.tar.gz", hash = "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e"}, -] - -[package.dependencies] -async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.12.0\""} - -[package.extras] -docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["flake8 (>=6.1,<7.0)", "uvloop (>=0.15.3)"] - [[package]] name = "attrs" version = "23.2.0" @@ -296,17 +258,28 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "babel" -version = "2.9.1" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, - {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] -[package.dependencies] -pytz = ">=2015.7" +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "backoff" +version = "2.2.1" +description = "Function decoration for backoff and retry" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, + {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, +] [[package]] name = "better-profanity" @@ -408,13 +381,13 @@ redis = ["redis (>=2.10.5)"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -582,19 +555,19 @@ cron = ["capturer (>=2.4)"] [[package]] name = "cyclonedx-python-lib" -version = "6.4.1" +version = "7.4.1" description = "Python library for CycloneDX" optional = false -python-versions = ">=3.8,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "cyclonedx_python_lib-6.4.1-py3-none-any.whl", hash = "sha256:42d50052c4604e8d6a91753e51bca33d668fb82adc1aab3f4eb54b89fa61cbc0"}, - {file = "cyclonedx_python_lib-6.4.1.tar.gz", hash = "sha256:aca5d8cf10f8d8420ba621e0cf4a24b98708afb68ca2ca72d7f2cc6394c75681"}, + {file = "cyclonedx_python_lib-7.4.1-py3-none-any.whl", hash = "sha256:73bf8d5c09ad10698c75d3ce3f123c84c9aff3959d67b8b5ca9e5a7c5da43abe"}, + {file = "cyclonedx_python_lib-7.4.1.tar.gz", hash = "sha256:23bf8196e008bb8e06c1040ad2ab69492891d8a581cb2aefa36a77f199790a37"}, ] [package.dependencies] license-expression = ">=30,<31" packageurl-python = ">=0.11,<2" -py-serializable = ">=0.16,<2" +py-serializable = ">=1.0.3,<2" sortedcontainers = ">=2.4.0,<3.0.0" [package.extras] @@ -641,49 +614,15 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] -[[package]] -name = "django" -version = "4.2" -description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Django-4.2-py3-none-any.whl", hash = "sha256:ad33ed68db9398f5dfb33282704925bce044bef4261cd4fb59e4e7f9ae505a78"}, - {file = "Django-4.2.tar.gz", hash = "sha256:c36e2ab12824e2ac36afa8b2515a70c53c7742f0d6eaefa7311ec379558db997"}, -] - -[package.dependencies] -asgiref = ">=3.6.0,<4" -sqlparse = ">=0.3.1" -tzdata = {version = "*", markers = "sys_platform == \"win32\""} - -[package.extras] -argon2 = ["argon2-cffi (>=19.1.0)"] -bcrypt = ["bcrypt"] - -[[package]] -name = "django-jazzmin" -version = "2.6.0" -description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy" -optional = false -python-versions = ">=3.6.2" -files = [ - {file = "django_jazzmin-2.6.0-py3-none-any.whl", hash = "sha256:fb554c2d564649c65243b13385121fdbdda58521f49544f9d7cb9c414a4908d4"}, - {file = "django_jazzmin-2.6.0.tar.gz", hash = "sha256:5bb07055cf19183030724f976904fd8b6337559727959340a43832fab0531812"}, -] - -[package.dependencies] -django = ">=2.2" - [[package]] name = "environs" -version = "10.2.0" +version = "10.3.0" description = "simplified environment variable parsing" optional = false python-versions = ">=3.8" files = [ - {file = "environs-10.2.0-py3-none-any.whl", hash = "sha256:579dddb252ef4bb83a302df82a99c98f6f3db30f043d1b7acff36264b0bfdc69"}, - {file = "environs-10.2.0.tar.gz", hash = "sha256:9513dd388c1eeb8e82f1ea5a701356abfb7a3d79925bff937ade67fe096e420d"}, + {file = "environs-10.3.0-py3-none-any.whl", hash = "sha256:feeaf28f17fd0499f9cd7c0fcf408c6d82c308e69e335eb92d09322fc9ed8138"}, + {file = "environs-10.3.0.tar.gz", hash = "sha256:cc421ddb143fa30183568164755aa113a160e555cd19e97e664c478662032c24"}, ] [package.dependencies] @@ -698,45 +637,45 @@ tests = ["environs[django]", "pytest"] [[package]] name = "filelock" -version = "3.13.1" +version = "3.15.4" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, + {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" -version = "7.0.0" +version = "7.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" files = [ - {file = "flake8-7.0.0-py2.py3-none-any.whl", hash = "sha256:a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3"}, - {file = "flake8-7.0.0.tar.gz", hash = "sha256:33f96621059e65eec474169085dc92bf26e7b2d47366b70be2f67ab80dc25132"}, + {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, + {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, ] [package.dependencies] mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.11.0,<2.12.0" +pycodestyle = ">=2.12.0,<2.13.0" pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "flatbuffers" -version = "23.5.26" +version = "24.3.25" description = "The FlatBuffers serialization format for Python" optional = false python-versions = "*" files = [ - {file = "flatbuffers-23.5.26-py2.py3-none-any.whl", hash = "sha256:c0ff356da363087b915fde4b8b45bdda73432fc17cddb3c8157472eab1422ad1"}, - {file = "flatbuffers-23.5.26.tar.gz", hash = "sha256:9ea1144cac05ce5d86e2859f431c6cd5e66cd9c78c558317c7955fb8d4c78d89"}, + {file = "flatbuffers-24.3.25-py2.py3-none-any.whl", hash = "sha256:8dbdec58f935f3765e4f7f3cf635ac3a77f83568138d6a2311f524ec96364812"}, + {file = "flatbuffers-24.3.25.tar.gz", hash = "sha256:de2ec5b203f21441716617f38443e0a8ebf3d25bf0d9c0bb0ce68fa00ad546a4"}, ] [[package]] @@ -825,6 +764,17 @@ files = [ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, ] +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + [[package]] name = "html5lib" version = "1.1" @@ -846,6 +796,51 @@ chardet = ["chardet (>=2.2)"] genshi = ["genshi"] lxml = ["lxml"] +[[package]] +name = "httpcore" +version = "1.0.5" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httpx" +version = "0.27.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + [[package]] name = "humanfriendly" version = "10.0" @@ -862,13 +857,13 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve [[package]] name = "identify" -version = "2.5.33" +version = "2.5.36" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, ] [package.extras] @@ -876,13 +871,13 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -910,29 +905,15 @@ files = [ [package.extras] colors = ["colorama (>=0.4.6)"] -[[package]] -name = "jsonfield" -version = "3.1.0" -description = "A reusable Django field that allows you to store validated JSON in your model." -optional = false -python-versions = ">=3.6" -files = [ - {file = "jsonfield-3.1.0-py3-none-any.whl", hash = "sha256:df857811587f252b97bafba42e02805e70a398a7a47870bc6358a0308dd689ed"}, - {file = "jsonfield-3.1.0.tar.gz", hash = "sha256:7e4e84597de21eeaeeaaa7cc5da08c61c48a9b64d0c446b2d71255d01812887a"}, -] - -[package.dependencies] -Django = ">=2.2" - [[package]] name = "license-expression" -version = "30.2.0" +version = "30.3.0" description = "license-expression is a comprehensive utility library to parse, compare, simplify and normalize license expressions (such as SPDX license expressions) using boolean logic." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "license-expression-30.2.0.tar.gz", hash = "sha256:599928edd995c43fc335e0af342076144dc71cb858afa1ed9c1c30c4e81794f5"}, - {file = "license_expression-30.2.0-py3-none-any.whl", hash = "sha256:1a7dc2bb2d09cdc983d072e4f9adc787e107e09def84cbb3919baaaf4f8e6fa1"}, + {file = "license-expression-30.3.0.tar.gz", hash = "sha256:1295406f736b4f395ff069aec1cebfad53c0fcb3cf57df0f5ec58fc7b905aea5"}, + {file = "license_expression-30.3.0-py3-none-any.whl", hash = "sha256:ae0ba9a829d6909c785dc2f0131f13d10d68318e4a5f28af5ef152d6b52f9b41"}, ] [package.dependencies] @@ -982,22 +963,21 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "marshmallow" -version = "3.20.2" +version = "3.21.3" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, - {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, + {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, + {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -1041,67 +1021,67 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msgpack" -version = "1.0.7" +version = "1.0.8" description = "MessagePack serializer" optional = false python-versions = ">=3.8" files = [ - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"}, - {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"}, - {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"}, - {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"}, - {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"}, - {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"}, - {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"}, - {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"}, - {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"}, - {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"}, - {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"}, - {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"}, - {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"}, - {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"}, - {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"}, - {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"}, - {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"}, - {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"}, - {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"}, - {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"}, - {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"}, - {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"}, - {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"}, - {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"}, - {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"}, - {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"}, - {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"}, + {file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"}, + {file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"}, + {file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"}, + {file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"}, + {file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"}, + {file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"}, + {file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"}, + {file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"}, + {file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"}, + {file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"}, + {file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"}, + {file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"}, + {file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"}, + {file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"}, + {file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151"}, + {file = "msgpack-1.0.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db"}, + {file = "msgpack-1.0.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2"}, + {file = "msgpack-1.0.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a"}, + {file = "msgpack-1.0.8-cp38-cp38-win32.whl", hash = "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c"}, + {file = "msgpack-1.0.8-cp38-cp38-win_amd64.whl", hash = "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"}, + {file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"}, + {file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"}, + {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, + {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, + {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] [[package]] @@ -1205,38 +1185,38 @@ files = [ [[package]] name = "mypy" -version = "1.8.0" +version = "1.10.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, + {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, + {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, + {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, + {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, + {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, + {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, + {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, + {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, + {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, + {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, + {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, + {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, + {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, + {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, + {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, + {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, + {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, + {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, + {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, + {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, + {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, + {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, ] [package.dependencies] @@ -1262,18 +1242,15 @@ files = [ [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "nudenet" version = "3.0.8" @@ -1292,105 +1269,105 @@ opencv-python-headless = "*" [[package]] name = "numpy" -version = "1.26.3" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:806dd64230dbbfaca8a27faa64e2f414bf1c6622ab78cc4264f7f5f028fee3bf"}, - {file = "numpy-1.26.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02f98011ba4ab17f46f80f7f8f1c291ee7d855fcef0a5a98db80767a468c85cd"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d45b3ec2faed4baca41c76617fcdcfa4f684ff7a151ce6fc78ad3b6e85af0a6"}, - {file = "numpy-1.26.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdd2b45bf079d9ad90377048e2747a0c82351989a2165821f0c96831b4a2a54b"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:211ddd1e94817ed2d175b60b6374120244a4dd2287f4ece45d49228b4d529178"}, - {file = "numpy-1.26.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b1240f767f69d7c4c8a29adde2310b871153df9b26b5cb2b54a561ac85146485"}, - {file = "numpy-1.26.3-cp310-cp310-win32.whl", hash = "sha256:21a9484e75ad018974a2fdaa216524d64ed4212e418e0a551a2d83403b0531d3"}, - {file = "numpy-1.26.3-cp310-cp310-win_amd64.whl", hash = "sha256:9e1591f6ae98bcfac2a4bbf9221c0b92ab49762228f38287f6eeb5f3f55905ce"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b831295e5472954104ecb46cd98c08b98b49c69fdb7040483aff799a755a7374"}, - {file = "numpy-1.26.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9e87562b91f68dd8b1c39149d0323b42e0082db7ddb8e934ab4c292094d575d6"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c66d6fec467e8c0f975818c1796d25c53521124b7cfb760114be0abad53a0a2"}, - {file = "numpy-1.26.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f25e2811a9c932e43943a2615e65fc487a0b6b49218899e62e426e7f0a57eeda"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af36e0aa45e25c9f57bf684b1175e59ea05d9a7d3e8e87b7ae1a1da246f2767e"}, - {file = "numpy-1.26.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:51c7f1b344f302067b02e0f5b5d2daa9ed4a721cf49f070280ac202738ea7f00"}, - {file = "numpy-1.26.3-cp311-cp311-win32.whl", hash = "sha256:7ca4f24341df071877849eb2034948459ce3a07915c2734f1abb4018d9c49d7b"}, - {file = "numpy-1.26.3-cp311-cp311-win_amd64.whl", hash = "sha256:39763aee6dfdd4878032361b30b2b12593fb445ddb66bbac802e2113eb8a6ac4"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a7081fd19a6d573e1a05e600c82a1c421011db7935ed0d5c483e9dd96b99cf13"}, - {file = "numpy-1.26.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12c70ac274b32bc00c7f61b515126c9205323703abb99cd41836e8125ea0043e"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f784e13e598e9594750b2ef6729bcd5a47f6cfe4a12cca13def35e06d8163e3"}, - {file = "numpy-1.26.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f24750ef94d56ce6e33e4019a8a4d68cfdb1ef661a52cdaee628a56d2437419"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:77810ef29e0fb1d289d225cabb9ee6cf4d11978a00bb99f7f8ec2132a84e0166"}, - {file = "numpy-1.26.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8ed07a90f5450d99dad60d3799f9c03c6566709bd53b497eb9ccad9a55867f36"}, - {file = "numpy-1.26.3-cp312-cp312-win32.whl", hash = "sha256:f73497e8c38295aaa4741bdfa4fda1a5aedda5473074369eca10626835445511"}, - {file = "numpy-1.26.3-cp312-cp312-win_amd64.whl", hash = "sha256:da4b0c6c699a0ad73c810736303f7fbae483bcb012e38d7eb06a5e3b432c981b"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1666f634cb3c80ccbd77ec97bc17337718f56d6658acf5d3b906ca03e90ce87f"}, - {file = "numpy-1.26.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18c3319a7d39b2c6a9e3bb75aab2304ab79a811ac0168a671a62e6346c29b03f"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b7e807d6888da0db6e7e75838444d62495e2b588b99e90dd80c3459594e857b"}, - {file = "numpy-1.26.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4d362e17bcb0011738c2d83e0a65ea8ce627057b2fdda37678f4374a382a137"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b8c275f0ae90069496068c714387b4a0eba5d531aace269559ff2b43655edd58"}, - {file = "numpy-1.26.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cc0743f0302b94f397a4a65a660d4cd24267439eb16493fb3caad2e4389bccbb"}, - {file = "numpy-1.26.3-cp39-cp39-win32.whl", hash = "sha256:9bc6d1a7f8cedd519c4b7b1156d98e051b726bf160715b769106661d567b3f03"}, - {file = "numpy-1.26.3-cp39-cp39-win_amd64.whl", hash = "sha256:867e3644e208c8922a3be26fc6bbf112a035f50f0a86497f98f228c50c607bb2"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3c67423b3703f8fbd90f5adaa37f85b5794d3366948efe9a5190a5f3a83fc34e"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46f47ee566d98849323f01b349d58f2557f02167ee301e5e28809a8c0e27a2d0"}, - {file = "numpy-1.26.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a8474703bffc65ca15853d5fd4d06b18138ae90c17c8d12169968e998e448bb5"}, - {file = "numpy-1.26.3.tar.gz", hash = "sha256:697df43e2b6310ecc9d95f05d5ef20eacc09c7c4ecc9da3f235d39e71b7da1e4"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] name = "onnxruntime" -version = "1.17.0" +version = "1.18.1" description = "ONNX Runtime is a runtime accelerator for Machine Learning models" optional = false python-versions = "*" files = [ - {file = "onnxruntime-1.17.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d2b22a25a94109cc983443116da8d9805ced0256eb215c5e6bc6dcbabefeab96"}, - {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4c87d83c6f58d1af2675fc99e3dc810f2dbdb844bcefd0c1b7573632661f6fc"}, - {file = "onnxruntime-1.17.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dba55723bf9b835e358f48c98a814b41692c393eb11f51e02ece0625c756b797"}, - {file = "onnxruntime-1.17.0-cp310-cp310-win32.whl", hash = "sha256:ee48422349cc500273beea7607e33c2237909f58468ae1d6cccfc4aecd158565"}, - {file = "onnxruntime-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f34cc46553359293854e38bdae2ab1be59543aad78a6317e7746d30e311110c3"}, - {file = "onnxruntime-1.17.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:16d26badd092c8c257fa57c458bb600d96dc15282c647ccad0ed7b2732e6c03b"}, - {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f1273bebcdb47ed932d076c85eb9488bc4768fcea16d5f2747ca692fad4f9d3"}, - {file = "onnxruntime-1.17.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cb60fd3c2c1acd684752eb9680e89ae223e9801a9b0e0dc7b28adabe45a2e380"}, - {file = "onnxruntime-1.17.0-cp311-cp311-win32.whl", hash = "sha256:4b038324586bc905299e435f7c00007e6242389c856b82fe9357fdc3b1ef2bdc"}, - {file = "onnxruntime-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:93d39b3fa1ee01f034f098e1c7769a811a21365b4883f05f96c14a2b60c6028b"}, - {file = "onnxruntime-1.17.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:90c0890e36f880281c6c698d9bc3de2afbeee2f76512725ec043665c25c67d21"}, - {file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7466724e809a40e986b1637cba156ad9fc0d1952468bc00f79ef340bc0199552"}, - {file = "onnxruntime-1.17.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d47bee7557a8b99c8681b6882657a515a4199778d6d5e24e924d2aafcef55b0a"}, - {file = "onnxruntime-1.17.0-cp312-cp312-win32.whl", hash = "sha256:bb1bf1ee575c665b8bbc3813ab906e091a645a24ccc210be7932154b8260eca1"}, - {file = "onnxruntime-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:ac2f286da3494b29b4186ca193c7d4e6a2c1f770c4184c7192c5da142c3dec28"}, - {file = "onnxruntime-1.17.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1ec485643b93e0a3896c655eb2426decd63e18a278bb7ccebc133b340723624f"}, - {file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83c35809cda898c5a11911c69ceac8a2ac3925911854c526f73bad884582f911"}, - {file = "onnxruntime-1.17.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fa464aa4d81df818375239e481887b656e261377d5b6b9a4692466f5f3261edc"}, - {file = "onnxruntime-1.17.0-cp38-cp38-win32.whl", hash = "sha256:b7b337cd0586f7836601623cbd30a443df9528ef23965860d11c753ceeb009f2"}, - {file = "onnxruntime-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:fbb9faaf51d01aa2c147ef52524d9326744c852116d8005b9041809a71838878"}, - {file = "onnxruntime-1.17.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:5a06ab84eaa350bf64b1d747b33ccf10da64221ed1f38f7287f15eccbec81603"}, - {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d3d11db2c8242766212a68d0b139745157da7ce53bd96ba349a5c65e5a02357"}, - {file = "onnxruntime-1.17.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5632077c3ab8b0cd4f74b0af9c4e924be012b1a7bcd7daa845763c6c6bf14b7d"}, - {file = "onnxruntime-1.17.0-cp39-cp39-win32.whl", hash = "sha256:61a12732cba869b3ad2d4e29ab6cb62c7a96f61b8c213f7fcb961ba412b70b37"}, - {file = "onnxruntime-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:461fa0fc7d9c392c352b6cccdedf44d818430f3d6eacd924bb804fdea2dcfd02"}, + {file = "onnxruntime-1.18.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:29ef7683312393d4ba04252f1b287d964bd67d5e6048b94d2da3643986c74d80"}, + {file = "onnxruntime-1.18.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc706eb1df06ddf55776e15a30519fb15dda7697f987a2bbda4962845e3cec05"}, + {file = "onnxruntime-1.18.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7de69f5ced2a263531923fa68bbec52a56e793b802fcd81a03487b5e292bc3a"}, + {file = "onnxruntime-1.18.1-cp310-cp310-win32.whl", hash = "sha256:221e5b16173926e6c7de2cd437764492aa12b6811f45abd37024e7cf2ae5d7e3"}, + {file = "onnxruntime-1.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:75211b619275199c861ee94d317243b8a0fcde6032e5a80e1aa9ded8ab4c6060"}, + {file = "onnxruntime-1.18.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:f26582882f2dc581b809cfa41a125ba71ad9e715738ec6402418df356969774a"}, + {file = "onnxruntime-1.18.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef36f3a8b768506d02be349ac303fd95d92813ba3ba70304d40c3cd5c25d6a4c"}, + {file = "onnxruntime-1.18.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:170e711393e0618efa8ed27b59b9de0ee2383bd2a1f93622a97006a5ad48e434"}, + {file = "onnxruntime-1.18.1-cp311-cp311-win32.whl", hash = "sha256:9b6a33419b6949ea34e0dc009bc4470e550155b6da644571ecace4b198b0d88f"}, + {file = "onnxruntime-1.18.1-cp311-cp311-win_amd64.whl", hash = "sha256:5c1380a9f1b7788da742c759b6a02ba771fe1ce620519b2b07309decbd1a2fe1"}, + {file = "onnxruntime-1.18.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:31bd57a55e3f983b598675dfc7e5d6f0877b70ec9864b3cc3c3e1923d0a01919"}, + {file = "onnxruntime-1.18.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9e03c4ba9f734500691a4d7d5b381cd71ee2f3ce80a1154ac8f7aed99d1ecaa"}, + {file = "onnxruntime-1.18.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:781aa9873640f5df24524f96f6070b8c550c66cb6af35710fd9f92a20b4bfbf6"}, + {file = "onnxruntime-1.18.1-cp312-cp312-win32.whl", hash = "sha256:3a2d9ab6254ca62adbb448222e630dc6883210f718065063518c8f93a32432be"}, + {file = "onnxruntime-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:ad93c560b1c38c27c0275ffd15cd7f45b3ad3fc96653c09ce2931179982ff204"}, + {file = "onnxruntime-1.18.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:3b55dc9d3c67626388958a3eb7ad87eb7c70f75cb0f7ff4908d27b8b42f2475c"}, + {file = "onnxruntime-1.18.1-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f80dbcfb6763cc0177a31168b29b4bd7662545b99a19e211de8c734b657e0669"}, + {file = "onnxruntime-1.18.1-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f1ff2c61a16d6c8631796c54139bafea41ee7736077a0fc64ee8ae59432f5c58"}, + {file = "onnxruntime-1.18.1-cp38-cp38-win32.whl", hash = "sha256:219855bd272fe0c667b850bf1a1a5a02499269a70d59c48e6f27f9c8bcb25d02"}, + {file = "onnxruntime-1.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:afdf16aa607eb9a2c60d5ca2d5abf9f448e90c345b6b94c3ed14f4fb7e6a2d07"}, + {file = "onnxruntime-1.18.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:128df253ade673e60cea0955ec9d0e89617443a6d9ce47c2d79eb3f72a3be3de"}, + {file = "onnxruntime-1.18.1-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9839491e77e5c5a175cab3621e184d5a88925ee297ff4c311b68897197f4cde9"}, + {file = "onnxruntime-1.18.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad3187c1faff3ac15f7f0e7373ef4788c582cafa655a80fdbb33eaec88976c66"}, + {file = "onnxruntime-1.18.1-cp39-cp39-win32.whl", hash = "sha256:34657c78aa4e0b5145f9188b550ded3af626651b15017bf43d280d7e23dbf195"}, + {file = "onnxruntime-1.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:9c14fd97c3ddfa97da5feef595e2c73f14c2d0ec1d4ecbea99c8d96603c89589"}, ] [package.dependencies] coloredlogs = "*" flatbuffers = "*" -numpy = ">=1.21.6" +numpy = ">=1.21.6,<2.0" packaging = "*" protobuf = "*" sympy = "*" [[package]] name = "opencv-python-headless" -version = "4.9.0.80" +version = "4.10.0.84" description = "Wrapper package for OpenCV python bindings." optional = false python-versions = ">=3.6" files = [ - {file = "opencv-python-headless-4.9.0.80.tar.gz", hash = "sha256:71a4cd8cf7c37122901d8e81295db7fb188730e33a0e40039a4e59c1030b0958"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:2ea8a2edc4db87841991b2fbab55fc07b97ecb602e0f47d5d485bd75cee17c1a"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:e0ee54e27be493e8f7850847edae3128e18b540dac1d7b2e4001b8944e11e1c6"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ce2865e8fec431c6f97a81e9faaf23fa5be61011d0a75ccf47a3c0d65fa73d"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:976656362d68d9f40a5c66f83901430538002465f7db59142784f3893918f3df"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-win32.whl", hash = "sha256:11e3849d83e6651d4e7699aadda9ec7ed7c38957cbbcb99db074f2a2d2de9670"}, - {file = "opencv_python_headless-4.9.0.80-cp37-abi3-win_amd64.whl", hash = "sha256:a8056c2cb37cd65dfcdf4153ca16f7362afcf3a50d600d6bb69c660fc61ee29c"}, + {file = "opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a4f4bcb07d8f8a7704d9c8564c224c8b064c63f430e95b61ac0bffaa374d330e"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:5ae454ebac0eb0a0b932e3406370aaf4212e6a3fdb5038cc86c7aea15a6851da"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46071015ff9ab40fccd8a163da0ee14ce9846349f06c6c8c0f2870856ffa45db"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:377d08a7e48a1405b5e84afcbe4798464ce7ee17081c1c23619c8b398ff18295"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-win32.whl", hash = "sha256:9092404b65458ed87ce932f613ffbb1106ed2c843577501e5768912360fc50ec"}, + {file = "opencv_python_headless-4.10.0.84-cp37-abi3-win_amd64.whl", hash = "sha256:afcf28bd1209dd58810d33defb622b325d3cbe49dcd7a43a902982c33e5fad05"}, ] [package.dependencies] @@ -1401,13 +1378,13 @@ numpy = [ [[package]] name = "packageurl-python" -version = "0.13.4" +version = "0.15.1" description = "A purl aka. Package URL parser and builder" optional = false python-versions = ">=3.7" files = [ - {file = "packageurl-python-0.13.4.tar.gz", hash = "sha256:6eb5e995009cc73387095e0b507ab65df51357d25ddc5fce3d3545ad6dcbbee8"}, - {file = "packageurl_python-0.13.4-py3-none-any.whl", hash = "sha256:62aa13d60a0082ff115784fefdfe73a12f310e455365cca7c6d362161067f35f"}, + {file = "packageurl_python-0.15.1-py3-none-any.whl", hash = "sha256:f7a44ddb9caaf6197b3b62b890ed0be5cb15e962accab2a51db36846d5174562"}, + {file = "packageurl_python-0.15.1.tar.gz", hash = "sha256:9a37b9a7cad9a2872b4612151ba3749fd9dec90485577c14d374b6e66b7edf03"}, ] [package.extras] @@ -1418,13 +1395,13 @@ test = ["pytest"] [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -1438,37 +1415,26 @@ files = [ {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] -[[package]] -name = "pbr" -version = "6.0.0" -description = "Python Build Reasonableness" -optional = false -python-versions = ">=2.6" -files = [ - {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, - {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, -] - [[package]] name = "pip" -version = "23.3.2" +version = "24.1.1" description = "The PyPA recommended tool for installing Python packages." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pip-23.3.2-py3-none-any.whl", hash = "sha256:5052d7889c1f9d05224cd41741acb7c5d6fa735ab34e339624a614eaaa7e7d76"}, - {file = "pip-23.3.2.tar.gz", hash = "sha256:7fd9972f96db22c8077a1ee2691b172c8089b17a5652a44494a9ecb0d78f9149"}, + {file = "pip-24.1.1-py3-none-any.whl", hash = "sha256:efca15145a95e95c00608afeab66311d40bfb73bb2266a855befd705e6bb15a0"}, + {file = "pip-24.1.1.tar.gz", hash = "sha256:5aa64f65e1952733ee0a9a9b1f52496ebdb3f3077cc46f80a16d983b58d1180a"}, ] [[package]] name = "pip-api" -version = "0.0.30" +version = "0.0.33" description = "An unofficial, importable pip API" optional = false python-versions = ">=3.7" files = [ - {file = "pip-api-0.0.30.tar.gz", hash = "sha256:a05df2c7aa9b7157374bcf4273544201a0c7bae60a9c65bcf84f3959ef3896f3"}, - {file = "pip_api-0.0.30-py3-none-any.whl", hash = "sha256:2a0314bd31522eb9ffe8a99668b0d07fee34ebc537931e7b6483001dbedcbdc9"}, + {file = "pip-api-0.0.33.tar.gz", hash = "sha256:1c2522ae21efcb034d89cc99f6cf1025293b31c63c29ee98b23f03a85f36bdae"}, + {file = "pip_api-0.0.33-py3-none-any.whl", hash = "sha256:b8d6eb5a87d3a9e112a20a8e9d24a6fc12d4e1c94d7595eeaf74be11ad47276c"}, ] [package.dependencies] @@ -1476,18 +1442,18 @@ pip = "*" [[package]] name = "pip-audit" -version = "2.7.0" +version = "2.7.3" description = "A tool for scanning Python environments for known vulnerabilities" optional = false python-versions = ">=3.8" files = [ - {file = "pip_audit-2.7.0-py3-none-any.whl", hash = "sha256:83e039740653eb9ef1a78b1540ed441600cd88a560588ba2c0a169180685a522"}, - {file = "pip_audit-2.7.0.tar.gz", hash = "sha256:67740c5b1d5d967a258c3dfefc46f9713a2819c48062505ddf4b29de101c2b75"}, + {file = "pip_audit-2.7.3-py3-none-any.whl", hash = "sha256:46a11faee3323f76adf7987de8171daeb660e8f57d8088cc27fb1c1e5c7747b0"}, + {file = "pip_audit-2.7.3.tar.gz", hash = "sha256:08891bbf179bffe478521f150818112bae998424f58bf9285c0078965aef38bc"}, ] [package.dependencies] CacheControl = {version = ">=0.13.0", extras = ["filecache"]} -cyclonedx-python-lib = ">=5,<7" +cyclonedx-python-lib = ">=5,<8" html5lib = ">=1.1" packaging = ">=23.0.0" pip-api = ">=0.0.28" @@ -1499,7 +1465,7 @@ toml = ">=0.10" [package.extras] dev = ["build", "bump (>=1.3.2)", "pip-audit[doc,lint,test]"] doc = ["pdoc"] -lint = ["interrogate", "mypy", "ruff (<0.1.12)", "types-html5lib", "types-requests", "types-toml"] +lint = ["interrogate", "mypy", "ruff (<0.4.3)", "setuptools", "types-html5lib", "types-requests", "types-toml"] test = ["coverage[toml] (>=7.0,!=7.3.3,<8.0)", "pretend", "pytest", "pytest-cov"] [[package]] @@ -1523,28 +1489,29 @@ testing = ["aboutcode-toolkit (>=6.0.0)", "black", "pytest (>=6,!=7.0.0)", "pyte [[package]] name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -1553,13 +1520,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.0" +version = "3.7.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, - {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, + {file = "pre_commit-3.7.1-py2.py3-none-any.whl", hash = "sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5"}, + {file = "pre_commit-3.7.1.tar.gz", hash = "sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a"}, ] [package.dependencies] @@ -1571,181 +1538,179 @@ virtualenv = ">=20.10.0" [[package]] name = "protobuf" -version = "4.25.2" +version = "5.27.2" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, - {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, - {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, - {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, - {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, - {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, - {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, - {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, - {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, - {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, + {file = "protobuf-5.27.2-cp310-abi3-win32.whl", hash = "sha256:354d84fac2b0d76062e9b3221f4abbbacdfd2a4d8af36bab0474f3a0bb30ab38"}, + {file = "protobuf-5.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:0e341109c609749d501986b835f667c6e1e24531096cff9d34ae411595e26505"}, + {file = "protobuf-5.27.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a109916aaac42bff84702fb5187f3edadbc7c97fc2c99c5ff81dd15dcce0d1e5"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:176c12b1f1c880bf7a76d9f7c75822b6a2bc3db2d28baa4d300e8ce4cde7409b"}, + {file = "protobuf-5.27.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:b848dbe1d57ed7c191dfc4ea64b8b004a3f9ece4bf4d0d80a367b76df20bf36e"}, + {file = "protobuf-5.27.2-cp38-cp38-win32.whl", hash = "sha256:4fadd8d83e1992eed0248bc50a4a6361dc31bcccc84388c54c86e530b7f58863"}, + {file = "protobuf-5.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:610e700f02469c4a997e58e328cac6f305f649826853813177e6290416e846c6"}, + {file = "protobuf-5.27.2-cp39-cp39-win32.whl", hash = "sha256:9e8f199bf7f97bd7ecebffcae45ebf9527603549b2b562df0fbc6d4d688f14ca"}, + {file = "protobuf-5.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:7fc3add9e6003e026da5fc9e59b131b8f22b428b991ccd53e2af8071687b4fce"}, + {file = "protobuf-5.27.2-py3-none-any.whl", hash = "sha256:54330f07e4949d09614707c48b06d1a22f8ffb5763c159efd5c0928326a91470"}, + {file = "protobuf-5.27.2.tar.gz", hash = "sha256:f3ecdef226b9af856075f28227ff2c90ce3a594d092c39bee5513573f25e2714"}, ] [[package]] -name = "psycopg2-binary" -version = "2.9.9" -description = "psycopg2 - Python-PostgreSQL Database Adapter" +name = "py-serializable" +version = "1.0.3" +description = "Library for serializing and deserializing Python Objects to and from JSON and XML." optional = false -python-versions = ">=3.7" +python-versions = "<4.0,>=3.8" files = [ - {file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"}, - {file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"}, - {file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"}, - {file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"}, - {file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"}, - {file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"}, - {file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"}, + {file = "py_serializable-1.0.3-py3-none-any.whl", hash = "sha256:afba815f465b9fe7ab1c1a56d1aa8880c8a9e67a6e28b7ed62d4696fa369caf8"}, + {file = "py_serializable-1.0.3.tar.gz", hash = "sha256:da3cb4b1f3cc5cc5ebecdd3dadbabd5f65d764357366fa64ee9cbaf0d4b70dcf"}, ] +[package.dependencies] +defusedxml = ">=0.7.1,<0.8.0" + [[package]] -name = "py-serializable" -version = "1.0.0" -description = "Library for serializing and deserializing Python Objects to and from JSON and XML." +name = "pyaes" +version = "1.6.1" +description = "Pure-Python Implementation of the AES block-cipher and common modes of operation" optional = false -python-versions = ">=3.8,<4.0" +python-versions = "*" files = [ - {file = "py_serializable-1.0.0-py3-none-any.whl", hash = "sha256:845a9399a16550e8703c3fb0da4fbb746a4e5f6cc4c95647c315c71fd6567cd5"}, - {file = "py_serializable-1.0.0.tar.gz", hash = "sha256:524df68c46315d7272959ae5296244e5a1e1e28330472ec214394162c39f545e"}, + {file = "pyaes-1.6.1.tar.gz", hash = "sha256:02c1b1405c38d3c370b085fb952dd8bea3fadcee6411ad99f312cc129c536d8f"}, ] -[package.dependencies] -defusedxml = ">=0.7.1,<0.8.0" +[[package]] +name = "pyasn1" +version = "0.6.0" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"}, + {file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"}, +] [[package]] name = "pycodestyle" -version = "2.11.1" +version = "2.12.0" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, - {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, + {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, + {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, ] [[package]] name = "pydantic" -version = "1.10.13" -description = "Data validation and settings management using python type hints" +version = "2.7.4" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, + {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.18.4" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.18.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, + {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, + {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, + {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, + {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, + {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, + {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, + {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, + {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, + {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, + {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, + {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, + {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, + {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyflakes" @@ -1760,28 +1725,27 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -1820,17 +1784,17 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.3" +version = "0.23.7" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.3.tar.gz", hash = "sha256:af313ce900a62fbe2b1aed18e37ad757f1ef9940c6b6a88e2954de38d6b1fb9f"}, - {file = "pytest_asyncio-0.23.3-py3-none-any.whl", hash = "sha256:37a9d912e8338ee7b4a3e917381d1c95bfc8682048cb0fbc35baba316ec1faba"}, + {file = "pytest_asyncio-0.23.7-py3-none-any.whl", hash = "sha256:009b48127fbe44518a547bddd25611551b0e43ccdbf1e67d12479f569832c20b"}, + {file = "pytest_asyncio-0.23.7.tar.gz", hash = "sha256:5f5c72948f4c49e7db4f29f2521d4031f1c27f86e57b046126654083d4770268"}, ] [package.dependencies] -pytest = ">=7.0.0" +pytest = ">=7.0.0,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -1886,7 +1850,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1921,19 +1884,34 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "que_sdk" +version = "0.2.3" +description = "" +optional = false +python-versions = "<4.0,>=3.11" +files = [ + {file = "que_sdk-0.2.3-py3-none-any.whl", hash = "sha256:867f6db3b5d397ef701536f4b3877f2886b2530a0793df977c36755799f30cfb"}, + {file = "que_sdk-0.2.3.tar.gz", hash = "sha256:afe1564d0766afc47df4233500069289f41149e83dc6303722bfd8ce72b35a09"}, +] + +[package.dependencies] +backoff = ">=2.2.1,<3.0.0" +httpx = ">=0.27.0,<0.28.0" + [[package]] name = "redis" -version = "5.0.1" +version = "5.0.7" description = "Python client for Redis database and key-value store" optional = false python-versions = ">=3.7" files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, + {file = "redis-5.0.7-py3-none-any.whl", hash = "sha256:0e479e24da960c690be5d9b96d21f7b918a98c0cf49af3b6fafaa0753f93a0db"}, + {file = "redis-5.0.7.tar.gz", hash = "sha256:8f611490b93c8109b50adc317b31bfd84fff31def3475b92e7e80bf39f48175b"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} [package.extras] hiredis = ["hiredis (>=1.0.0)"] @@ -1941,13 +1919,13 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1962,13 +1940,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.7.0" +version = "13.7.1" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, - {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, + {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, + {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, ] [package.dependencies] @@ -1978,6 +1956,20 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "rsa" +version = "4.9" +description = "Pure-Python RSA implementation" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + [[package]] name = "ruff" version = "0.1.15" @@ -2004,22 +1996,6 @@ files = [ {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] -[[package]] -name = "setuptools" -version = "69.0.3" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -2031,6 +2007,17 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + [[package]] name = "sortedcontainers" version = "2.4.0" @@ -2042,52 +2029,36 @@ files = [ {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, ] -[[package]] -name = "sqlparse" -version = "0.4.4" -description = "A non-validating SQL parser." -optional = false -python-versions = ">=3.5" -files = [ - {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, - {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, -] - -[package.extras] -dev = ["build", "flake8"] -doc = ["sphinx"] -test = ["pytest", "pytest-cov"] - [[package]] name = "sympy" -version = "1.12" +version = "1.12.1" description = "Computer algebra system (CAS) in Python" optional = false python-versions = ">=3.8" files = [ - {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"}, - {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"}, + {file = "sympy-1.12.1-py3-none-any.whl", hash = "sha256:9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515"}, + {file = "sympy-1.12.1.tar.gz", hash = "sha256:2877b03f998cd8c08f07cd0de5b767119cd3ef40d09f41c30d722f6686b0fb88"}, ] [package.dependencies] -mpmath = ">=0.19" +mpmath = ">=1.1.0,<1.4.0" [[package]] -name = "testresources" -version = "2.0.1" -description = "Testresources, a pyunit extension for managing expensive test resources" +name = "telethon" +version = "1.36.0" +description = "Full-featured Telegram client library for Python 3" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "testresources-2.0.1-py2.py3-none-any.whl", hash = "sha256:67a361c3a2412231963b91ab04192209aa91a1aa052f0ab87245dbea889d1282"}, - {file = "testresources-2.0.1.tar.gz", hash = "sha256:ee9d1982154a1e212d4e4bac6b610800bfb558e4fb853572a827bc14a96e4417"}, + {file = "Telethon-1.36.0.tar.gz", hash = "sha256:11db5c7ed7e37f1272d443fb7eea0f1db580d56c6949165233946fb323aaf3a7"}, ] [package.dependencies] -pbr = ">=1.8" +pyaes = "*" +rsa = "*" [package.extras] -test = ["docutils", "fixtures", "testtools"] +cryptg = ["cryptg"] [[package]] name = "toml" @@ -2102,24 +2073,24 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "tzdata" -version = "2023.4" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] @@ -2141,13 +2112,13 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3) [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] @@ -2156,25 +2127,15 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] -[[package]] -name = "uuid" -version = "1.30" -description = "UUID object and generation functions (Python 2.3 or higher)" -optional = false -python-versions = "*" -files = [ - {file = "uuid-1.30.tar.gz", hash = "sha256:1f87cc004ac5120466f36c5beae48b4c48cc411968eed0eaecd3da82aa96193f"}, -] - [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.26.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, + {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, ] [package.dependencies] @@ -2183,7 +2144,7 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] @@ -2197,6 +2158,20 @@ files = [ {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, ] +[[package]] +name = "yandex-geo" +version = "2.1.2" +description = "Simple library for getting address or coordinates via Yandex geocoder" +optional = false +python-versions = "<4.0,>=3.11" +files = [ + {file = "yandex_geo-2.1.2-py3-none-any.whl", hash = "sha256:f3e35f67ae3dee1a3c75bf96da2ee7478b77d4329479920b680950b28e123463"}, + {file = "yandex_geo-2.1.2.tar.gz", hash = "sha256:3654fd9678b44416629dec06c54a17603a62341eaff2cb454eeb9906af871e8e"}, +] + +[package.dependencies] +httpx = ">=0.27.0,<0.28.0" + [[package]] name = "yarl" version = "1.9.4" @@ -2303,4 +2278,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "7b8ccf81efa5f306de213446f2c3290ae238eb0b3571e6e749f9701865d6aefc" +content-hash = "4157b8b428eb4606de62c62e6888611475ece1fceee9e65979a7cb13d0fb2dc5" diff --git a/pyproject.toml b/pyproject.toml index 29c82e9..e1d0845 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,53 +1,48 @@ [tool.poetry] name = "datingbot" version = "0.1.0" -description = "A Telegram Bot with open source code, which implemented django and a dating system" +description = "A Dating Telegram Bot with open source code" authors = ["David Dzhalaev <72649244+DavidRomanovizc@users.noreply.github.com>"] license = "Attribution-NonCommercial 3.0 Unported" readme = "README.md" [tool.poetry.dependencies] python = "^3.11" -aiogram = "2.25.1" -environs = "10.2.0" -asyncpg = "0.29.0" -Django = "4.2" -psycopg2-binary = "2.9.9" -jsonfield = ">=3.1.0,<3.2.0" -asgiref = "3.7.2" -uuid = ">=1.30,<2.0" -pip = "23.3.2" -setuptools = "69.0.3" -django-jazzmin = ">=2.6.0,<2.7.0" +aiogram = "^3.4.1" +environs = "^10.2.0" better-profanity = ">=0.7.0,<0.8.0" -pytest = "7.4.4" -aiohttp = "<3.9.0" -async-lru = "2.0.4" -pytest-asyncio = "0.23.3" -apscheduler = "3.10.4" -nudenet = "3.0.8" -yarl = "1.9.4" -aiofiles = "23.2.1" -pre-commit = "3.6.0" -testresources = "^2.0.1" -pydantic = "1.10.13" -redis = "5.0.1" +aiohttp = "<3.9.3" +apscheduler = "^3.10.4" +nudenet = "^3.0.8" +pydantic = "^2.4.1" +redis = "^5.0.1" betterlogging = ">=0.2.1,<0.3.0" -flake8 = "7.0.0" -black = "23.12.1" +que-sdk = "^0.2.3" +babel = "^2.15.0" +yandex-geo = "^2.1.1" +aiogram-calendar = "^0.5.0" +numpy = "1.26.4" + +[tool.poetry.group.dev.dependencies] +telethon = "^1.35.0" +pytest-asyncio = "^0.23.6" +anyio = "^4.3.0" +flake8 = "^7.0.0" +black = "^23.12.1" mypy = "^1.8.0" isort = "^5.13.2" deptry = "^0.12.0" ruff = "^0.1.14" pip-audit = "^2.7.0" +pre-commit = "^3.6.0" +pytest = "^7.4.4" [tool.black] line-length = 99 exclude = [ "venv", - "django_project/telegrambot/common/migrations", - "django_project/telegrambot/usersmanage/migrations", - ".git" + ".git", + "deprecate/" ] target-version = ['py311'] @@ -64,6 +59,7 @@ disallow_untyped_calls = true warn_redundant_casts = true warn_unused_configs = true strict_equality = true +exclude = ["deprecated"] [tool.isort] profile = "black" @@ -77,7 +73,7 @@ include_trailing_comma = true line_length = 99 use_parentheses = true known_third_party = ['django', 'rest_framework_extensions', 'aiogram'] -known_first_party = ["common", "usersmanage",] +known_first_party = ["common", "usersmanage", ] skip = ["__init__.py", "app.py"] [tool.ruff] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 9872150..0000000 --- a/requirements.txt +++ /dev/null @@ -1,27 +0,0 @@ -aiogram==2.25.1 -environs==10.2.0 -asyncpg==0.29.0 -Django==4.2 -psycopg2-binary==2.9.9 -jsonfield~=3.1.0 -asgiref==3.7.2 -uuid~=1.30 -pip==23.3.2 -setuptools==69.0.3 -django-jazzmin~=2.6.0 -better_profanity~=0.7.0 -pytest==7.4.4 -aiohttp<3.9.0 -async-lru==2.0.4 -pytest-asyncio==0.23.3 -APScheduler==3.10.4 -NudeNet==3.0.8 -yarl==1.9.4 -aiofiles==23.2.1 -pre-commit==3.6.0 -testresources -pydantic==1.10.13 -redis==5.0.1 -betterlogging~=0.2.1 -flake8==7.0.0 -black==23.12.1 \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..8c7f012 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,7 @@ +from . import ( + tgbot, +) + +__all__ = ( + "tgbot", +) diff --git a/django_project/telegrambot/usersmanage/migrations/__init__.py b/src/tgbot/__init__.py similarity index 100% rename from django_project/telegrambot/usersmanage/migrations/__init__.py rename to src/tgbot/__init__.py diff --git a/src/tgbot/config.py b/src/tgbot/config.py new file mode 100644 index 0000000..6eda80a --- /dev/null +++ b/src/tgbot/config.py @@ -0,0 +1,166 @@ +from dataclasses import ( + dataclass, +) +from functools import ( + lru_cache, +) +import inspect +from pathlib import ( + Path, +) + +from environs import ( + Env, +) + + +@dataclass +class RedisConfig: + """ + Redis configuration class. + + Attributes + ---------- + password : Optional(str) + The password used to authenticate with Redis. + port : Optional(int) + The port where Redis server is listening. + host : Optional(str) + The host where Redis server is located. + """ + + password: str | None + port: int | None + host: str | None + + def dsn(self) -> str: + """ + Constructs and returns a Redis DSN (Data Source Name) for this database configuration. + """ + if self.password: + return f"redis://:{self.password}@{self.host}:{self.port}/0" + else: + return f"redis://{self.host}:{self.port}/0" + + @staticmethod + def from_env(env: Env) -> "RedisConfig": + """ + Creates the RedisConfig object from environment variables. + """ + password = env.str("REDIS_PASSWORD", None) + port = env.int("REDIS_PORT") + host = env.str("REDIS_HOST") + + return RedisConfig(password=password, port=port, host=host) + + +@dataclass(frozen=True, slots=True) +class TgBot: + token: str + admin_ids: list[int] + support_ids: list[int] + timezone: str + ip: str + moderate_chat: int + use_redis: bool + _BASE_DIR = Path(__file__).parent.parent.parent + LOCALES_DIR = _BASE_DIR / "locales" + + @staticmethod + def from_env(env: Env) -> "TgBot": + """ + Creates the TgBot object from environment variables. + """ + token = env.str("BOT_TOKEN") + admin_ids = list(map(int, env.list("ADMINS"))) + support_ids = list(map(int, env.list("SUPPORTS"))) + ip = env.str("IP") + timezone = env.str("TIMEZONE") + moderate_chat = env.int("MODERATE_CHAT") + use_redis = env.bool("USE_REDIS") + return TgBot( + token=token, + admin_ids=admin_ids, + support_ids=support_ids, + ip=ip, timezone=timezone, + moderate_chat=moderate_chat, + use_redis=use_redis, + ) + + +@dataclass(frozen=True, slots=True) +class Miscellaneous: + secret_key: str + api_id: int | None + api_hash: str | None + session_str: str | None + yandex_map_api_key: str + + @staticmethod + def from_env(env: Env) -> "Miscellaneous": + """ + Creates the Miscellaneous object from environment variables. + """ + secret_key = env.str("SIGNATURE_SECRET_KEY") + api_id = env.int("API_ID") + api_hash = env.str("API_HASH") + session_str = env.str("SESSION_STR") + yandex_map_api_key = env.str("YANDEX_MAP_API_KEY") + return Miscellaneous( + secret_key=secret_key, + api_id=api_id, + api_hash=api_hash, + session_str=session_str, + yandex_map_api_key=yandex_map_api_key, + ) + + +@dataclass(frozen=True, slots=True) +class Config: + tg_bot: TgBot + misc: Miscellaneous + redis: RedisConfig | None = None + + +def search_env() -> str: + current_frame = inspect.currentframe() + frame = current_frame.f_back + caller_dir = Path(frame.f_code.co_filename).parent.resolve() + start = caller_dir / ".env" + return str(start) + + +def change_env(section: str, value: str) -> None: + env = Env() + env.read_env() + + dumped_env = env.dump() + text = "" + start = search_env() + + with open(start, "w", encoding="utf-8") as file: + for v in dumped_env: + if v: + e = dumped_env[v] + if v == section: + e = value + text += f"{v}={e}\n" + file.write(text) + + +@lru_cache +def load_config() -> Config: + """ + This function takes an optional file path as input and returns a Config object. + It reads environment variables from a .env file if provided, else from the process environment. + :return: Config object with attributes set as per environment variables. + """ + + env = Env() + env.read_env(search_env()) + + return Config( + tg_bot=TgBot.from_env(env), + misc=Miscellaneous.from_env(env), + redis=RedisConfig.from_env(env) + ) diff --git a/src/tgbot/filters/__init__.py b/src/tgbot/filters/__init__.py new file mode 100644 index 0000000..244bf63 --- /dev/null +++ b/src/tgbot/filters/__init__.py @@ -0,0 +1,11 @@ +from .filters_chat import ( + ChatTypeFilter, +) +from .is_admin_filter import ( + IsAdmin, +) + +__all__ = ( + "IsAdmin", + "ChatTypeFilter" +) diff --git a/src/tgbot/filters/filters_chat.py b/src/tgbot/filters/filters_chat.py new file mode 100644 index 0000000..8b32593 --- /dev/null +++ b/src/tgbot/filters/filters_chat.py @@ -0,0 +1,17 @@ +from aiogram.filters import ( + BaseFilter, +) +from aiogram.types import ( + Message, +) + + +class ChatTypeFilter(BaseFilter): + def __init__(self, chat_type: str | list[str]) -> None: + self.chat_type = chat_type + + async def __call__(self, message: Message) -> bool: + if isinstance(self.chat_type, str): + return message.chat.type == self.chat_type + else: + return message.chat.type in self.chat_type diff --git a/src/tgbot/filters/is_admin_filter.py b/src/tgbot/filters/is_admin_filter.py new file mode 100644 index 0000000..126803c --- /dev/null +++ b/src/tgbot/filters/is_admin_filter.py @@ -0,0 +1,15 @@ +from aiogram import ( + types, +) +from aiogram.filters import ( + BaseFilter, +) + +from src.tgbot.config import ( + load_config, +) + + +class IsAdmin(BaseFilter): + async def __call__(self, message: types.Message) -> bool: + return message.from_user.id in load_config().tg_bot.admin_ids diff --git a/src/tgbot/handlers/__init__.py b/src/tgbot/handlers/__init__.py new file mode 100644 index 0000000..c2cc351 --- /dev/null +++ b/src/tgbot/handlers/__init__.py @@ -0,0 +1,24 @@ +from .profile import ( + get_profile_router, + create_profile_router, + update_profile_router, +) +from .start import ( + start_router, +) +from .user import ( + user_router, +) + +routers_list = [ + start_router, + user_router, + get_profile_router, + create_profile_router, + update_profile_router, + # echo_router, # echo_router must be last +] + +__all__ = ( + "routers_list", +) diff --git a/src/tgbot/handlers/profile/__init__.py b/src/tgbot/handlers/profile/__init__.py new file mode 100644 index 0000000..f187007 --- /dev/null +++ b/src/tgbot/handlers/profile/__init__.py @@ -0,0 +1,9 @@ +from .create import create_profile_router +from .get import get_profile_router +from .update import update_profile_router + +__all__ = ( + "get_profile_router", + "create_profile_router", + "update_profile_router", +) diff --git a/src/tgbot/handlers/profile/create.py b/src/tgbot/handlers/profile/create.py new file mode 100644 index 0000000..3836e97 --- /dev/null +++ b/src/tgbot/handlers/profile/create.py @@ -0,0 +1,373 @@ +import asyncio +import datetime +from decimal import ( + Decimal, +) +import http +from pathlib import ( + Path, +) +from typing import ( + Any, +) + +from aiofiles import ( # type: ignore + os, +) +from aiogram import ( + Bot, + F, + Router, + types, +) +from aiogram.enums import ( + ContentType, +) +from aiogram.filters import ( + StateFilter, +) +from aiogram.fsm.context import ( + FSMContext, +) +from aiogram_calendar import ( + DialogCalendar, + DialogCalendarCallback, + get_user_locale, +) +from que_sdk import ( + QueClient, +) +from que_sdk.schemas import ( + ProfileCreateSchema, +) +from yandex_geocoder import ( + Client, +) + +from src.tgbot import ( + services, +) +from src.tgbot.keyboards import ( + reply, +) +from src.tgbot.misc import ( + states, +) + +create_profile_router = Router() + + +@create_profile_router.callback_query(F.data == "user:profile-create") +@create_profile_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.gender)) +async def profile_create_handler(obj: types.TelegramObject, state: FSMContext) -> None: + text = ( + "Вам нужно пройти опрос, чтобы создать профиль:\n\n" + "Напишите мне ваше имя, которое будут все видеть в анкете" + ) + reply_markup = reply.get_user_first_name() + if isinstance(obj, types.Message): + await obj.answer(text=text, reply_markup=reply_markup) + if isinstance(obj, types.CallbackQuery) and state is not None: + await obj.message.delete() + await obj.message.answer(text=text, reply_markup=reply_markup) + await state.set_state(states.RegistrationSG.first_name) + + +@create_profile_router.message(F.text, StateFilter(states.RegistrationSG.first_name)) +async def input_first_name_handler( + obj: types.TelegramObject, + state: FSMContext, + bot: Bot, +) -> None: + text = "Принято! Выберите ваш гендер" + first_name: str + storage = await state.get_data() + profile = storage.get("profile", {}) + if isinstance(obj, types.Message): + first_name = obj.text if obj.text != "Взять из телеграмма" else obj.from_user.first_name + profile["first_name"] = first_name + await state.update_data({"profile": profile}) + await obj.answer(text=text, reply_markup=reply.gender_menu()) + + if isinstance(obj, types.CallbackQuery): + text = "Вы вернулись на шаг назад. Выберите ваш гендер" + await bot.delete_message(chat_id=obj.from_user.id, message_id=obj.message.message_id - 1) + await bot.delete_message(chat_id=obj.from_user.id, message_id=obj.message.message_id) + await obj.message.answer(text=text, reply_markup=reply.gender_menu()) + await state.set_state(states.RegistrationSG.gender) + + +@create_profile_router.message(F.text == "♂ Мужской", StateFilter(states.RegistrationSG.gender)) +@create_profile_router.message(F.text == "♀ Женский", StateFilter(states.RegistrationSG.gender)) +@create_profile_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.city)) +async def input_gender_handler(message: types.Message, state: FSMContext) -> None: + storage = await state.get_data() + profile = storage.get("profile") + genders = { + "♂ Мужской": "male", + "♀ Женский": "female" + } + current_year = datetime.datetime.now().year + year = current_year - 18 + if genders.get(message.text): + profile["gender"] = genders[message.text] + await state.update_data({"profile": profile}) + text = ( + "Теперь выберите дату своего рождения" + ) + await message.answer(text=text, reply_markup=types.ReplyKeyboardRemove()) + await asyncio.sleep(0.15) + await message.answer( + text="Календарь:", + reply_markup=await DialogCalendar( + locale=await get_user_locale(message.from_user) + ).start_calendar(year=year), + ) + await state.set_state(states.RegistrationSG.birthday) + + +@create_profile_router.callback_query( + DialogCalendarCallback.filter(), + StateFilter(states.RegistrationSG.birthday) +) +@create_profile_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.about_me)) +async def process_dialog_calendar( + obj: types.TelegramObject, + state: FSMContext, + bot: Bot, + callback_data: DialogCalendarCallback | None = None, +) -> None: + text = ( + "Нажмите на кнопку ниже, чтобы определить ваше местоположение! Или напишите текстом" + ) + storage = await state.get_data() + profile = storage.get("profile") + if isinstance(obj, types.CallbackQuery): + call = obj + if callback_data.act == "CANCEL": + await input_first_name_handler(obj=call, state=state, bot=bot) + else: + selected, date = await DialogCalendar( + locale=await get_user_locale(call.from_user) + ).process_selection(call, callback_data) + if selected: + current_date = datetime.datetime.now().date() + if date.date() < current_date: + profile["birthdate"] = date.strftime("%Y-%m-%d") + await state.update_data({"profile": profile}) + await call.message.answer(text=text, reply_markup=reply.get_location_menu()) + await state.set_state(states.RegistrationSG.city) + else: + await call.answer(text="Выбранная вами дата превышает текущую", show_alert=True) + if isinstance(obj, types.Message): + message = obj + await message.answer(text=text, reply_markup=reply.get_location_menu()) + await state.set_state(states.RegistrationSG.city) + + +@create_profile_router.message( + F.content_type.in_([ContentType.LOCATION]), + StateFilter(states.RegistrationSG.city), +) +async def handle_user_location(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + ya_client: Client = middleware_data.get("ya_client") + longitude = message.location.longitude + latitude = message.location.latitude + city = await ya_client.aioaddress(longitude=Decimal(longitude), latitude=Decimal(latitude), level="city") + storage = await state.get_data() + profile = storage.get("profile") + profile.update({ + "city": city, + "longitude": longitude, + "latitude": latitude + }) + await state.update_data({"profile": profile}) + text = ( + "Отлично! Теперь напишите о себе" + ) + await message.answer(text=text, reply_markup=reply.back_to_menu()) + await state.set_state(states.RegistrationSG.about_me) + + +@create_profile_router.message(F.text != "✅ Да все хорошо!", StateFilter(states.RegistrationSG.city)) +@create_profile_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.interested_in)) +async def input_city_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + ya_client: Client = middleware_data.get("ya_client") + longitude, latitude = await ya_client.aiocoordinates(message.text) + city = await ya_client.aioaddress(longitude=longitude, latitude=latitude, level="city") + storage = await state.get_data() + profile = storage.get("profile") + text = ( + "Я нашел такой адрес:\n" + "*{city}*\n" + "Если все правильно, то подтвердите" + ).format(city=city) + profile.update({ + "city": city, + "longitude": float(longitude), + "latitude": float(latitude) + }) + + await state.update_data({"profile": profile}) + await message.answer(text=text, reply_markup=reply.confirmation_menu()) + + +@create_profile_router.message(F.text == "✅ Да все хорошо!", StateFilter(states.RegistrationSG.city)) +async def handle_confirmation_city(message: types.Message, state: FSMContext) -> None: + text = ( + "Отлично! Теперь напишите о себе" + ) + await message.answer(text=text, reply_markup=reply.back_to_menu()) + await state.set_state(states.RegistrationSG.about_me) + + +@create_profile_router.message(F.text, StateFilter(states.RegistrationSG.about_me)) +@create_profile_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.hobbies)) +async def input_about_me_handler(message: types.Message, state: FSMContext) -> None: + storage = await state.get_data() + profile = storage.get("profile") + profile["description"] = message.text + text = "Принято! Теперь выберите кого вы бы хотели найти" + + await state.update_data({"profile": profile}) + await message.answer(text=text, reply_markup=reply.interested_in_gender_menu()) + await state.set_state(states.RegistrationSG.interested_in) + + +@create_profile_router.message( + F.text == "♂ Парня", + StateFilter(states.RegistrationSG.interested_in), +) +@create_profile_router.message( + F.text == "♀ Девушку", + StateFilter(states.RegistrationSG.interested_in), +) +@create_profile_router.message( + F.text == "<< Вернуться назад", + StateFilter(states.RegistrationSG.photos) +) +async def input_interested_in_handler(message: types.Message, state: FSMContext) -> None: + gender = message.text + storage = await state.get_data() + interested_genders = { + "♂ Парня": "male", + "♀ Девушку": "female", + } + profile = storage.get("profile") + if interested_genders.get(gender): + profile["interested_in"] = interested_genders.get(gender) + await state.update_data({"profile": profile}) + text = ( + "Отлично! Выберите интересные для вас занятия" + ) + await message.answer(text=text, reply_markup=reply.hobbies_menu()) + await state.set_state(states.RegistrationSG.hobbies) + + +@create_profile_router.message(F.text, StateFilter(states.RegistrationSG.hobbies)) +async def input_hobbies_handler(message: types, state: FSMContext) -> None: + storage = await state.get_data() + selected_interests = storage.get("profile").get("hobbies", []) + profile = storage.get("profile") + hobby_name = message.text + text = ( + "И напоследок, пришлите одну или несколько своих фотографий" + ) + if hobby_name == "Подтвердить выбор": + if not selected_interests: + await message.answer(text="Вы должны выбрать как минимум один интерес") + else: + await message.answer(text=text, reply_markup=reply.get_photo_from_user_menu()) + await state.set_state(states.RegistrationSG.photos) + elif hobby_name == "Очистить список": + selected_interests = [] + profile["hobbies"] = selected_interests + await state.update_data({"profile": profile}) + else: + selected_interests.append(hobby_name) + profile["hobbies"] = selected_interests + await state.update_data({"profile": profile}) + + +# https://ru.stackoverflow.com/questions/1456135/ +@create_profile_router.message( + F.content_type.in_([ContentType.PHOTO]), + StateFilter(states.RegistrationSG.photos), +) +async def user_handle_album( + message: types.Message, + state: FSMContext, + bot: Bot, + album: list[types.Message] | None = None, +) -> None: + storage = await state.get_data() + profile = storage.get("profile") + text = services.profile_text(profile) + telegram_id = message.from_user.id + # Если изменяем расположение файла, то еще нужно изменить root + # TODO: Надо бы перенести в services + root = Path(__file__).resolve().parent.parent.parent.parent.parent + user_folder = rf"{root}/photos/{telegram_id}/" + profile_service = services.ProfileService(user_folder) + censor_warning_text = "Система обнаружила наготу в фотографиях. Попробуйте ещё раз" + + if not await os.path.exists(user_folder): + await os.mkdir(user_folder) + + if album is None: + await profile_service.download_photos(bot=bot, photos=message) + + if await profile_service.check_photos(): + await message.answer(text=censor_warning_text) + + file_id = message.photo[-1].file_id + await message.answer_photo(photo=file_id, caption=text) + else: + if len(album) > 5: + await message.answer(text="Превышено максимальное количество фото: не более 5") + return + + await profile_service.download_photos(bot=bot, photos=album) + if await profile_service.check_photos(): + await message.answer(text=censor_warning_text) + + media_group = [ + types.InputMediaPhoto(media=photo.photo[-1].file_id, caption=text if i == 0 else '') + for i, photo in enumerate(album) + ] + await message.answer_media_group(media=media_group) + profile["folder_path"] = user_folder + await state.update_data({"profile": profile}) + await state.update_data({"profile_service": profile_service}) + await message.answer(text="Подтвердите корректность данных", reply_markup=reply.confirmation_menu()) + await state.set_state(states.RegistrationSG.confirmation) + + +@create_profile_router.message(F.text == "✅ Да все хорошо!", StateFilter(states.RegistrationSG.confirmation)) +async def send_profile_data_to_server(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + profile = storage.get("profile") + profile_service: services.ProfileService = storage.get("profile_service") + status_code, response = await que_client.create_profile( + data_in=ProfileCreateSchema( + first_name=profile.get("first_name"), + gender=profile.get("gender"), + city=profile.get("city"), + latitude=profile.get("latitude"), + longitude=profile.get("longitude"), + birthdate=profile.get("birthdate"), + description=profile.get("description"), + interested_in=profile.get("interested_in"), + hobbies=profile.get("hobbies") + ), + access_token=storage.get("access_token") + ) + if status_code == http.HTTPStatus.CREATED: + await profile_service.send_photos(client=que_client, access_token=storage.get("access_token")) + await message.answer(text="Поздравляем, вы создали профиль", reply_markup=reply.main_menu()) + else: + await message.answer(text="Произошла какая-то ошибка на стороне сервера. Попробуйте еще раз немного позже") + await profile_service.delete_files_in_folder() + await state.update_data({"profile": None}) + await state.update_data({"user": None}) diff --git a/src/tgbot/handlers/profile/get.py b/src/tgbot/handlers/profile/get.py new file mode 100644 index 0000000..a0ad82f --- /dev/null +++ b/src/tgbot/handlers/profile/get.py @@ -0,0 +1,43 @@ +from typing import ( + Any, +) + +from aiogram import ( + F, + Router, + types, +) +from aiogram.fsm.context import ( + FSMContext, +) +from que_sdk import ( + QueClient, +) + +from src.tgbot import ( + services, +) +from src.tgbot.keyboards import ( + reply, +) + +get_profile_router = Router() + + +@get_profile_router.callback_query(F.data == "user:profile") +async def profile_handler(call: types.CallbackQuery, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + _, user = await que_client.get_user_me(access_token=storage.get("access_token")) + profile = user.get("profile") + photos = user.get("photos") + text = services.profile_text(profile) + media_group = [ + types.InputMediaPhoto(media=photo.get("remote_url"), caption=text if i == 0 else '') + for i, photo in enumerate(photos) + ] + await call.message.delete() + await call.message.answer(text="💫", reply_markup=reply.profile_menu()) # type: ignore + await call.message.answer_media_group( + media=media_group, + ) diff --git a/src/tgbot/handlers/profile/update.py b/src/tgbot/handlers/profile/update.py new file mode 100644 index 0000000..61b304f --- /dev/null +++ b/src/tgbot/handlers/profile/update.py @@ -0,0 +1,59 @@ +from typing import ( + Any, +) + +from aiogram import ( + F, + Router, + types, +) +from aiogram.filters import ( + StateFilter, +) +from aiogram.fsm.context import ( + FSMContext, +) +from que_sdk import ( + QueClient, +) +from que_sdk.schemas import ( + ProfileUpdateSchema, +) + +from src.tgbot.keyboards import ( + inline, + reply, +) +from src.tgbot.misc import ( + states, +) + +update_profile_router = Router() + + +@update_profile_router.message(F.text == "✏️ Изменить") +async def update_profile_handler(message: types.Message) -> None: + text = "Выберите, что вы хотите изменить в своём профиле" + await message.answer(text=text, reply_markup=inline.profile_update_menu()) # type: ignore + + +@update_profile_router.callback_query(F.data == "first_name") +async def update_first_name_handler(call: types.CallbackQuery, state: FSMContext) -> None: + await call.message.delete() + await call.message.answer(text="Введите новое имя", reply_markup=reply.back_to_menu()) + await state.set_state(states.UpdateProfileSG.first_name) # type: ignore + + +@update_profile_router.message(F.text, StateFilter(states.UpdateProfileSG.first_name)) # type: ignore +async def input_first_name_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + profile_id = storage.get("user").get("profile").get("id") + access_token = storage.get("access_token") + await que_client.update_profile( + access_token=access_token, + profile_id=profile_id, + data_in=ProfileUpdateSchema( + first_name=message.text + ) + ) diff --git a/src/tgbot/handlers/start.py b/src/tgbot/handlers/start.py new file mode 100644 index 0000000..fde7b77 --- /dev/null +++ b/src/tgbot/handlers/start.py @@ -0,0 +1,127 @@ +import http +import json +from typing import ( + Any, +) + +from aiogram import ( + F, + Router, + types, +) +from aiogram.filters import ( + CommandStart, +) +from aiogram.fsm.context import ( + FSMContext, +) +from aiogram.utils.i18n import ( + gettext as _, + lazy_gettext as __, +) +from que_sdk import ( + QueClient, + schemas, +) + +from src.tgbot.config import ( + Config, +) +from src.tgbot.filters import ( + ChatTypeFilter, +) +from src.tgbot.keyboards import ( + inline, + reply, +) +from src.tgbot.misc import ( + messages, +) +from src.tgbot.services import ( + AuthService, +) + +start_router = Router() +start_router.message.filter( + ChatTypeFilter(chat_type=["private"]) +) + + +@start_router.message(CommandStart()) +async def start_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + config: Config = middleware_data.get("config") + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + auth = AuthService(client=que_client, config=config) + if not storage: + status_code, response = await auth.handle_login_t_me(message=message, state=state) + if status_code == http.HTTPStatus.NOT_FOUND: + await message.answer( + text=messages.not_found_user, + reply_markup=reply.login_signup_menu() + ) + storage = await state.get_data() + status_code, response = await auth.get_user_data(storage=storage) + if status_code == http.HTTPStatus.BAD_REQUEST: + code = response.get("detail").get("code") + if code == 3002: + await message.answer(text=messages.deactivate_user) + else: + if status_code != http.HTTPStatus.UNAUTHORIZED: + username = response.get("username") if response.get("username") is not None else message.from_user.username + await message.answer( + text=messages.greet_auth_user.format(username=username), + reply_markup=reply.main_menu() + ) + + +@start_router.message(F.text == __("📝 Создать аккаунт")) +async def signup_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + config: Config = middleware_data.get("config") + auth = AuthService(client=que_client, config=config) + username = message.from_user.username + status_code, response = await que_client.signup( + data_in=schemas.SignUpSchema( + username=username, + telegram_id=message.from_user.id, + ) + ) + + await auth.handle_login_t_me(state=state, message=message) + await message.answer( + text=messages.welcome.format(username=username), + reply_markup=reply.main_menu() + ) + + +@start_router.message(F.web_app_data) +async def web_app_login_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + client: QueClient = middleware_data.get("que-client") + data = json.loads(message.web_app_data.data) + status_code, response = await client.login( + data_in=schemas.LoginSchema( + username=data.get("login"), + password=data.get("password"), + telegram_id=message.from_user.id + ) + ) + if status_code == http.HTTPStatus.OK: + access_token, refresh_toke = response.get('access_token'), response.get('refresh_token') + await state.update_data({"access_token": access_token, "refresh_token": refresh_toke}) + await message.answer( + text=_("С возвращением, {username}").format(username=data.get("login")), + reply_markup=reply.main_menu() + ) + if status_code == http.HTTPStatus.UNAUTHORIZED: + await message.answer( + text=messages.invalid_credentials + ) + + +@start_router.message(F.text == __("ℹ️ О проекте")) +async def about_project_handler(message: types.Message) -> None: + text = _( + "Система работает на open-source" + ) + await message.answer(text=text, reply_markup=inline.about_project_menu()) diff --git a/src/tgbot/handlers/user.py b/src/tgbot/handlers/user.py new file mode 100644 index 0000000..b159036 --- /dev/null +++ b/src/tgbot/handlers/user.py @@ -0,0 +1,88 @@ +from typing import ( + Any, +) + +from aiogram import ( + F, + Router, + types, +) +from aiogram.filters import ( + Command, + StateFilter, +) +from aiogram.fsm.context import ( + FSMContext, +) +from que_sdk import ( + QueClient, +) + +from src.tgbot.filters import ( + ChatTypeFilter, +) +from src.tgbot.keyboards import ( + inline, + reply, +) +from src.tgbot.misc import ( + states, +) + +user_router = Router() +user_router.message.filter( + ChatTypeFilter(chat_type=["private"]) +) + + +@user_router.message(F.text == "👤 Аккаунт") +@user_router.message(F.text == "<< Вернуться назад", StateFilter(states.RegistrationSG.first_name)) +@user_router.callback_query(F.data == "back_to_user_menu") +async def user_handler(obj: types.TelegramObject, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + user = storage.get("user") + if user is None: + _, response = await que_client.get_user_me(access_token=storage.get("access_token")) + else: + response = user + days = response.get("days_since_created") + text = ( + "Имя пользователя: *{username}*\n" + "Уникальный ID: `{telegram_id}`\n\n" + "Вы с нами {days} дней" + ).format( + username=response.get("username"), + telegram_id=response.get("telegram_id"), + days=days + ) + profile_created = bool(response.get("profile")) + await state.update_data({"id": response.get("id")}) + if isinstance(obj, types.Message): + if obj.text == "<< Вернуться назад": + await obj.answer(text="👤", reply_markup=reply.main_menu()) + await state.set_state(None) + await obj.answer(text=text, reply_markup=inline.user_menu(is_profile=profile_created)) + elif isinstance(obj, types.CallbackQuery): + await obj.message.edit_text(text=text, reply_markup=inline.user_menu(is_profile=profile_created)) + + +@user_router.message(F.text, Command("reactivate")) +async def user_activate_handler(message: types.Message, state: FSMContext, **middleware_data: Any) -> None: + que_client: QueClient = middleware_data.get("que-client") + storage = await state.get_data() + access_token = storage.get("access_token") + await que_client.reactivate_user(access_token=access_token) + await message.delete() + await message.answer(text="Поздравляем! Вы восстановили аккаунт", reply_markup=reply.main_menu()) + + +@user_router.callback_query(F.data == "user:signout") +async def user_signout_handler(call: types.CallbackQuery, state: FSMContext) -> None: + text = ( + "Вы вышли из текущей сессии, чтобы войти в аккаунт используйте команду /start или кнопку ниже" + ) + # TODO: Проверить работоспособность + await state.clear() + await call.message.delete() + await call.message.answer(text=text, reply_markup=reply.login_menu()) diff --git a/src/tgbot/keyboards/__init__.py b/src/tgbot/keyboards/__init__.py new file mode 100644 index 0000000..1e14f37 --- /dev/null +++ b/src/tgbot/keyboards/__init__.py @@ -0,0 +1,9 @@ +from . import ( + inline, + reply, +) + +__all__ = ( + "inline", + "reply", +) diff --git a/src/tgbot/keyboards/inline.py b/src/tgbot/keyboards/inline.py new file mode 100644 index 0000000..292d266 --- /dev/null +++ b/src/tgbot/keyboards/inline.py @@ -0,0 +1,64 @@ +from aiogram import ( + types, +) +from aiogram.types import ( + WebAppInfo, +) +from aiogram.utils.i18n import ( + gettext as _, +) +from aiogram.utils.keyboard import ( + InlineKeyboardBuilder, +) + + +def about_project_menu() -> types.InlineKeyboardMarkup: + builder = InlineKeyboardBuilder() + builder.row( + types.InlineKeyboardButton(text="🔗 Github", web_app=WebAppInfo(url="https://github.com/QueGroup")) + ) + return builder.as_markup() + + +def user_menu(is_profile: bool) -> types.InlineKeyboardMarkup: + builder = InlineKeyboardBuilder() + if is_profile: + builder.row( + types.InlineKeyboardButton(text=_("👤 Профиль"), callback_data="user:profile"), + ) + else: + builder.row( + types.InlineKeyboardButton(text=_("Создать профиль"), callback_data="user:profile-create"), + ) + builder.row( + types.InlineKeyboardButton(text=_("Изменить"), callback_data="user:edit"), + ) + builder.row( + types.InlineKeyboardButton(text=_("🔙 Выйти из аккаунта"), callback_data="user:signout") + ) + + return builder.as_markup() + + +def user_activation_menu() -> types.InlineKeyboardMarkup: + builder = InlineKeyboardBuilder() + builder.row( + types.InlineKeyboardButton(text=_("🚀 Активировать"), callback_data="user:activate") + ) + return builder.as_markup() + + +def profile_update_menu() -> types.InlineKeyboardMarkup: + builder = InlineKeyboardBuilder() + + builder.row( + types.InlineKeyboardButton(text=_("📇 Имя"), callback_data="first_name"), + types.InlineKeyboardButton(text=_("⚧️ Пол"), callback_data="gender"), + types.InlineKeyboardButton(text=_("🏙️ Город"), callback_data="city"), + types.InlineKeyboardButton(text=_("🎂 Дата рождения"), callback_data="birthdate"), + types.InlineKeyboardButton(text=_("📸 Фото"), callback_data="photo"), + types.InlineKeyboardButton(text=_("✍️ О себе"), callback_data="about_me"), + types.InlineKeyboardButton(text=_("🧑‍🎨 Хобби"), callback_data="hobbies") + ) + builder.adjust(1, 2, 1, 2) + return builder.as_markup() diff --git a/src/tgbot/keyboards/reply.py b/src/tgbot/keyboards/reply.py new file mode 100644 index 0000000..1af56ab --- /dev/null +++ b/src/tgbot/keyboards/reply.py @@ -0,0 +1,152 @@ +from aiogram import ( + types, +) +from aiogram.types import ( + WebAppInfo, +) +from aiogram.utils.i18n import ( + gettext as _, +) +from aiogram.utils.keyboard import ( + ReplyKeyboardBuilder, +) + + +def main_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.add( + types.KeyboardButton(text=_("👤 Аккаунт")) + ) + builder.row( + types.KeyboardButton(text=_("💜 Знакомства")), + types.KeyboardButton(text=_("🎭 Мероприятия")), + ) + builder.row( + types.KeyboardButton(text=_("ℹ️ О проекте")) + ) + return builder.as_markup(resize_keyboard=True) + + +def login_signup_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text=_("📝 Создать аккаунт")), + types.KeyboardButton( + text=_("🔑 Войти в аккаунт"), web_app=WebAppInfo(url="https://floppy-phones-camp.loca.lt") + ), + ) + return builder.as_markup(resize_keyboard=True) + + +def login_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton( + text=_("🔑 Войти в аккаунт"), web_app=WebAppInfo(url="https://floppy-phones-camp.loca.lt") + ), + ) + return builder.as_markup(resize_keyboard=True) + + +def gender_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="♂ Мужской"), + types.KeyboardButton(text="♀ Женский"), + ) + builder.row( + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def interested_in_gender_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="♂ Парня"), + types.KeyboardButton(text="♀ Девушку"), + ) + builder.row( + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def hobbies_menu() -> types.ReplyKeyboardMarkup: + hobbies = [ + ("Спорт", "sports"), + ("Музыка", "music"), + ("Путешествия", "travelling"), + ("Готовка", "cooking"), + ("Компьютерные игры", "gaming") + ] + builder = ReplyKeyboardBuilder() + + for hobby_name, hobby_callback in hobbies: + button_text = f"{hobby_name}" + builder.row( + types.KeyboardButton(text=button_text) + ) + builder.adjust(1, 2) + builder.row( + types.KeyboardButton(text="Подтвердить выбор"), + types.KeyboardButton(text="Очистить список"), + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def get_location_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.add( + types.KeyboardButton( + text=_("🗺 Определить автоматически"), request_location=True + ), + types.KeyboardButton(text="<< Вернуться назад") + ) + builder.adjust(1) + return builder.as_markup(resize_keyboard=True) + + +def get_photo_from_user_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def get_user_first_name() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="Взять из телеграмма") + ) + builder.row( + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def back_to_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="<< Вернуться назад") + ) + return builder.as_markup(resize_keyboard=True) + + +def confirmation_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="✅ Да все хорошо!") + ) + return builder.as_markup(resize_keyboard=True) + + +def profile_menu() -> types.ReplyKeyboardMarkup: + builder = ReplyKeyboardBuilder() + builder.row( + types.KeyboardButton(text="✏️ Изменить"), + types.KeyboardButton(text="🗑 Удалить") + ) + return builder.as_markup(resize_keyboard=True) diff --git a/src/tgbot/middlewares/__init__.py b/src/tgbot/middlewares/__init__.py new file mode 100644 index 0000000..218ca11 --- /dev/null +++ b/src/tgbot/middlewares/__init__.py @@ -0,0 +1,45 @@ +# from .AgentSupport import ( +# SupportMiddleware, +# ) +# from .BanCheck import ( +# BanMiddleware, +# ) +# from .IsMaintenanceCheck import ( +# IsMaintenance, +# ) +# from .LinkCheck import ( +# LinkCheckMiddleware, +# ) +# from .Log import ( +# LogMiddleware, +# ) +# from .SchedulerWare import ( +# SchedulerMiddleware, +# ) +from .access_control import ( + AccessControlMiddleware, +) +from .album import ( + AlbumMiddleware, +) +from .di import ( + DIMiddleware, +) +from .throttling import ( + ThrottlingMiddleware, +) + +__all__ = ( + # "AgentSupport", + # "BanMiddleware", + # "IsMaintenance", + # "LinkCheck", + # "LogMiddleware", + # "SchedulerMiddleware", + "ThrottlingMiddleware", + # "SupportMiddleware", + # "LinkCheckMiddleware", + "DIMiddleware", + "AccessControlMiddleware", + "AlbumMiddleware", +) diff --git a/src/tgbot/middlewares/access_control.py b/src/tgbot/middlewares/access_control.py new file mode 100644 index 0000000..e9cdef6 --- /dev/null +++ b/src/tgbot/middlewares/access_control.py @@ -0,0 +1,104 @@ +import datetime +import http +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, +) +from aiogram.fsm.context import ( + FSMContext, +) +from aiogram.types import ( + CallbackQuery, + TelegramObject, +) +from que_sdk import ( + QueClient, +) + +from src.tgbot.misc import ( + messages, +) +from src.tgbot.misc.exceptions import ( + CancelHandler, +) +from src.tgbot.types import ( + Handler, +) + + +class AccessControlMiddleware(BaseMiddleware): + def __init__(self, client: QueClient) -> None: + self.client = client + self.text_unauthorized = "Вы не вошли в аккаунт" + + async def __call__( + self, + handler: Handler, + event: TelegramObject, + data: dict[str, Any], + ) -> Any: + update = data.get("event_update") + try: + command = update.message.text + except AttributeError: + command = event.data + state = data.get("state") + + if await self._is_allowed_command(event, command): + return await handler(event, data) + + try: + await self._on_process_event(state=state) + return await handler(event, data) + except CancelHandler as e: + await self._handle_cancel_event(event=event, e=e) + + @staticmethod + async def _is_allowed_command(event: TelegramObject, command: str) -> bool: + allowed_commands = {"/start", "/reactivate", "📝 Создать аккаунт", "/help"} + if isinstance(event, CallbackQuery): + return command in allowed_commands + else: + return event.web_app_data is not None or command in allowed_commands + + async def _on_process_event(self, state: FSMContext) -> None: + storage = await state.get_data() + + if ( + storage and + isinstance(storage.get("timestamp"), datetime.datetime) and + datetime.datetime.now() - storage.get("timestamp") < datetime.timedelta(minutes=15) + ): + + status_code, response = storage.get("status_code"), storage.get("user") + else: + status_code, response = await self.client.get_user_me( + access_token=storage.get("access_token", "") + ) + if status_code != http.HTTPStatus.UNAUTHORIZED or status_code == http.HTTPStatus.BAD_REQUEST: + await state.update_data( + { + "status_code": status_code, + "user": response, + "timestamp": datetime.datetime.now() + } + ) + if status_code == http.HTTPStatus.UNAUTHORIZED: + raise CancelHandler("unauthorized") + elif status_code == http.HTTPStatus.BAD_REQUEST: + code = response.get("detail").get("code") + if code == 3002: + raise CancelHandler("deactivate") + + async def _handle_cancel_event(self, event: TelegramObject, e: CancelHandler) -> None: + response_texts = { + "deactivate": messages.deactivate_user, + "unauthorized": self.text_unauthorized, + } + response_text = response_texts.get(e.title) + + if response_text: + await event.answer(text=response_text) diff --git a/src/tgbot/middlewares/album.py b/src/tgbot/middlewares/album.py new file mode 100644 index 0000000..f9d4b32 --- /dev/null +++ b/src/tgbot/middlewares/album.py @@ -0,0 +1,47 @@ +import asyncio +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, + types, +) + +from src.tgbot.types import ( + Handler, +) + + +class AlbumMiddleware(BaseMiddleware): + """ + Album middleware for capturing media groups + """ + album_data: dict[Any, Any] = dict() + + def __init__(self, latency: int | float = 1): + self.latency = latency + super().__init__() + + async def __call__( + self, + handler: Handler, + message: types.Message, + data: dict[str, Any] + ) -> None: + if not message.media_group_id: + await handler(message, data) + return + try: + self.album_data[message.media_group_id].append(message) + except KeyError: + self.album_data[message.media_group_id] = [message] + await asyncio.sleep(self.latency) + + data["_is_last"] = True + data["album"] = self.album_data[message.media_group_id] + await handler(message, data) + + if message.media_group_id and data.get("_is_last"): + del self.album_data[message.media_group_id] + del data["_is_last"] diff --git a/src/tgbot/middlewares/check_maintenance.py b/src/tgbot/middlewares/check_maintenance.py new file mode 100644 index 0000000..7597fb7 --- /dev/null +++ b/src/tgbot/middlewares/check_maintenance.py @@ -0,0 +1,50 @@ +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, +) +from aiogram.types import ( + TelegramObject, +) + +from src.tgbot.types import ( + Handler, +) + + +class IsMaintenance(BaseMiddleware): + async def __call__( + self, + handler: Handler, + event: TelegramObject, + data: dict[str, Any] + ) -> Any: + pass + + # def __init__(self): + # super(IsMaintenance, self).__init__() + # + # async def on_process_message(self, message: types.Message, data: dict): + # await self.check_tech_works(obj=message) + # + # async def on_process_callback_query(self, call: types.CallbackQuery, data: dict): + # await self.check_tech_works(obj=call) + # + # @staticmethod + # async def check_tech_works( + # obj: types.CallbackQuery | types.Message + # ) -> NoReturn: + # text = _("Ведутся технические работы") + # try: + # setting = await db_commands.select_setting_tech_work() + # tech_works = setting.get("technical_works", False) + # if tech_works and obj.from_user.id not in load_config().tg_bot.admin_ids: + # try: + # await obj.answer(text=text, show_alert=True) + # except TypeError: + # await obj.answer(text=text) + # raise CancelHandler() + # except AttributeError: + # pass diff --git a/src/tgbot/middlewares/di.py b/src/tgbot/middlewares/di.py new file mode 100644 index 0000000..0354576 --- /dev/null +++ b/src/tgbot/middlewares/di.py @@ -0,0 +1,47 @@ +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, +) +from aiogram.types import ( + TelegramObject, +) +from que_sdk import ( + QueClient, +) +from yandex_geocoder import ( + Client, +) + +from src.tgbot.config import ( + Config, +) +from src.tgbot.types import ( + Handler, +) + + +class DIMiddleware(BaseMiddleware): + def __init__( + self, + config: Config, + client: QueClient, + ya_client: Client + ) -> None: + self.config = config + self.client = client + self.ya_client = ya_client + + async def __call__( + self, + handler: Handler, + event: TelegramObject, + data: dict[str, Any], + ) -> Any: + data["config"] = self.config + data["que-client"] = self.client + data["ya_client"] = self.ya_client + + return await handler(event, data) diff --git a/src/tgbot/middlewares/link_check.py b/src/tgbot/middlewares/link_check.py new file mode 100644 index 0000000..98b5887 --- /dev/null +++ b/src/tgbot/middlewares/link_check.py @@ -0,0 +1,65 @@ +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, +) +from aiogram.types import ( + TelegramObject, +) + +from src.tgbot.types import ( + Handler, +) + + +class LinkCheckMiddleware(BaseMiddleware): + async def __call__( + self, + handler: Handler, + event: TelegramObject, + data: dict[str, Any] + ) -> Any: + pass + + # async def on_process_message(self, message: types.Message, data: dict) -> None: + # if isinstance(message.chat.type, types.ChatType): + # await self._check_links_and_handle(message.from_user.id, obj=message) + # + # async def on_process_callback_query( + # self, call: types.CallbackQuery, data: dict + # ) -> None: + # await self._check_links_and_handle(call.from_user.id, obj=call) + # + # @staticmethod + # async def _check_links_and_handle( + # user_id: int, obj: types.CallbackQuery | types.Message + # ) -> NoReturn: + # links_db = await db_commands.select_all_links() + # subscribed_links = set() + # + # async def check_subscription(link_id): + # check = await bot.get_chat_member(chat_id=link_id, user_id=user_id) + # return check.status != "left" + # + # for link in links_db: + # if await check_subscription(link["telegram_link_id"]): + # subscribed_links.add(link["telegram_link_id"]) + # text, markup = ( + # "Вы подписались не на все каналы! Чтобы продолжить пользоваться ботом, " + # "подпишитесь! Ссылки ниже: " + # ), await necessary_links_keyboard( + # telegram_id=user_id, + # links_db=links_db, + # ) + # if ( + # len(subscribed_links) != len(links_db) + # and obj.from_user.id not in load_config().tg_bot.admin_ids + # ): + # try: + # await obj.answer(text=text, reply_markup=markup) + # except TypeError: + # await obj.message.answer(text=text, reply_markup=markup) + # await asyncio.sleep(1) + # raise CancelHandler() diff --git a/middlewares/SchedulerWare.py b/src/tgbot/middlewares/scheduler.py similarity index 53% rename from middlewares/SchedulerWare.py rename to src/tgbot/middlewares/scheduler.py index 70d5c85..3fb966c 100644 --- a/middlewares/SchedulerWare.py +++ b/src/tgbot/middlewares/scheduler.py @@ -1,31 +1,32 @@ from typing import ( Any, - Awaitable, - Callable, - Dict, ) -from aiogram.dispatcher.middlewares import ( +from aiogram import ( BaseMiddleware, ) -from aiogram.types.base import ( +from aiogram.types import ( TelegramObject, ) from apscheduler.schedulers.asyncio import ( AsyncIOScheduler, ) +from src.tgbot.types import ( + Handler, +) + class SchedulerMiddleware(BaseMiddleware): def __init__(self, scheduler: AsyncIOScheduler): - super(SchedulerMiddleware, self).__init__() + super().__init__() self.scheduler = scheduler - def __call__( + async def __call__( self, - handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]], + handler: Handler, event: TelegramObject, - data: Dict[str, Any], + data: dict[str, Any], ) -> Any: data["appscheduler"] = self.scheduler - return handler(event, data) + return await handler(event, data) diff --git a/src/tgbot/middlewares/tech_support.py b/src/tgbot/middlewares/tech_support.py new file mode 100644 index 0000000..4d9cb2a --- /dev/null +++ b/src/tgbot/middlewares/tech_support.py @@ -0,0 +1,37 @@ +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, +) +from aiogram.types import ( + TelegramObject, +) + +from src.tgbot.types import ( + Handler, +) + + +class SupportMiddleware(BaseMiddleware): + + async def __call__( + self, + handler: Handler, + event: TelegramObject, + data: dict[str, Any] + ) -> Any: + pass + # dispatcher = Dispatcher.get_current() + # state = dispatcher.current_state( + # chat=message.from_user.id, user=message.from_user.id + # ) + # + # state_str = str(await state.get_state()) + # if state_str == "in_support": + # data = await state.get_data() + # second_id = data.get("second_id") + # await message.copy_to(second_id) + # + # raise CancelHandler() diff --git a/src/tgbot/middlewares/throttling.py b/src/tgbot/middlewares/throttling.py new file mode 100644 index 0000000..a1c8528 --- /dev/null +++ b/src/tgbot/middlewares/throttling.py @@ -0,0 +1,118 @@ +import logging +import time +from typing import ( + Any, +) + +from aiogram import ( + BaseMiddleware, + types, +) +from redis.asyncio.client import Redis # type: ignore + +from src.tgbot.misc.exceptions import ( + CancelHandler, + Throttled, +) +from src.tgbot.types import ( + Handler, +) + + +class ThrottlingMiddleware(BaseMiddleware): + def __init__( + self, + r: Redis, + limit: int = 1, + key_prefix: str = 'antiflood_', + ) -> None: + self.rate_limit = limit + self.prefix = key_prefix + self.throttle_manager = ThrottleManager(r=r) + + super().__init__() + + async def __call__( + self, + handler: Handler, + event: types.Message, + data: dict[str, Any] + ) -> Any: + + try: + await self.on_process_event(event) + except CancelHandler: + # Cancel current handler + return + + try: + result = await handler(event, data) + except Exception as e: + logging.info(e) + return + + return result + + async def on_process_event(self, event: types.Message) -> Any: + limit = self.rate_limit + key = f"{self.prefix}_message" + + try: + await self.throttle_manager.throttle(key, rate=limit, user_id=event.from_user.id, chat_id=event.chat.id) + except Throttled as t: + await self.event_throttled(event, t) + raise CancelHandler() + + @staticmethod + async def event_throttled(event: types.Message, throttled: Throttled) -> None: + delta = throttled.rate - throttled.delta + if throttled.exceeded_count <= 3: + await event.answer(f'Too many requests.\nTry again in {delta:.2f} seconds.') + + +class ThrottleManager: + bucket_keys = [ + "RATE_LIMIT", "DELTA", + "LAST_CALL", "EXCEEDED_COUNT" + ] + + def __init__(self, r: Redis): + self.redis = r + + async def throttle(self, key: str, rate: float, user_id: int, chat_id: int) -> bool: + now = time.time() + bucket_name = f'throttle_{key}_{user_id}_{chat_id}' + + data = await self.redis.hmget(bucket_name, self.bucket_keys) + data = { + k: float(v.decode()) + if isinstance(v, bytes) + else v + for k, v in zip(self.bucket_keys, data) + if v is not None + } + called = data.get("LAST_CALL", now) + delta = now - float(called) + result = delta >= rate or delta <= 0 + data["RATE_LIMIT"] = rate + data["LAST_CALL"] = now + data["DELTA"] = delta + if not result: + data["EXCEEDED_COUNT"] = int(data["EXCEEDED_COUNT"]) + data["EXCEEDED_COUNT"] += 1 + else: + data["EXCEEDED_COUNT"] = 1 + + await self.redis.hset(bucket_name, mapping=data) + + if not result: + raise Throttled( + key=key, + chat=chat_id, + user=user_id, + rate=rate, + delta=delta, + called_at=now, + exceeded_count=data.get("EXCEEDED_COUNT", 0) + ) + return result diff --git a/src/tgbot/misc/__init__.py b/src/tgbot/misc/__init__.py new file mode 100644 index 0000000..a3bae78 --- /dev/null +++ b/src/tgbot/misc/__init__.py @@ -0,0 +1,15 @@ +from . import ( + security, + states, +) +from .constants import messages +from .utils import ( + os_path_join, +) + +__all__ = ( + "security", + "states", + "os_path_join", + "messages", +) diff --git a/src/tgbot/misc/constants.py b/src/tgbot/misc/constants.py new file mode 100644 index 0000000..549c915 --- /dev/null +++ b/src/tgbot/misc/constants.py @@ -0,0 +1,22 @@ +import dataclasses + + +@dataclasses.dataclass +class MessageTexts: + welcome: str = "🎉 Добро пожаловать, {username}! Вы создали новый аккаунт" + greet_auth_user: str = "👋 Привет, {username}, вы вошли в свой аккаунт" + deactivate_user: str = ("🛑 К сожалению, ваш аккаунт был деактивирован.\n" + "Чтобы возобновить работу с нашим приложением, пожалуйста, активируйте аккаунт.\n" + "Для этого используйте команду /reactivate.") + invalid_credentials: str = ("🔐 Ой, кажется, вы ввели неправильный логин или пароль. Пожалуйста, проверьте " + "введенные данные и попробуйте снова.") + not_found_user: str = ("🔍 Извините, мы не смогли найти ваш аккаунт.\nВы можете создать новый " + "аккаунт, нажав на кнопку 'Создать аккаунт' ниже.\nили войти в свой " + "аккаунт, используя ваш логин и пароль.") + + +messages = MessageTexts() + +__all__ = ( + "messages", +) diff --git a/src/tgbot/misc/exceptions.py b/src/tgbot/misc/exceptions.py new file mode 100644 index 0000000..69a6da4 --- /dev/null +++ b/src/tgbot/misc/exceptions.py @@ -0,0 +1,24 @@ +import dataclasses +import time + + +@dataclasses.dataclass(eq=False) +class CancelHandler(Exception): + title: str | None = None + + +@dataclasses.dataclass(eq=False) +class Throttled(Exception): + title: str | None = None + key: str = '' + called_at: float = dataclasses.field(default_factory=time.time) + rate: float | None = None + exceeded_count: int = 0 + delta: float = 0.0 + user: int | None = None + chat: int | None = None + + def __str__(self) -> str: + return f"Rate limit exceeded! (Limit: {self.rate} s, " \ + f"exceeded: {self.exceeded_count}, " \ + f"time delta: {round(self.delta, 3)} s)" diff --git a/src/tgbot/misc/security.py b/src/tgbot/misc/security.py new file mode 100644 index 0000000..6b406f1 --- /dev/null +++ b/src/tgbot/misc/security.py @@ -0,0 +1,16 @@ +import hashlib +import hmac +import secrets +import time +from typing import ( + Any, +) + + +def generate_signature(telegram_id: int, secret_key: str) -> dict[str, Any]: + timestamp = int(time.time()) + nonce = secrets.randbits(32) % (999999 - 100000) + 100000 + data_to_sign = f"{telegram_id}{timestamp}{nonce}" + + signature = hmac.new(secret_key.encode(), data_to_sign.encode(), hashlib.sha256).hexdigest() + return {"telegram_id": telegram_id, "signature": signature, "nonce": nonce, "timestamp": timestamp} diff --git a/src/tgbot/misc/states.py b/src/tgbot/misc/states.py new file mode 100644 index 0000000..764e1a0 --- /dev/null +++ b/src/tgbot/misc/states.py @@ -0,0 +1,26 @@ +from aiogram.fsm import ( + state, +) + + +class RegistrationSG(state.StatesGroup): + first_name = state.State() + gender = state.State() + city = state.State() + birthday = state.State() + about_me = state.State() + interested_in = state.State() + hobbies = state.State() + photos = state.State() + confirmation = state.State() + + +class UpdateProfileSG(state.StatesGroup): + first_name = state.State() + gender = state.State() + city = state.State() + birthday = state.State() + about_me = state.State() + interested_in = state.State() + hobbies = state.State() + photos = state.State() diff --git a/src/tgbot/misc/utils.py b/src/tgbot/misc/utils.py new file mode 100644 index 0000000..bd29a5b --- /dev/null +++ b/src/tgbot/misc/utils.py @@ -0,0 +1,5 @@ +import os + + +def os_path_join(folder_path: str, file_name: str) -> str: + return os.path.join(folder_path, file_name) diff --git a/src/tgbot/services/__init__.py b/src/tgbot/services/__init__.py new file mode 100644 index 0000000..adf67b8 --- /dev/null +++ b/src/tgbot/services/__init__.py @@ -0,0 +1,23 @@ +from .broadcaster import ( + broadcast, +) +from .nude_classifier import ( + classification_image, +) +from .profile import ProfileService, profile_text +from .set_bot_commands import ( + set_default_commands, +) +from .user import ( + AuthService +) + +__all__ = ( + "ProfileService", + "AuthService", + "profile_text", + "broadcaster", + "set_default_commands", + "classification_image", + "broadcast", +) diff --git a/src/tgbot/services/broadcaster.py b/src/tgbot/services/broadcaster.py new file mode 100644 index 0000000..42a6a35 --- /dev/null +++ b/src/tgbot/services/broadcaster.py @@ -0,0 +1,89 @@ +import asyncio +import logging +from typing import ( + Union, +) + +from aiogram import ( + Bot, + exceptions, +) +from aiogram.types import ( + InlineKeyboardMarkup, +) + + +async def send_message( + bot: Bot, + user_id: int | str, + text: str, + disable_notification: bool = False, + reply_markup: InlineKeyboardMarkup = None, +) -> bool: + """ + Safe messages sender + + :param bot: Bot instance. + :param user_id: user id. If str - must contain only digits. + :param text: text of the message. + :param disable_notification: disable notification or not. + :param reply_markup: reply markup. + :return: success. + """ + try: + await bot.send_message( + user_id, + text, + disable_notification=disable_notification, + reply_markup=reply_markup, + ) + except exceptions.TelegramBadRequest as e: + logging.error(f"Telegram server says - Bad Request: chat not found {e}") + except exceptions.TelegramForbiddenError: + logging.error(f"Target [ID:{user_id}]: got TelegramForbiddenError") + except exceptions.TelegramRetryAfter as e: + logging.error( + f"Target [ID:{user_id}]: Flood limit is exceeded. Sleep {e.retry_after} seconds." + ) + await asyncio.sleep(e.retry_after) + return await send_message( + bot, user_id, text, disable_notification, reply_markup + ) # Recursive call + except exceptions.TelegramAPIError: + logging.exception(f"Target [ID:{user_id}]: failed") + else: + logging.info(f"Target [ID:{user_id}]: success") + return True + return False + + +async def broadcast( + bot: Bot, + users: list[Union[str, int]], + text: str, + disable_notification: bool = False, + reply_markup: InlineKeyboardMarkup = None, +) -> int: + """ + Simple broadcaster. + :param bot: Bot instance. + :param users: List of users. + :param text: Text of the message. + :param disable_notification: Disable notification or not. + :param reply_markup: Reply markup. + :return: Count of messages. + """ + count = 0 + try: + for user_id in users: + if await send_message( + bot, user_id, text, disable_notification, reply_markup + ): + count += 1 + await asyncio.sleep( + 0.05 + ) # 20 messages per second (Limit: 30 messages per second) + finally: + logging.info(f"{count} messages successful sent.") + + return count diff --git a/src/tgbot/services/nude_classifier.py b/src/tgbot/services/nude_classifier.py new file mode 100644 index 0000000..8cb7a9d --- /dev/null +++ b/src/tgbot/services/nude_classifier.py @@ -0,0 +1,15 @@ +import pathlib + +from nudenet import ( + NudeDetector, +) + + +def classification_image(image_path: str | pathlib.Path) -> bool: + detector = NudeDetector() + classes = detector.detect(image_path=image_path) + censor_classes = ["FEMALE_BREAST_EXPOSED", "FEMALE_GENITALIA_EXPOSED", "ANUS_EXPOSED", "MALE_GENITALIA_EXPOSED"] + for class_ in classes: + if class_.get("class") in censor_classes and class_.get("score") >= 0.5: + return True + return False diff --git a/src/tgbot/services/profile.py b/src/tgbot/services/profile.py new file mode 100644 index 0000000..8507fe9 --- /dev/null +++ b/src/tgbot/services/profile.py @@ -0,0 +1,105 @@ +import asyncio +from concurrent.futures import ( + ThreadPoolExecutor, +) +from typing import ( + Any, +) + +import aiofiles # type: ignore +from aiofiles import ( + os, +) +from aiogram import ( + Bot, + types, +) +from que_sdk import ( + QueClient, +) + +from src.tgbot import ( + misc, +) +from src.tgbot.services import ( + classification_image, +) + + +def profile_text(profile: dict[str, Any]) -> str: + genders = { + "male": "Мужской", + "female": "Женский" + } + + interested_genders = { + "male": "Парня", + "female": "Девушку", + } + + text = ( + f"*Имя:* {profile['first_name']}\n" + f"*Пол:* {genders[profile['gender']]}\n" + f"*Дата рождения:* {profile['birthdate']}\n" + f"*Город:* {profile['city']}\n" + f"*О себе:* {profile['description']}\n" + f"*Хочешь найти:* {interested_genders[profile['interested_in']]}\n" + f"*Хобби:* {', '.join(profile['hobbies'])}\n" + ) + return text + + +class ProfileService: + + # TODO: Убрать из параметров folder_path, а задать его прямо в __init__ + def __init__( + self, + folder_path: str + ): + self.folder_path = folder_path + + async def send_photos(self, client: QueClient, access_token: str) -> None: + for file_name in await os.listdir(self.folder_path): + file_path = misc.os_path_join(self.folder_path, file_name) + async with aiofiles.open(file_path, "rb") as file: + file_data = await file.read() + status_code, response = await client.upload_photo(access_token=access_token, file=file_data) + if status_code != 200: + raise Exception(f"Failed to upload photo {file_name}: {response}") + + async def delete_files_in_folder(self) -> None: + filenames = await aiofiles.os.listdir(self.folder_path) + tasks = [aiofiles.os.remove(misc.os_path_join(self.folder_path, filename)) for filename in filenames] + await asyncio.gather(*tasks) + + async def classify_images(self) -> list[Any]: + async def classify_image(file_path: str) -> bool: + loop = asyncio.get_running_loop() + with ThreadPoolExecutor() as pool: + return await loop.run_in_executor(pool, classification_image, file_path) + + filenames = await aiofiles.os.listdir(self.folder_path) + tasks = [classify_image(misc.os_path_join(self.folder_path, filename)) for filename in filenames] + # noinspection PyTypeChecker + return await asyncio.gather(*tasks) + + async def download_photos(self, bot: Bot, photos: list[types.Message] | types.Message) -> None: + tasks = [] + + if isinstance(photos, types.Message): + photos = [photos] + + for photo in photos: + file_id = photo.photo[-1].file_id + file = await bot.get_file(file_id=file_id) + file_destination = misc.os_path_join(self.folder_path, f"photo_{file_id}.jpg") + tasks.append(bot.download_file(file_path=file.file_path, destination=file_destination)) + + await asyncio.gather(*tasks) + + async def check_photos(self) -> bool: + is_nude = await self.classify_images() + if any(is_nude): + await self.delete_files_in_folder() + return True + return False diff --git a/src/tgbot/services/set_bot_commands.py b/src/tgbot/services/set_bot_commands.py new file mode 100644 index 0000000..f1fb5c6 --- /dev/null +++ b/src/tgbot/services/set_bot_commands.py @@ -0,0 +1,43 @@ +import logging + +from aiogram import ( + Bot, + types, +) + +from src.tgbot.config import ( + Config, +) + + +async def set_user_commands( + bot: Bot, user_id: int, commands: list[types.BotCommand] +) -> None: + try: + await bot.set_my_commands( + commands=commands, scope=types.BotCommandScopeChat(chat_id=user_id) + ) + except Exception as ex: + logging.error(f"{user_id}: Commands are not installed. {ex}") + + +async def set_default_commands(bot: Bot, config: Config) -> None: + default_commands = [ + types.BotCommand(command="start", description="🟢 Запустить бота"), + ] + + await bot.set_my_commands(default_commands, scope=types.BotCommandScopeDefault()) + + # admin_commands = [ + # types.BotCommand(command="admin", description="⚒ Админ-Меню"), + # types.BotCommand(command="users", description="🫂 Пользователи"), + # types.BotCommand(command="settings", description="⚙️ Настройки"), + # types.BotCommand(command="logs", description="🗒 Логи"), + # ] + # + # for admin_id in config.tg_bot.admin_ids: + # await set_user_commands( + # bot=bot, + # user_id=admin_id, + # commands=admin_commands + default_commands + # ) diff --git a/src/tgbot/services/user.py b/src/tgbot/services/user.py new file mode 100644 index 0000000..d1fe880 --- /dev/null +++ b/src/tgbot/services/user.py @@ -0,0 +1,50 @@ +import http +from typing import ( + Any, +) + +from aiogram import ( + types, +) +from aiogram.fsm.context import ( + FSMContext, +) +from que_sdk import ( + QueClient, + schemas, +) + +from src.tgbot.config import ( + Config, +) +from src.tgbot.misc import ( + security, +) + + +class AuthService: + def __init__(self, client: QueClient, config: Config): + self.client = client + self.config = config + + async def get_user_data(self, storage: dict[str, Any]) -> tuple[http.HTTPStatus, dict[str, Any]]: + access_token = storage.get("access_token") + status_code, response = await self.client.get_user_me(access_token=access_token) + + return status_code, response + + async def handle_login_t_me( + self, + message: types.Message, + state: FSMContext, + ) -> tuple[http.HTTPStatus, dict[str, Any]] | None: + auth_data = security.generate_signature( + telegram_id=message.from_user.id, secret_key=self.config.misc.secret_key + ) + status_code, response = await self.client.login_t_me(data_in=schemas.TMELoginSchema(**auth_data)) + if status_code == http.HTTPStatus.OK: + access_token, refresh_toke = response.get('access_token'), response.get('refresh_token') + + await state.update_data({"access_token": access_token, "refresh_token": refresh_toke}) + + return status_code, response diff --git a/src/tgbot/types.py b/src/tgbot/types.py new file mode 100644 index 0000000..1af46fc --- /dev/null +++ b/src/tgbot/types.py @@ -0,0 +1,11 @@ +from typing import ( + Any, + Awaitable, + Callable, +) + +from aiogram.types import ( + TelegramObject, +) + +Handler = Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]] diff --git a/states/__init__.py b/states/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/states/admins.py b/states/admins.py deleted file mode 100644 index 508c601..0000000 --- a/states/admins.py +++ /dev/null @@ -1,9 +0,0 @@ -from aiogram.dispatcher.filters.state import ( - State, - StatesGroup, -) - - -class AdminsActions(StatesGroup): - add = State() - delete = State() diff --git a/states/new_data_state.py b/states/new_data_state.py deleted file mode 100644 index 2c2b6a3..0000000 --- a/states/new_data_state.py +++ /dev/null @@ -1,22 +0,0 @@ -from aiogram.dispatcher.filters.state import ( - State, - StatesGroup, -) - - -class NewData(StatesGroup): - sex = State() - commentary = State() - name = State() - need_partner_sex = State() - age = State() - city = State() - nationality = State() - education = State() - town = State() - car = State() - own_home = State() - hobbies = State() - child = State() - marital = State() - photo = State() diff --git a/states/reg_state.py b/states/reg_state.py deleted file mode 100644 index a583dff..0000000 --- a/states/reg_state.py +++ /dev/null @@ -1,21 +0,0 @@ -from aiogram.dispatcher.filters.state import ( - State, - StatesGroup, -) - - -class RegData(StatesGroup): - sex = State() - commentary = State() - name = State() - need_partner_sex = State() - age = State() - nationality = State() - education = State() - town = State() - car = State() - own_home = State() - hobbies = State() - child = State() - marital = State() - photo = State() diff --git a/test/__init__.py b/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/conftest.py b/test/conftest.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_api/__init__.py b/test/test_api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_api/test_location.py b/test/test_api/test_location.py deleted file mode 100644 index a48f153..0000000 --- a/test/test_api/test_location.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import ( - NoReturn, - Tuple, -) - -import aiohttp -import pytest - -from data.config import ( - load_config, -) -from loader import ( - client, -) -from utils.YandexMap.api import ( - Client, -) -from utils.YandexMap.exceptions import ( - InvalidKey, - NothingFound, - UnexpectedResponse, -) - - -@pytest.mark.asyncio -async def test_request_success() -> NoReturn: - async with aiohttp.ClientSession() as session: - async with session.get( - url="https://geocode-maps.yandex.ru/1.x/", - params=dict( - format="json", - apikey=load_config().misc.yandex_api_key, - geocode="Detroit", - ), - ) as response: - assert response.status == 200 - data = await response.json() - assert isinstance(data, dict) - assert "response" in data - - -@pytest.mark.asyncio -async def test_request_invalid_key() -> None: - with pytest.raises(InvalidKey): - cl = Client(api_key="invalid_key") - await cl._request("Detroit") - - -@pytest.mark.asyncio -async def test_request_unexpected_response() -> None: - with pytest.raises(UnexpectedResponse): - cl = Client(api_key="valid_key") - await cl._request("InvalidAddress") - - -@pytest.mark.asyncio -async def test_coordinates_success() -> NoReturn: - coordinates = await client.coordinates("Detroit") - assert isinstance(coordinates, Tuple) - assert len(coordinates) == 2 - assert all(isinstance(coord, str) for coord in coordinates) - - -@pytest.mark.asyncio -async def test_address_success() -> NoReturn: - coordinates = await client.coordinates("Detroit") - address = await client.address(*coordinates) - assert isinstance(address, str) - - -@pytest.mark.asyncio -async def test_address_nothing_found() -> None: - with pytest.raises(NothingFound): - await client.address("100.0", "200.0") diff --git a/test/test_functions/__init__.py b/test/test_functions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_functions/test_event_functions.py b/test/test_functions/test_event_functions.py deleted file mode 100644 index 49a6deb..0000000 --- a/test/test_functions/test_event_functions.py +++ /dev/null @@ -1,103 +0,0 @@ -from datetime import ( - datetime, - timedelta, -) -from typing import ( - NoReturn, -) -from unittest import ( - mock, -) -from unittest.mock import ( - AsyncMock, - Mock, - patch, -) - -import pytest - -from functions.event import ( - extra_features, -) -from utils.db_api import ( - db_commands, -) - - -@pytest.mark.asyncio -async def test_check_event_date_past_date() -> None: - telegram_id = 1 - event_time = datetime.now() - timedelta(days=10) - with patch.object( - db_commands, - "select_user_meetings", - new=AsyncMock(return_value={"time_event": event_time.strftime("%d-%m-%Y")}), - ): - update_mock = AsyncMock() - with patch.object( - db_commands, "update_user_meetings_data", new=update_mock - ) as mock: - await extra_features.check_event_date(telegram_id) - mock.assert_called_once_with( - telegram_id=telegram_id, - is_admin=False, - verification_status=False, - is_active=False, - ) - - -@pytest.mark.asyncio -async def test_check_event_date_future_date() -> None: - telegram_id = 1 - event_time = datetime.now() + timedelta(days=10) - with patch.object( - db_commands, - "select_user_meetings", - new=AsyncMock(return_value={"time_event": event_time.strftime("%d-%m-%Y")}), - ): - update_mock = AsyncMock() - with patch.object( - db_commands, "update_user_meetings_data", new=update_mock - ) as mock: - await extra_features.check_event_date(telegram_id) - mock.assert_called_once_with( - telegram_id=telegram_id, - is_admin=True, - verification_status=True, - is_active=True, - ) - - -@pytest.mark.asyncio -async def test_get_next_registration() -> NoReturn: - db_command = Mock() - db_command.select_user.return_value = {"telegram_id": 1, "events": []} - result = await extra_features.get_next_registration(telegram_id=1) - assert result == [] - - -@pytest.mark.asyncio -async def test_get_next_random_event_id() -> NoReturn: - # Mock search_event_forms() для возврата тестовых данных - mock_event_forms = [ - {"telegram_id": 1}, - {"telegram_id": 2}, - {"telegram_id": 3}, - ] - db_commands.search_event_forms = mock.AsyncMock(return_value=mock_event_forms) - - db_commands.check_returned_event_id = mock.AsyncMock(return_value=False) - - event_id = await extra_features.get_next_random_event_id(telegram_id=1) - assert event_id == 2 - - await db_commands.check_returned_event_id(telegram_id=1, id_of_events_seen=2) - - with pytest.raises(ValueError) as exc_info: - await extra_features.get_next_random_event_id(telegram_id=1) - assert str(exc_info.value) == "No upcoming events found" - - db_commands.check_returned_event_id = mock.AsyncMock(return_value=True) - - event_id = await extra_features.get_next_random_event_id(telegram_id=2) - assert event_id == 3 diff --git a/test/test_handlers/__init__.py b/test/test_handlers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/test_handlers/test_echo.py b/test/test_handlers/test_echo.py deleted file mode 100644 index 3e8c196..0000000 --- a/test/test_handlers/test_echo.py +++ /dev/null @@ -1,20 +0,0 @@ -from unittest.mock import ( - AsyncMock, -) - -from aiogram.utils.markdown import ( - hcode, -) -import pytest - -from handlers.echo_handler import ( - bot_echo, -) - - -@pytest.mark.asyncio -async def test_echo_handler() -> None: - text_mock = ["Эхо без состояния.", "Сообщение: ", hcode("repeat me")] - message_mock = AsyncMock(text=text_mock) - await bot_echo(message=message_mock) - message_mock.answer.assert_called_with(text_mock) diff --git a/test/test_handlers/test_group_start.py b/test/test_handlers/test_group_start.py deleted file mode 100644 index f550abd..0000000 --- a/test/test_handlers/test_group_start.py +++ /dev/null @@ -1,22 +0,0 @@ -from unittest.mock import ( - AsyncMock, -) - -import pytest - -from handlers.groups.start import ( - start_group_handler, -) -from loader import ( - _, -) - - -@pytest.mark.asyncio -async def test_start_group_handler() -> None: - text_mock = _( - "Привет, я бот, проекта Que Group, для верификации анкет для знакомств\n\n" - ) - message_mock = AsyncMock(text=text_mock) - await start_group_handler(message=message_mock) - message_mock.answer.assert_called_with(text_mock) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e7a75d1 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +# https://github.com/ehForwarderBot/efb-telegram-master/tree/master/tests diff --git a/functions/__init__.py b/tests/e2e/__init__.py similarity index 100% rename from functions/__init__.py rename to tests/e2e/__init__.py diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py new file mode 100644 index 0000000..1e52613 --- /dev/null +++ b/tests/e2e/conftest.py @@ -0,0 +1,38 @@ +import pytest +from telethon import ( + TelegramClient, +) +from telethon.sessions import ( + StringSession, +) +from telethon.tl.custom import ( + Conversation, +) + +from src.tgbot.config import ( + Miscellaneous, + load_config, +) + + +@pytest.fixture(scope="session") +def config() -> Miscellaneous: + return load_config().misc + + +@pytest.fixture(scope="session") +def anyio_backend() -> str: + return "asyncio" + + +@pytest.fixture(scope="session") +async def conv(config: Miscellaneous) -> Conversation: + client = TelegramClient( + StringSession(config.session_str), + config.api_id, + config.api_hash, + sequential_updates=True + ) + await client.connect() + async with client.conversation("@TestingDatingbottestbot", timeout=5) as conv: + yield conv diff --git a/tests/e2e/test_help.py b/tests/e2e/test_help.py new file mode 100644 index 0000000..30c2670 --- /dev/null +++ b/tests/e2e/test_help.py @@ -0,0 +1,22 @@ +from aiogram import ( + types, +) +import pytest +from telethon.tl.custom import ( + Conversation, +) + + +@pytest.mark.anyio +async def test_help(conv: Conversation) -> None: + await conv.send_message("/help") + resp: types.Message = await conv.get_response() + assert "👍 👎" in resp.raw_text + + +@pytest.mark.anyio +async def test_start_handler(conv: Conversation) -> None: + await conv.send_message('/start') + resp: types.Message = await conv.get_response() + resp.raw_text = resp.raw_text.replace(resp.raw_text[8:20], "") + assert resp.raw_text == "👋 Привет вы вошли в аккаунт" diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py new file mode 100644 index 0000000..6e4dd7b --- /dev/null +++ b/tests/utils/__init__.py @@ -0,0 +1,7 @@ +from .helpers import ( + get_button_with_text, +) + +__all__ = ( + "get_button_with_text", +) diff --git a/tests/utils/_get_session_string.py b/tests/utils/_get_session_string.py new file mode 100644 index 0000000..c42abf9 --- /dev/null +++ b/tests/utils/_get_session_string.py @@ -0,0 +1,12 @@ +from telethon import ( + TelegramClient, +) +from telethon.sessions import ( + StringSession, +) + +api_id = 28394664 +api_hash = "59e0397dd64ba527b2761ed10f4d92de" + +with TelegramClient(StringSession(), api_id, api_hash) as client: + print("Session string:", client.session.save()) diff --git a/tests/utils/helpers.py b/tests/utils/helpers.py new file mode 100644 index 0000000..7807883 --- /dev/null +++ b/tests/utils/helpers.py @@ -0,0 +1,29 @@ +# tests/helpers.py + +from typing import ( + Optional, +) + +from telethon.tl.custom.message import ( + Message, + MessageButton, +) + + +def get_button_with_text( + message: Message, text: str, strict: bool = False +) -> Optional[MessageButton]: + """Return MessageButton from Message with text or None.""" + if message.buttons is None: + return None + + for row in message.buttons: + for button in row: + if strict: + is_match = text == button.text + else: + is_match = text in button.text + if is_match: + return button + + return None diff --git a/utils/NudeNet/__init__.py b/utils/NudeNet/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/NudeNet/predictor.py b/utils/NudeNet/predictor.py deleted file mode 100644 index 165da57..0000000 --- a/utils/NudeNet/predictor.py +++ /dev/null @@ -1,21 +0,0 @@ -import pathlib -from typing import ( - Union, -) - -from loader import ( - detector, -) - - -async def classification_image(image_path: Union[str, pathlib.Path]) -> list[dict]: - return detector.detect(image_path) - - -async def generate_censored_image( - image_path: Union[str, pathlib.Path], out_path: Union[str, pathlib.Path] -) -> None: - detector.censor( - image_path=image_path, - output_path=out_path, - ) diff --git a/utils/YandexMap/__init__.py b/utils/YandexMap/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/YandexMap/api.py b/utils/YandexMap/api.py deleted file mode 100644 index 2ee55a2..0000000 --- a/utils/YandexMap/api.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import ( - Any, - Tuple, -) - -import aiohttp - -from utils.YandexMap.exceptions import ( - InvalidKey, - NothingFound, - UnexpectedResponse, -) - - -class Client: - __slots__ = ("api_key",) - api_key: str - - def __init__(self, api_key: str): - self.api_key = api_key - - async def _request(self, address: str) -> Any: - async with aiohttp.ClientSession() as session: - async with session.get( - url="https://geocode-maps.yandex.ru/1.x/", - params=dict(format="json", apikey=self.api_key, geocode=address), - ) as response: - if response.status == 200: - a = await response.json() - return a["response"] - elif response.status == 403: - raise InvalidKey() - else: - raise UnexpectedResponse( - f"status_code={response.status}, body={response.content}" - ) - - async def coordinates(self, address: str) -> Tuple: - d = await self._request(address) - data = d["GeoObjectCollection"]["featureMember"] - - if not data: - raise NothingFound(f'Nothing found for "{address}" not found') - - coordinates = data[0]["GeoObject"]["Point"]["pos"] - longitude, latitude = tuple(coordinates.split(" ")) - return longitude, latitude - - async def address(self, longitude, latitude) -> Any: - response = await self._request(f"{longitude},{latitude}") - data = response.get("GeoObjectCollection", {}).get("featureMember", []) - - if not data: - raise NothingFound(f'Nothing found for "{longitude} {latitude}"') - - try: - address_details = data[0]["GeoObject"]["metaDataProperty"][ - "GeocoderMetaData" - ]["AddressDetails"]["Country"] - try: - locality = address_details["AdministrativeArea"]["Locality"][ - "LocalityName" - ] - except KeyError: - locality = address_details["AdministrativeArea"][ - "SubAdministrativeArea" - ]["Locality"]["LocalityName"] - - return locality - except KeyError: - return None diff --git a/utils/YandexMap/exceptions.py b/utils/YandexMap/exceptions.py deleted file mode 100644 index 8a50ff2..0000000 --- a/utils/YandexMap/exceptions.py +++ /dev/null @@ -1,14 +0,0 @@ -class YandexGeocoderException(Exception): - pass - - -class UnexpectedResponse(YandexGeocoderException): - pass - - -class NothingFound(YandexGeocoderException): - pass - - -class InvalidKey(YandexGeocoderException): - pass diff --git a/utils/__init__.py b/utils/__init__.py deleted file mode 100644 index f09a801..0000000 --- a/utils/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from . import ( - db_api, - misc, - set_bot_commands, -) diff --git a/utils/db_api/__init__.py b/utils/db_api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/db_api/db_commands.py b/utils/db_api/db_commands.py deleted file mode 100644 index 622f171..0000000 --- a/utils/db_api/db_commands.py +++ /dev/null @@ -1,260 +0,0 @@ -import os - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.telegrambot.telegrambot.settings") -import django - -django.setup() -from asgiref.sync import ( - sync_to_async, -) -from django.db.models import ( - F, - Q, -) - - - - -from django.db.models.expressions import ( - CombinedExpression, - Value, -) - -from django_project.telegrambot.usersmanage.models import ( - NecessaryLink, - SettingModel, - User, - UserMeetings, - ViewedProfile, -) - - -@sync_to_async -def select_all_links(): - links = NecessaryLink.objects.all().values() - return links - - -@sync_to_async -def select_user(telegram_id: int): - try: - user = User.objects.get(telegram_id=telegram_id) - except Exception as ex: - user = User.objects.filter(telegram_id=telegram_id).values().first() - print(f"Error in select_user {ex}") - return user - - -@sync_to_async -def select_user_object(telegram_id: int): - try: - user = User.objects.get(telegram_id=telegram_id) - except Exception as ex: - user = User.objects.filter(telegram_id=telegram_id).values().first() - print(f"Error in select_user_object {ex}") - return user - - -@sync_to_async -def add_profile_to_viewed(user, viewed_profile): - return ViewedProfile.objects.create(viewer=user, profile=viewed_profile) - - -@sync_to_async -def check_user_exists(telegram_id: int): - user_exists = User.objects.filter(telegram_id=telegram_id).exists() - return user_exists - - -@sync_to_async -def check_user_meetings_exists(telegram_id: int): - user_exists = UserMeetings.objects.filter(telegram_id=telegram_id).exists() - return user_exists - - -@sync_to_async -def add_user(telegram_id, name, username, referrer_id=None): - if referrer_id: - return User( - telegram_id=int(telegram_id), - name=name, - username=username, - referrer_id=referrer_id, - ).save() - else: - return User(telegram_id=int(telegram_id), name=name, username=username).save() - - -@sync_to_async -def delete_user(telegram_id): - return User.objects.filter(telegram_id=telegram_id).delete() - - -@sync_to_async -def delete_user_meetings(telegram_id): - return UserMeetings.objects.filter(telegram_id=telegram_id).delete() - - -@sync_to_async -def add_meetings_user(telegram_id, username): - return UserMeetings(telegram_id=int(telegram_id), username=username).save() - - -@sync_to_async -def select_all_user_meetings(): - users = UserMeetings.objects.all().values() - return users - - -@sync_to_async -def select_user_meetings(telegram_id: int): - user = UserMeetings.objects.get(telegram_id=telegram_id) - return user - - -@sync_to_async -def select_all_users(): - users = User.objects.all().values() - return users - - -@sync_to_async -def select_all_users_id(telegram_id: int): - users = User.objects.filter(telegram_id=telegram_id).all().values() - return users - - -@sync_to_async -def count_users(): - return User.objects.all().count() - - -@sync_to_async -def update_user_data(telegram_id, **kwargs): - return User.objects.filter(telegram_id=telegram_id).update(**kwargs) - - -@sync_to_async -def update_user_meetings_data(telegram_id, **kwargs): - return UserMeetings.objects.filter(telegram_id=telegram_id).update(**kwargs) - - -@sync_to_async -def select_meetings_user(telegram_id: int): - user = UserMeetings.objects.filter(telegram_id=telegram_id).values().first() - return user - - -# https://stackoverflow.com/questions/29014966/django-1-8-arrayfield-append-extend -@sync_to_async -def update_user_events(telegram_id: int, events_id: int): - return User.objects.filter(telegram_id=telegram_id).update( - events=CombinedExpression(F("events"), "||", Value([f"{events_id}"])) - ) - - -@sync_to_async -def remove_events_from_user(telegram_id: int, events_id: int): - user = User.objects.get(telegram_id=telegram_id) - user.remove_events(f"{events_id}") - - -@sync_to_async -def select_user_username(username: str): - try: - user = User.objects.get(username=username) - except Exception as ex: - user = User.objects.filter(username=username).values().first() - print(f"Error in select_user_username {ex}") - return user - - -# https://stackoverflow.com/questions/10040143/and-dont-work-with-filter-in-django -@sync_to_async -def search_users( - need_partner_sex, - need_age_min, - need_age_max, - user_need_city, - offset: int, - limit: int, -): - query = ( - Q(is_banned=False) - & Q(sex=need_partner_sex) - & ( - (Q(age__gte=need_age_min) & Q(age__lte=need_age_max)) - | (Q(age__gte=need_age_min + 1) & Q(age__lte=need_age_max + 1)) - ) - & Q(city=user_need_city) - & Q(status=True) - ) - users = User.objects.filter(query).values()[offset: offset + limit] - return users - - -@sync_to_async -def search_event_forms(): - return UserMeetings.objects.filter(Q(is_active=True)).all().values() - - -@sync_to_async -def search_users_all(offset: int, limit: int): - return ( - User.objects.filter(Q(is_banned=False) & Q(status=True)) - .all() - .values()[offset: offset + limit] - ) - - -@sync_to_async -def count_all_users_kwarg(**kwarg): - return User.objects.filter(**kwarg).all().values().count() - - -@sync_to_async -def update_setting(telegram_id: int, **kwargs): - return SettingModel.objects.filter(telegram_id=telegram_id).update(**kwargs) - - -@sync_to_async -def select_setting(telegram_id): - try: - return SettingModel.objects.get(telegram_id=telegram_id) - except Exception as ex: - print(f"Error in select_setting {ex}") - return SettingModel.objects.filter(telegram_id=telegram_id).values().first() - - -@sync_to_async -def add_user_to_settings(telegram_id: int): - return SettingModel(telegram_id=int(telegram_id)).save() - - -@sync_to_async -def select_setting_tech_work(): - return SettingModel.objects.filter(technical_works=True).values().first() - - -@sync_to_async -def check_returned_event_id(telegram_id: int, id_of_events_seen: int) -> bool: - """ - Function that checks if the given event_id was previously returned for the given telegram_id. - """ - returned_event = User.objects.filter(telegram_id=telegram_id).first() - event_list = returned_event.id_of_events_seen - - return str(id_of_events_seen) in event_list - - -@sync_to_async -def add_returned_event_id(telegram_id: int, id_of_events_seen: int): - """Function that adds the returned event_id for the given telegram_id to the database.""" - returned_event, created = User.objects.get_or_create(telegram_id=telegram_id) - returned_event.id_of_events_seen.append(id_of_events_seen) - returned_event.save() - - -@sync_to_async -def reset_view_limit(): - return User.objects.filter(limit_of_views__lt=10).update(limit_of_views=10) diff --git a/utils/faker.py b/utils/faker.py deleted file mode 100644 index e56f898..0000000 --- a/utils/faker.py +++ /dev/null @@ -1,82 +0,0 @@ -from datetime import ( - datetime, - timedelta, -) -import random - -import psycopg2 - -from data.config import ( - load_config, -) - -db_params = { - "host": load_config().db.host, - "database": load_config().db.database, - "user": load_config().db.user, - "password": load_config().db.password, -} - -cities = ["cities"] -photos = [ - "id of photos" -] - - -def create_users(num_users): - conn = psycopg2.connect(**db_params) - cursor = conn.cursor() - - for _ in range(num_users): - user_data = { - "created_at": datetime.now() - timedelta(days=random.randint(0, 365 * 5)), - "updated_at": datetime.now() - timedelta(days=random.randint(0, 365 * 5)), - "telegram_id": random.randint(10_000_000, 100_000_000), - "name": "User" + str(random.randint(1, 10000)), - "username": "user" + str(random.randint(1, 10000)), - "sex": random.choice(["Женский", "Мужской"]), - "age": random.randint(18, 80), - "city": random.choice(cities), - "need_city": random.choice(cities), - "longitude": random.uniform(-180, 180), - "latitude": random.uniform(-90, 90), - "verification": random.choice([True, False]), - "language": "en" if random.random() < 0.5 else "es", - "varname": "Var" + str(random.randint(1, 100)), - "lifestyle": None, - "is_banned": random.choice([True, False]), - "photo_id": random.choice(photos), - "commentary": "Comment" + str(random.randint(1, 100)), - "need_partner_sex": random.choice(["Мужской", "Женский"]), - "need_partner_age_min": random.randint(18, 80), - "need_partner_age_max": random.randint(18, 80), - "phone_number": None, - "status": True, - "instagram": "insta_" + str(random.randint(1, 10000)), - } - - insert_query = """ - INSERT INTO usersmanage_user ( - telegram_id, name, username, sex, age, city, need_city, - longitude, latitude, verification, language, varname, lifestyle, - is_banned, photo_id, commentary, need_partner_sex, need_partner_age_min, - need_partner_age_max, phone_number, status, instagram, created_at, updated_at - ) - VALUES ( - %(telegram_id)s, %(name)s, %(username)s, %(sex)s, %(age)s, %(city)s, - %(need_city)s, %(longitude)s, %(latitude)s, %(verification)s, %(language)s, - %(varname)s, %(lifestyle)s, %(is_banned)s, %(photo_id)s, %(commentary)s, - %(need_partner_sex)s, %(need_partner_age_min)s, %(need_partner_age_max)s, - %(phone_number)s, %(status)s, %(instagram)s, %(created_at)s, %(updated_at)s - ) - """ - - cursor.execute(insert_query, user_data) - conn.commit() - - cursor.close() - conn.close() - - -num_users_to_create = 500_000 -create_users(num_users_to_create) diff --git a/utils/jobs/__init__.py b/utils/jobs/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/jobs/autobackup.py b/utils/jobs/autobackup.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/jobs/autoupdate.py b/utils/jobs/autoupdate.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/logger.py b/utils/logger.py deleted file mode 100644 index ae97a17..0000000 --- a/utils/logger.py +++ /dev/null @@ -1,13 +0,0 @@ -import logging - -import betterlogging as bl - - -def setup_logger(level=logging.INFO, ignored=""): - bl.basic_colorized_config(level=level) - logging.basicConfig( - level=logging.INFO, - format="%(filename)s:%(lineno)d #%(levelname)-8s [%(asctime)s] - %(name)s - %(message)s", - ) - for ignore in ignored: - logging.getLogger(ignore).disabled = True diff --git a/utils/misc/__init__.py b/utils/misc/__init__.py deleted file mode 100644 index 467e60f..0000000 --- a/utils/misc/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .throttling import ( - rate_limit, -) diff --git a/utils/misc/ds_name.py b/utils/misc/ds_name.py deleted file mode 100644 index 29f23d3..0000000 --- a/utils/misc/ds_name.py +++ /dev/null @@ -1,13 +0,0 @@ -from aiogram import ( - types, -) -from aiogram.utils.markdown import ( - hbold, -) - - -def get_display_name(user: types.User) -> str: - if user.username: - return f"@{user.username}" - - return hbold(user.first_name) diff --git a/utils/misc/profanityFilter.py b/utils/misc/profanityFilter.py deleted file mode 100644 index 9a39be8..0000000 --- a/utils/misc/profanityFilter.py +++ /dev/null @@ -1,13 +0,0 @@ -from better_profanity import ( - profanity, -) - - -def censored_message(message: str) -> str: - """ - Get censored message. - - This function only works with English words. - """ - censored_text = profanity.censor(message) - return censored_text diff --git a/utils/misc/throttling.py b/utils/misc/throttling.py deleted file mode 100644 index 52dc542..0000000 --- a/utils/misc/throttling.py +++ /dev/null @@ -1,18 +0,0 @@ -def rate_limit(limit: int, key=None): - """ - Rate limit decorator. - - Decorator for configuring rate limit and key in different functions. - - :param limit: - :param key: - :return: - """ - - def decorator(func): - setattr(func, "throttling_rate_limit", limit) - if key: - setattr(func, "throttling_key", key) - return func - - return decorator diff --git a/utils/notify_admins.py b/utils/notify_admins.py deleted file mode 100644 index d3733f9..0000000 --- a/utils/notify_admins.py +++ /dev/null @@ -1,60 +0,0 @@ -from abc import ( - ABC, - abstractmethod, -) - -import aiogram -from aiogram import ( - Dispatcher, -) -import aiogram.utils.exceptions -from aiogram.utils.exceptions import ( - ChatNotFound, -) - -from data.config import ( - load_config, -) -from loader import ( - _, - bot, - logger, -) - - -class BaseNotification(ABC): - @abstractmethod - def send(self, *args): - pass - - -class AdminNotification(BaseNotification): - def __init__(self, dp: Dispatcher): - self.dp = dp - - async def send(self) -> None: - logger.info(_("Оповещение администрации...")) - for admin in load_config().tg_bot.admin_ids: - try: - await bot.send_message( - admin, _("Бот был успешно запущен"), disable_notification=True - ) - except ChatNotFound: - logger.debug("Чат с админом не найден") - - -class ErrorNotification(BaseNotification): - def __init__(self, error_message: Exception): - self.__error_message = error_message - - async def send(self) -> None: - text = ( - f"❗ Error During Operation ❗\n" - f"{self.__error_message}\n\n❗" - f" The bot will restart automatically." - ) - for user_id in load_config().tg_bot.admin_ids: - try: - await bot.send_message(user_id, text) - except (aiogram.exceptions.BotBlocked, aiogram.exceptions.ChatNotFound): - continue diff --git a/utils/set_bot_commands.py b/utils/set_bot_commands.py deleted file mode 100644 index 2b5f43d..0000000 --- a/utils/set_bot_commands.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging - -from aiogram import ( - Dispatcher, - types, -) - -from data.config import ( - load_config, -) - - -async def set_user_commands( - dp: Dispatcher, user_id: int, commands: list[types.BotCommand] -): - try: - await dp.bot.set_my_commands( - commands=commands, scope=types.BotCommandScopeChat(user_id) - ) - except Exception as ex: - logging.error(f"{user_id}: Commands are not installed. {ex}") - - -async def set_default_commands(dp: Dispatcher) -> None: - default_commands = [ - types.BotCommand("start", "🟢 Запустить бота"), - ] - - admin_commands = [ - types.BotCommand("admin", "⚒ Админ-Меню"), - types.BotCommand("users", "🫂 Пользователи"), - types.BotCommand("settings", "⚙️ Настройки"), - types.BotCommand("ad", "📊 Реклама"), - types.BotCommand("logs", "🗒 Логи"), - ] - - await dp.bot.set_my_commands(default_commands, scope=types.BotCommandScopeDefault()) - - for admin_id in load_config().tg_bot.admin_ids: - await set_user_commands(dp, admin_id, admin_commands + default_commands) diff --git a/utils/yoomoney/__init__.py b/utils/yoomoney/__init__.py deleted file mode 100644 index 7ebc8e3..0000000 --- a/utils/yoomoney/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .authorization import ( - authorize_app, -) -from .wallet import ( - YooMoneyWallet, -) diff --git a/utils/yoomoney/authorization.py b/utils/yoomoney/authorization.py deleted file mode 100644 index b1af35c..0000000 --- a/utils/yoomoney/authorization.py +++ /dev/null @@ -1,36 +0,0 @@ -from utils.yoomoney.request import ( - send_request, -) - -AUTH_APP_URL = ( - "https://yoomoney.ru/oauth/authorize?client_id={client_id}&response_type=code" - "&redirect_uri={redirect_uri}&scope={permissions}" -) - -GET_TOKEN_URL = ( - "https://yoomoney.ru/oauth/token?code={code}&client_id={client_id}&" - "grant_type=authorization_code&redirect_uri={redirect_uri}" -) - - -async def authorize_app(client_id, redirect_uri, app_permissions: list[str, ...]): - formatted_auth_app_url = AUTH_APP_URL.format( - client_id=client_id, - redirect_uri=redirect_uri, - permissions="%20".join(app_permissions), - ) - response = await send_request(formatted_auth_app_url, response_without_data=True) - - print(f"Перейдите по URL и подтвердите доступ для приложения\n{response.url}") - code = input("Введите код в консоль > ").strip() - - get_token_url = GET_TOKEN_URL.format( - code=code, client_id=client_id, redirect_uri=redirect_uri - ) - _, data = await send_request(get_token_url) - - access_token = data.get("access_token") - if not access_token: - return print(f"Не удалось получить токен. {data.get('error', '')}") - - return print(f"Ваш токен — {access_token}. Сохраните его в безопасном месте!") diff --git a/utils/yoomoney/exceptions.py b/utils/yoomoney/exceptions.py deleted file mode 100644 index cce856a..0000000 --- a/utils/yoomoney/exceptions.py +++ /dev/null @@ -1,6 +0,0 @@ -class UnresolvedRequestMethod(Exception): - pass - - -class BadResponse(Exception): - pass diff --git a/utils/yoomoney/get_token.py b/utils/yoomoney/get_token.py deleted file mode 100644 index 5437a1b..0000000 --- a/utils/yoomoney/get_token.py +++ /dev/null @@ -1,27 +0,0 @@ -import asyncio - -from data.config import ( - load_config, -) -from utils.yoomoney import ( - authorize_app, -) - - -async def main(): - await authorize_app( - client_id=load_config().misc.client_id, - redirect_uri=load_config().misc.redirect_url, - app_permissions=[ - "account-info", - "operation-history", - "operation-details", - "incoming-transfers", - "payment-p2p", - "payment-shop", - ], - ) - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/utils/yoomoney/request.py b/utils/yoomoney/request.py deleted file mode 100644 index f690eab..0000000 --- a/utils/yoomoney/request.py +++ /dev/null @@ -1,54 +0,0 @@ -from aiohttp import ( - ClientResponse, - ClientSession, -) -from aiohttp.client_exceptions import ( - ContentTypeError, -) - -from utils.yoomoney.exceptions import ( - BadResponse, - UnresolvedRequestMethod, -) - -ALLOWED_METHODS = ("post", "get") - - -async def send_request( - url: str, method: str = "post", response_without_data: bool = False, **kwargs -) -> (ClientResponse, dict | None): - headers = {"Content-Type": "application/x-www-form-urlencoded"} - if add_headers := kwargs.pop("headers", {}): - headers |= add_headers - - method = method.lower().strip() - await check_method(method) - - async with ClientSession() as session: - async with getattr(session, method)(url, headers=headers, **kwargs) as response: - await post_handle_response(response) - - if response_without_data: - return response - - return response, await response.json() - - -async def check_method(method: str): - if method not in ALLOWED_METHODS: - raise UnresolvedRequestMethod - - -async def post_handle_response(response: ClientResponse): - try: - response_data = await response.json() - if isinstance(response_data, dict) and response_data.get("error"): - raise BadResponse( - f"error — {response_data.get('error')}, response is {response}" - ) - - except ContentTypeError: - pass - - if response.status >= 400: - raise BadResponse(response) diff --git a/utils/yoomoney/types/__init__.py b/utils/yoomoney/types/__init__.py deleted file mode 100644 index a4a57fe..0000000 --- a/utils/yoomoney/types/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .account_info import ( - AccountInfo, -) -from .operation_details import ( - OperationDetails, -) -from .operation_history import ( - Operation, -) -from .payment import ( - PaymentForm, - PaymentSource, -) diff --git a/utils/yoomoney/types/account_info.py b/utils/yoomoney/types/account_info.py deleted file mode 100644 index 1dec5a3..0000000 --- a/utils/yoomoney/types/account_info.py +++ /dev/null @@ -1,34 +0,0 @@ -from pydantic import ( - BaseModel, - Field, -) - - -class BalanceDetails(BaseModel): - total: int - available: int - deposition_pending: int | None - blocked: int | None - debt: int | None - hold: int | None - - -class LinkedCard(BaseModel): - pan_fragment: str - card_type: str = Field(None, alias="type") - - -class AccountInfo(BaseModel): - """ - Получение информации о состоянии счета пользователя. - - https://yoomoney.ru/docs/wallet/user-account/account-info - """ - - account: str # номер счета - balance: int # баланс счета - currency: str # код валюты счета - account_status: str - account_type: str - balance_details: BalanceDetails | None - cards_linked: list[LinkedCard, ...] | None diff --git a/utils/yoomoney/types/operation_details.py b/utils/yoomoney/types/operation_details.py deleted file mode 100644 index cab8efb..0000000 --- a/utils/yoomoney/types/operation_details.py +++ /dev/null @@ -1,38 +0,0 @@ -from datetime import ( - datetime, -) -from typing import ( - Literal, -) - -from pydantic import ( - BaseModel, - Field, -) - - -class OperationDetails(BaseModel): - """ - Детальная информация об операции из истории. - - https://yoomoney.ru/docs/wallet/user-account/operation-details - """ - - error: str | None - operation_id: str - status: str - pattern_id: str | None - direction: Literal["in"] | Literal["out"] - amount: int - amount_due: int | None - fee: int | None - operation_datetime: datetime = Field(alias="datetime") - title: str - sender: int | None - recipient: str | None - recipient_type: str | None - message: str | None - comment: str | None - label: str | None - details: str | None - operation_type: str = Field(alias="type") diff --git a/utils/yoomoney/types/operation_history.py b/utils/yoomoney/types/operation_history.py deleted file mode 100644 index 6155bf7..0000000 --- a/utils/yoomoney/types/operation_history.py +++ /dev/null @@ -1,29 +0,0 @@ -from datetime import ( - datetime, -) -from typing import ( - Literal, -) - -from pydantic import ( - BaseModel, - Field, -) - - -class Operation(BaseModel): - """ - Описание платежной операции. - - https://yoomoney.ru/docs/wallet/user-account/operation-history#response-operation - """ - - operation_id: str - status: str - execution_datetime: datetime = Field(alias="datetime") - title: str - pattern_id: str | None - direction: Literal["in"] | Literal["out"] - amount: int - label: str | None - operation_type: str = Field(alias="type") diff --git a/utils/yoomoney/types/payment.py b/utils/yoomoney/types/payment.py deleted file mode 100644 index 3639fce..0000000 --- a/utils/yoomoney/types/payment.py +++ /dev/null @@ -1,15 +0,0 @@ -from dataclasses import ( - dataclass, -) - - -@dataclass(frozen=True, slots=True) -class PaymentSource: - BANK_CARD = "AC" - YOOMONEY_WALLET = "PC" - - -@dataclass(frozen=True, slots=True) -class PaymentForm: - link_for_customer: str - payment_label: str diff --git a/utils/yoomoney/wallet.py b/utils/yoomoney/wallet.py deleted file mode 100644 index b7603d4..0000000 --- a/utils/yoomoney/wallet.py +++ /dev/null @@ -1,87 +0,0 @@ -from utils.yoomoney.request import ( - send_request, -) -from utils.yoomoney.types import ( - AccountInfo, - Operation, - OperationDetails, - PaymentForm, - PaymentSource, -) - - -class YooMoneyWallet: - def __init__(self, access_token: str): - self.host = "https://yoomoney.ru" - self.__headers = dict(Authorization=f"Bearer {access_token}") - - @property - async def account_info(self) -> AccountInfo: - url = self.host + "/api/account-info" - response, data = await send_request(url, headers=self.__headers) - return AccountInfo.parse_obj(data) - - async def get_operation_details(self, operation_id: str) -> OperationDetails: - url = self.host + "/api/operation-details" - response, data = await send_request( - url, headers=self.__headers, data={"operation_id": operation_id} - ) - return OperationDetails.parse_obj(data) - - async def get_operation_history( - self, label: str | None = None - ) -> list[Operation, ...]: - """ - Получение последних 30 операций. - - На 10.03.2023 API yoomoney напросто игнорирует указанные в документации параметры - - https://yoomoney.ru/docs/payment-buttons/using-api/forms?lang=ru#parameters - """ - history_url = self.host + "/api/operation-history" - response, data = await send_request(history_url, headers=self.__headers) - if operations := data.get("operations"): - parsed = [Operation.parse_obj(operation) for operation in operations] - if label: - parsed = [operation for operation in parsed if operation.label == label] - return parsed - - async def create_payment_form( - self, - amount_rub: int, - unique_label: str, - success_redirect_url: str | None = None, - payment_source: PaymentSource = PaymentSource.BANK_CARD, - ) -> PaymentForm: - account_info = await self.account_info - quickpay_url = "https://yoomoney.ru/quickpay/confirm.xml?" - params = { - "receiver": account_info.account, - "quickpay-form": "button", - "paymentType": payment_source, - "sum": amount_rub, - "successURL": success_redirect_url, - "label": unique_label, - } - params = {k: v for k, v in params.items() if v} - response = await send_request( - quickpay_url, response_without_data=True, params=params - ) - - return PaymentForm( - link_for_customer=str(response.url), payment_label=unique_label - ) - - async def check_payment_on_successful(self, label: str) -> bool: - need_operations = await self.get_operation_history(label=label) - return bool(need_operations) and need_operations.pop().status == "success" - - async def revoke_token(self) -> None: - url = self.host + "/api/revoke" - response = await send_request( - url=url, response_without_data=True, headers=self.__headers - ) - print( - f"Запрос на отзыв токена завершен с кодом {response.status} " - "https://yoomoney.ru/docs/wallet/using-api/authorization/revoke-access-token#response" - )