diff --git a/.gitignore b/.gitignore index e6175e54..c585ef47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # Папки __pycache__/ node_modules/ -webpack_stats/ +/constructor_telegram_bots/static/frontend/ .vscode/ /static/ media/ @@ -11,7 +11,7 @@ dist/ # Файлы celerybeat-schedule -*.webpack.stats.json +webpack.stats.json .env *.db *.mo \ No newline at end of file diff --git a/constructor_telegram_bots/__init__.py b/constructor_telegram_bots/__init__.py index ab58a1b9..a4e666db 100644 --- a/constructor_telegram_bots/__init__.py +++ b/constructor_telegram_bots/__init__.py @@ -1,4 +1,4 @@ from constructor_telegram_bots.celery import celery_app -__all__ = ('celery_app',) +__all__ = ('celery_app',) \ No newline at end of file diff --git a/constructor_telegram_bots/asgi.py b/constructor_telegram_bots/asgi.py index 04b5aa03..5fb7eb93 100644 --- a/constructor_telegram_bots/asgi.py +++ b/constructor_telegram_bots/asgi.py @@ -5,4 +5,4 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'constructor_telegram_bots.settings') -application = get_asgi_application() +application = get_asgi_application() \ No newline at end of file diff --git a/constructor_telegram_bots/celery.py b/constructor_telegram_bots/celery.py index 34bacaa5..28605140 100644 --- a/constructor_telegram_bots/celery.py +++ b/constructor_telegram_bots/celery.py @@ -13,4 +13,4 @@ def celery_after_setup(*args, **kwargs) -> None: from telegram_bot.tasks import start_all_telegram_bots as celery_start_all_telegram_bots - celery_start_all_telegram_bots.delay() + celery_start_all_telegram_bots.delay() \ No newline at end of file diff --git a/constructor_telegram_bots/context_processors.py b/constructor_telegram_bots/context_processors.py deleted file mode 100644 index 8b51efd4..00000000 --- a/constructor_telegram_bots/context_processors.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf import settings - - -def constructor_telegram_bot_username(*args, **kwargs) -> dict[str, str]: - return {'constructor_telegram_bot_username': settings.CONSTRUCTOR_TELEGRAM_BOT_USERNAME} diff --git a/constructor_telegram_bots/environment.py b/constructor_telegram_bots/environment.py index 749a9025..e025172f 100644 --- a/constructor_telegram_bots/environment.py +++ b/constructor_telegram_bots/environment.py @@ -72,4 +72,4 @@ def replace_text_variables_to_jinja_variables_values(telegram_bot, text: str, ji }).json()['response'] async def areplace_text_variables_to_jinja_variables_values(telegram_bot, text: str, jinja_variables: dict[str, Any]) -> str: - return await sync_to_async(replace_text_variables_to_jinja_variables_values)(telegram_bot, text, jinja_variables) + return await sync_to_async(replace_text_variables_to_jinja_variables_values)(telegram_bot, text, jinja_variables) \ No newline at end of file diff --git a/constructor_telegram_bots/exception_formatter.py b/constructor_telegram_bots/exception_formatter.py index 106d7e0d..0c7375e6 100644 --- a/constructor_telegram_bots/exception_formatter.py +++ b/constructor_telegram_bots/exception_formatter.py @@ -19,4 +19,4 @@ def format_error_response(self, error_response: ErrorResponse) -> FormatErrorRes 'name': error.attr, 'message': error.detail, 'level': 'danger', - } + } \ No newline at end of file diff --git a/constructor_telegram_bots/gunicorn_config.py b/constructor_telegram_bots/gunicorn_config.py index 569a764a..d8c0dbb9 100644 --- a/constructor_telegram_bots/gunicorn_config.py +++ b/constructor_telegram_bots/gunicorn_config.py @@ -7,4 +7,4 @@ capture_output = True accesslog = str(BASE_DIR / 'logs/gunicorn_info.log') -errorlog = str(BASE_DIR / 'logs/gunicorn_info.log') +errorlog = str(BASE_DIR / 'logs/gunicorn_info.log') \ No newline at end of file diff --git a/constructor_telegram_bots/settings.py b/constructor_telegram_bots/settings.py index e7cacd13..e7133e21 100644 --- a/constructor_telegram_bots/settings.py +++ b/constructor_telegram_bots/settings.py @@ -33,12 +33,6 @@ SITE_DOMAIN = 'http://127.0.0.1:8000' if DEBUG else 'https://constructor.exg1o.org' ALLOWED_HOSTS = ['127.0.0.1', 'constructor.exg1o.org'] -CSRF_TRUSTED_ORIGINS = [ - 'http://*.127.0.0.1', - 'https://*.127.0.0.1', - 'http://constructor.exg1o.org', - 'https://constructor.exg1o.org', -] CELERY_BROKER_URL = 'redis://127.0.0.1:6379' @@ -74,52 +68,22 @@ 'django.contrib.messages', 'django.contrib.staticfiles', + 'user', 'telegram_bot', - 'telegram_bot.frontend', - 'telegram_bot.api', + 'plugin', - 'user', - 'home', 'team', 'updates', 'instruction', 'donation', - 'personal_cabinet', - 'plugin', 'privacy_policy', ] -WEBPACK_LOADER_BASE_CONFIG = { - 'CACHE': not DEBUG, - 'POLL_INTERVAL': 0.1, -} WEBPACK_LOADER = { - 'DEFAULT': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/default.webpack.stats.json', - }, - 'HOME:INDEX': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/index.home.webpack.stats.json', - }, - 'TEAM:INDEX': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/index.team.webpack.stats.json', - }, - 'PERSONAL_CABINET:INDEX': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/index.personal-cabinet.webpack.stats.json', - }, - 'TELEGRAM_BOT_MENU:DEFAULT': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/default.telegram-bot-menu.webpack.stats.json', - }, - 'TELEGRAM_BOT_MENU:INDEX': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/index.telegram-bot-menu.webpack.stats.json', - }, - 'TELEGRAM_BOT_MENU:VARIABLES': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/variables.telegram-bot-menu.webpack.stats.json', - }, - 'TELEGRAM_BOT_MENU:USERS': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/users.telegram-bot-menu.webpack.stats.json', - }, - 'TELEGRAM_BOT_MENU:DATABASE': WEBPACK_LOADER_BASE_CONFIG | { - 'STATS_FILE': BASE_DIR / 'webpack_stats/database.telegram-bot-menu.webpack.stats.json', + 'INDEX': { + 'CACHE': not DEBUG, + 'POLL_INTERVAL': 0.1, + 'STATS_FILE': BASE_DIR / 'frontend/webpack.stats.json', }, } @@ -157,13 +121,11 @@ ] REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', - 'rest_framework.authentication.SessionAuthentication', - ], 'EXCEPTION_HANDLER': 'drf_standardized_errors.handler.exception_handler', } -DRF_STANDARDIZED_ERRORS = {'EXCEPTION_FORMATTER_CLASS': 'constructor_telegram_bots.exception_formatter.CustomExceptionFormatter'} +DRF_STANDARDIZED_ERRORS = { + 'EXCEPTION_FORMATTER_CLASS': 'constructor_telegram_bots.exception_formatter.CustomExceptionFormatter', +} TEMPLATES = [ @@ -177,8 +139,6 @@ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', - - 'constructor_telegram_bots.context_processors.constructor_telegram_bot_username', ], }, }, @@ -222,7 +182,10 @@ STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static' -STATICFILES_DIRS = [BASE_DIR / 'constructor_telegram_bots/static'] +STATICFILES_DIRS = [ + BASE_DIR / 'constructor_telegram_bots/static', + BASE_DIR / 'frontend/dist', +] MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'media' @@ -299,4 +262,4 @@ 'propagate': True, }, }, -} +} \ No newline at end of file diff --git a/constructor_telegram_bots/static/default/src/logout.ts b/constructor_telegram_bots/static/default/src/logout.ts deleted file mode 100644 index 658f6110..00000000 --- a/constructor_telegram_bots/static/default/src/logout.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { askConfirmModal } from 'global_modules/modals/ask_confirm_modal'; - -declare const userIsAuth: boolean; -declare const userLogoutUrl: string; -declare const userLogoutAskConfirmModalTitle: string; -declare const userLogoutAskConfirmModalText: string; - -if (userIsAuth) { - document.querySelector('#userLogoutButton')!.addEventListener('click', (): void => { - askConfirmModal( - userLogoutAskConfirmModalTitle, - userLogoutAskConfirmModalText, - (): string => window.location.href = userLogoutUrl, - ); - }); -} \ No newline at end of file diff --git a/constructor_telegram_bots/static/default/src/main.ts b/constructor_telegram_bots/static/default/src/main.ts deleted file mode 100644 index 549030fa..00000000 --- a/constructor_telegram_bots/static/default/src/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -import 'bootstrap'; -import 'bootstrap/dist/css/bootstrap.min.css'; -import 'bootstrap-icons/font/bootstrap-icons.min.css'; - -import './logout'; -import './modals/login_via_telegram_modal'; \ No newline at end of file diff --git a/constructor_telegram_bots/static/default/src/modals/login_via_telegram_modal.ts b/constructor_telegram_bots/static/default/src/modals/login_via_telegram_modal.ts deleted file mode 100644 index d907cf0c..00000000 --- a/constructor_telegram_bots/static/default/src/modals/login_via_telegram_modal.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Modal } from 'bootstrap'; -import QRCode from 'qrcode'; - -declare const userIsAuth: boolean; - -if (!userIsAuth) { - const modal = new Modal('#loginViaTelegramModal'); - const modalToggleButtonElement = document.querySelector('#loginViaTelegramModalButton')!; - - QRCode.toCanvas( - document.querySelector('#loginViaTelegramModal .qrcode'), - modalToggleButtonElement.href, - {width: 256, margin: 0}, - ); - - modalToggleButtonElement.addEventListener('click', (): void => modal.toggle()); - - if (new URLSearchParams(window.location.search).has('require-login')) { - modalToggleButtonElement.click(); - } -} \ No newline at end of file diff --git a/constructor_telegram_bots/static/global_modules/api.ts b/constructor_telegram_bots/static/global_modules/api.ts deleted file mode 100644 index 6911d06e..00000000 --- a/constructor_telegram_bots/static/global_modules/api.ts +++ /dev/null @@ -1,48 +0,0 @@ -export type ObjectAsJson = Record; - -export namespace ApiResponse { - export interface Base extends Omit { - ok: Ok; - json: Json; - } - export interface Success { - message: string; - level: 'success' | 'primary'; - } - export interface Error { - code: string; - name: string | null; - message: string; - level: 'danger'; - } - - export type Default = Base | Base; -} - -export async function makeRequest( - url: string, - method: 'POST' | 'PATCH' | 'DELETE' | 'GET', - headers?: HeadersInit, - data?: ObjectAsJson | FormData, -): Promise> { - let requestInit: RequestInit = {method: method} - - if (data) { - if (data instanceof FormData) { - requestInit = Object.assign(requestInit, {body: data}); - } else { - requestInit = Object.assign(requestInit, { - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify(data), - }); - } - } - - if (requestInit.headers || headers) { - requestInit = Object.assign(requestInit, {headers: Object.assign({}, requestInit.headers || {}, headers || {})}); - } - - const response = await fetch(url, requestInit); - - return Object.assign(response, {json: await response.json()}); -} \ No newline at end of file diff --git a/constructor_telegram_bots/static/global_modules/jsi18n.d.ts b/constructor_telegram_bots/static/global_modules/jsi18n.d.ts deleted file mode 100644 index f62f8b4d..00000000 --- a/constructor_telegram_bots/static/global_modules/jsi18n.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -declare function pluralidx(n: number): number; -declare function gettext(msgid: string): string; -declare function ngettext(singular: string, plural: string, count: number): string; -declare function gettext_noop(msgid: string): string; -declare function pgettext(context: string, msgid: string): string; -declare function npgettext(context: string, singular: string, plural: string, count: number): string; -declare function interpolate(fmt: string, obj: Record, named: boolean): string; -declare function get_format(format_type: string): string; -declare const jsi18n_initialized: boolean; \ No newline at end of file diff --git a/constructor_telegram_bots/static/global_modules/modals/ask_confirm_modal.ts b/constructor_telegram_bots/static/global_modules/modals/ask_confirm_modal.ts deleted file mode 100644 index 770b5ad6..00000000 --- a/constructor_telegram_bots/static/global_modules/modals/ask_confirm_modal.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Modal } from 'bootstrap'; - -const modal = new Modal('#askConfirmModal'); -const titleElement = document.querySelector('#askConfirmModalTitle')!; -const bodyElement = document.querySelector('#askConfirmModalBody')!; -const yesButtonElement = document.querySelector('#askConfirmModalYesButton')!; - -yesButtonElement.addEventListener('click', (): void => modal.toggle()); - -export function askConfirmModal(title: string, body: string, func: () => any): void { - titleElement.innerHTML = title; - bodyElement.innerHTML = body; - - if (yesButtonElement.onclick) { - yesButtonElement.removeEventListener('click', yesButtonElement.onclick); - } - yesButtonElement.onclick = func; - - modal.toggle(); -} \ No newline at end of file diff --git a/constructor_telegram_bots/static/global_modules/monaco_editor.ts b/constructor_telegram_bots/static/global_modules/monaco_editor.ts deleted file mode 100644 index 6bf65c34..00000000 --- a/constructor_telegram_bots/static/global_modules/monaco_editor.ts +++ /dev/null @@ -1,21 +0,0 @@ -import monaco from 'monaco-editor'; - -export function updateEditorLayout( - monacoEditor: monaco.editor.IStandaloneCodeEditor, - shouldResetWidth: boolean = false, -): void { - monacoEditor.layout({ - width: shouldResetWidth ? 0 : monacoEditor.getContainerDomNode().getBoundingClientRect().width, - height: (monacoEditor.getModel() as monaco.editor.ITextModel).getLineCount() * 19, - }); -} - -export const defaultEditorOptions: monaco.editor.IStandaloneEditorConstructionOptions = { - minimap: {enabled: false}, - renderLineHighlight: 'none', - lineNumbersMinChars: 3, - overviewRulerLanes: 0, - scrollBeyondLastLine: false, - scrollbar: {vertical: 'hidden'}, - inlayHints: {enabled: 'off'}, -} \ No newline at end of file diff --git a/constructor_telegram_bots/static/global_modules/toast.ts b/constructor_telegram_bots/static/global_modules/toast.ts deleted file mode 100644 index 48485b26..00000000 --- a/constructor_telegram_bots/static/global_modules/toast.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Toast as BaseToast } from 'bootstrap'; - -const containerElement = document.querySelector('#toastContainer')!; -const icons = { - success: 'check-circle-fill', - primary: 'info-circle-fill', - danger: 'exclamation-triangle-fill', -} - -export default class Toast extends BaseToast { - public element: HTMLDivElement; - - public constructor(message: string, level: keyof typeof icons, delay: number = 6000) { - const element = document.createElement('div'); - element.className = `toast text-bg-${level} mb-0 fade`; - element.role = 'alert'; - element.setAttribute('aria-live', 'assertive'); - element.setAttribute('aria-atomic', 'true'); - element.innerHTML = ` -
- - ${message} - -
- `; - containerElement.appendChild(element); - - super(element, {autohide: level !== 'danger', delay: delay}); - - this.element = element; - this.element.addEventListener('hidden.bs.toast', () => this.element.remove()); - } -} \ No newline at end of file diff --git a/constructor_telegram_bots/templates/404.html b/constructor_telegram_bots/templates/404.html deleted file mode 100644 index 727ab723..00000000 --- a/constructor_telegram_bots/templates/404.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'base_success_or_error.html' %} -{% load i18n %} - -{% block title %}{% trans 'Страница не найдена' %}{% endblock title %} - -{% block meta_refresh_url %}{% url 'home:index' %}{% endblock meta_refresh_url %} - -{% block content_heading %}{% trans 'Ошибка 404!' %}{% endblock content_heading %} -{% block content_text %}{% trans 'Страница не найдена, автоматический переход на главную страницу через 3 секунды.' %}{% endblock content_text %} \ No newline at end of file diff --git a/constructor_telegram_bots/templates/admin/base_site.html b/constructor_telegram_bots/templates/admin/base_site.html index 045c2a69..e18c35b8 100644 --- a/constructor_telegram_bots/templates/admin/base_site.html +++ b/constructor_telegram_bots/templates/admin/base_site.html @@ -16,7 +16,7 @@ {% block welcome-msg %}{% endblock welcome-msg %} {% block userlinks %} -{% trans 'Вернуться на сайт' %} / +{% trans 'Вернуться на сайт' %} / {% trans 'Выйти' %} /
{% csrf_token %} diff --git a/constructor_telegram_bots/templates/admin/login.html b/constructor_telegram_bots/templates/admin/login.html index 84f61fa4..b3ef9b4a 100644 --- a/constructor_telegram_bots/templates/admin/login.html +++ b/constructor_telegram_bots/templates/admin/login.html @@ -1,5 +1 @@ -{% extends 'base.html' %} - -{% block meta %} - -{% endblock meta %} \ No newline at end of file + \ No newline at end of file diff --git a/constructor_telegram_bots/templates/base.html b/constructor_telegram_bots/templates/base.html deleted file mode 100644 index a7c7c8d1..00000000 --- a/constructor_telegram_bots/templates/base.html +++ /dev/null @@ -1,71 +0,0 @@ -{% load static %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - - -{% get_current_language as LANGUAGE_CODE %} - - - - - - {% block title %}{% endblock title %} - Constructor Telegram Bots - - - - - - - {% block meta %}{% endblock meta %} - - - - {% block styles %} - {% render_bundle 'main' 'css' 'DEFAULT' %} - {% endblock styles %} - - - - {% block navbar %} - {% include 'navbar.html' with extra_class=navbar_extra_class %} - {% endblock navbar %} - - {% block modals %} - {% if user.is_authenticated %} - {% include 'modals/ask_confirm_modal.html' %} - {% else %} - {% include 'modals/login_via_telegram_modal.html' %} - {% endif %} - {% endblock modals %} - -
- -
- {% block main %}{% endblock main %} -
- - {% block footer %} - {% include 'footer.html' with extra_class=footer_extra_class %} - {% endblock footer %} - - - - - - - {% block scripts %} - {% render_bundle 'main' 'js' 'DEFAULT' %} - {% endblock scripts %} - \ No newline at end of file diff --git a/constructor_telegram_bots/templates/base_success_or_error.html b/constructor_telegram_bots/templates/base_success_or_error.html deleted file mode 100644 index 12af8bb9..00000000 --- a/constructor_telegram_bots/templates/base_success_or_error.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}{{ title }}{% endblock title %} - -{% block meta %} - -{% endblock meta %} - -{% block main %} -
-
-
-

{% block content_heading %}{{ content.heading }}{% endblock content_heading %}

-

{% block content_text %}{{ content.text }}{% endblock content_text %}

-
-
-
-{% endblock main %} \ No newline at end of file diff --git a/constructor_telegram_bots/templates/footer.html b/constructor_telegram_bots/templates/footer.html deleted file mode 100644 index 6a87fb9c..00000000 --- a/constructor_telegram_bots/templates/footer.html +++ /dev/null @@ -1,26 +0,0 @@ -{% load i18n %} - - \ No newline at end of file diff --git a/constructor_telegram_bots/templates/index.html b/constructor_telegram_bots/templates/index.html new file mode 100644 index 00000000..a3bd5059 --- /dev/null +++ b/constructor_telegram_bots/templates/index.html @@ -0,0 +1,35 @@ +{% load static %} +{% load i18n %} +{% load render_bundle from webpack_loader %} + + +{% get_current_language as LANGUAGE_CODE %} + + + + + + Constructor Telegram Bots + + + + + + + + + {% block styles %} + {% render_bundle 'main' 'css' 'INDEX' %} + {% endblock styles %} + + + +
+ + + + {% block scripts %} + {% render_bundle 'main' 'js' 'INDEX' %} + {% endblock scripts %} + + \ No newline at end of file diff --git a/constructor_telegram_bots/templates/modals/ask_confirm_modal.html b/constructor_telegram_bots/templates/modals/ask_confirm_modal.html deleted file mode 100644 index f51cf43b..00000000 --- a/constructor_telegram_bots/templates/modals/ask_confirm_modal.html +++ /dev/null @@ -1,19 +0,0 @@ -{% load i18n %} - -{% with modal_id='askConfirmModal' %} - -{% endwith %} \ No newline at end of file diff --git a/constructor_telegram_bots/templates/modals/login_via_telegram_modal.html b/constructor_telegram_bots/templates/modals/login_via_telegram_modal.html deleted file mode 100644 index 437d5bd0..00000000 --- a/constructor_telegram_bots/templates/modals/login_via_telegram_modal.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load i18n %} - - \ No newline at end of file diff --git a/constructor_telegram_bots/templates/navbar.html b/constructor_telegram_bots/templates/navbar.html deleted file mode 100644 index f502b6e2..00000000 --- a/constructor_telegram_bots/templates/navbar.html +++ /dev/null @@ -1,62 +0,0 @@ -{% load i18n %} - -
\ No newline at end of file diff --git a/constructor_telegram_bots/templates/widgets/add_button.html b/constructor_telegram_bots/templates/widgets/add_button.html deleted file mode 100644 index 57acef32..00000000 --- a/constructor_telegram_bots/templates/widgets/add_button.html +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/constructor_telegram_bots/templates/widgets/info_area.html b/constructor_telegram_bots/templates/widgets/info_area.html deleted file mode 100644 index 5ed2175b..00000000 --- a/constructor_telegram_bots/templates/widgets/info_area.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
{{ value }}
- {{ text }} -
\ No newline at end of file diff --git a/constructor_telegram_bots/urls.py b/constructor_telegram_bots/urls.py index 6f8394d7..f5e343c7 100644 --- a/constructor_telegram_bots/urls.py +++ b/constructor_telegram_bots/urls.py @@ -1,10 +1,9 @@ -from django.urls import path, include +from django.urls import path, re_path, include from django.contrib import admin from django.views.i18n import JavaScriptCatalog +from django.views.generic import TemplateView from django.conf import settings -import sys - urlpatterns = [ path('admin/', admin.site.urls), @@ -13,28 +12,23 @@ path('tinymce/', include('tinymce.urls')), - path('user/', include('user.urls')), - path('', include('home.urls')), - path('team/', include('team.urls')), - path('updates/', include('updates.urls')), - path('instruction/', include('instruction.urls')), - path('donation/', include('donation.urls')), - path('personal-cabinet/', include('personal_cabinet.urls')), - path('', include('telegram_bot.urls')), - path('plugins/', include('plugin.urls')), - path('privacy-policy/', include('privacy_policy.urls')), -] + path('api/', include([ + path('', include('user.urls')), + path('telegram-bots/', include('telegram_bot.urls')), + path('plugins/', include('plugin.urls')), + + path('team/', include('team.urls')), + path('', include('updates.urls')), + path('donations/', include('donation.urls')), + path('instruction/', include('instruction.urls')), + path('privacy-policy/', include('privacy_policy.urls')), + ])), + re_path(r'^.*', TemplateView.as_view(template_name='index.html')), +] if settings.DEBUG: from django.conf.urls.static import static urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - -if sys.platform == 'win32': - match sys.argv: - case ['manage.py', 'runserver', *extra_options]: - from telegram_bot.tasks import start_all_telegram_bots as celery_start_all_telegram_bots - - celery_start_all_telegram_bots() + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/constructor_telegram_bots/utils/admin.py b/constructor_telegram_bots/utils/admin.py index 4ba9cd3d..b9783c4f 100644 --- a/constructor_telegram_bots/utils/admin.py +++ b/constructor_telegram_bots/utils/admin.py @@ -5,4 +5,4 @@ def format_html_url(url: str, text: str | None = None) -> str: if text is None: text = url - return format_html(f'{text}') + return format_html(f'{text}') \ No newline at end of file diff --git a/constructor_telegram_bots/utils/drf.py b/constructor_telegram_bots/utils/drf.py index 26f66adc..8ef06e59 100644 --- a/constructor_telegram_bots/utils/drf.py +++ b/constructor_telegram_bots/utils/drf.py @@ -24,4 +24,4 @@ def __init__( data['message'] = message data['level'] = level - super().__init__(data, status, headers=headers) + super().__init__(data, status, headers=headers) \ No newline at end of file diff --git a/constructor_telegram_bots/utils/other.py b/constructor_telegram_bots/utils/other.py index dbd460c9..f573d1d6 100644 --- a/constructor_telegram_bots/utils/other.py +++ b/constructor_telegram_bots/utils/other.py @@ -2,4 +2,4 @@ def generate_random_string(length: int, chars: str) -> str: - return ''.join([random.choice(chars) for _ in range(length)]) + return ''.join([random.choice(chars) for _ in range(length)]) \ No newline at end of file diff --git a/constructor_telegram_bots/utils/shortcuts.py b/constructor_telegram_bots/utils/shortcuts.py deleted file mode 100644 index c1881c61..00000000 --- a/constructor_telegram_bots/utils/shortcuts.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.http import HttpRequest, HttpResponse -from django import urls -from django.utils.translation import gettext as _ -from django.shortcuts import render - -from rest_framework.status import is_success - - -def render_success_or_error( - request: HttpRequest, - heading: str, - text: str, - redirect_to_url: str | None = None, - status: int = 200, -) -> HttpResponse: - if redirect_to_url is None: - redirect_to_url = urls.reverse('home') - - if is_success(status): - title = _('Успех') - else: - title = _('Ошибка') - - return render(request, 'base_success_or_error.html', { - 'title': title, - 'meta': {'refresh': {'url': redirect_to_url}}, - 'content': {'heading': heading, 'text': text}, - }, status=status) diff --git a/constructor_telegram_bots/wsgi.py b/constructor_telegram_bots/wsgi.py index 1ee29238..65ecf829 100644 --- a/constructor_telegram_bots/wsgi.py +++ b/constructor_telegram_bots/wsgi.py @@ -5,4 +5,4 @@ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'constructor_telegram_bots.settings') -application = get_wsgi_application() +application = get_wsgi_application() \ No newline at end of file diff --git a/donation/admin.py b/donation/admin.py index e85288d3..cff26f81 100644 --- a/donation/admin.py +++ b/donation/admin.py @@ -13,9 +13,9 @@ @admin.register(Donation) class DonationAdmin(admin.ModelAdmin): date_hierarchy = 'date' + list_display = ['sum_', 'telegram_url_', 'date'] - list_display = ('sum_', 'telegram_url_', 'date') - fields = ('sum', 'telegram_url', 'date') + fields = ['sum', 'telegram_url', 'date'] @admin.display(description=_('Сумма'), ordering='sum') def sum_(self, donation: Donation) -> str: @@ -27,16 +27,17 @@ def telegram_url_(self, donation: Donation) -> str: @admin.register(DonationSection) class DonationSectionAdmin(TranslationAdmin): - list_display = ('title', 'position') + list_display = ['title', 'position'] - fields = ('title', 'text', 'position') + fields = ['title', 'text', 'position'] formfield_overrides = {models.TextField: {'widget': TinyMCE}} @admin.register(DonationButton) class DonationButtonAdmin(TranslationAdmin): - list_display = ('text', 'url_', 'position') - fields = ('text', 'url', 'position') + list_display = ['text', 'url_', 'position'] + + fields = ['text', 'url', 'position'] @admin.display(description=_('Ссылка'), ordering='url') def url_(self, donation_button: DonationButton) -> str: - return format_html_url(donation_button.url) + return format_html_url(donation_button.url) \ No newline at end of file diff --git a/donation/apps.py b/donation/apps.py index 73ca95ba..4a67d244 100644 --- a/donation/apps.py +++ b/donation/apps.py @@ -6,4 +6,4 @@ class DonationConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'donation' - verbose_name = _('Пожертвования') + verbose_name = _('Пожертвования') \ No newline at end of file diff --git a/donation/models.py b/donation/models.py index 1420410e..03fcdfd7 100644 --- a/donation/models.py +++ b/donation/models.py @@ -57,4 +57,4 @@ class Meta: verbose_name_plural = _('Кнопки') def __str__(self) -> str: - return self.text + return self.text \ No newline at end of file diff --git a/donation/serializers.py b/donation/serializers.py new file mode 100644 index 00000000..6118ef59 --- /dev/null +++ b/donation/serializers.py @@ -0,0 +1,33 @@ +from django.template import defaultfilters as filters + +from rest_framework import serializers + +from .models import Donation, DonationSection, DonationButton + +from typing import Any + + +class DonationModelSerializer(serializers.ModelSerializer): + class Meta: + model = Donation + fields = ['id', 'sum', 'telegram_url', 'date'] + + def to_representation(self, instance: Donation) -> dict[str, Any]: + representation: dict[str, Any] = super().to_representation(instance) + representation['date'] = f'{filters.date(instance.date)} {filters.time(instance.date)}' + + return representation + +class DonationSectionModelSerializer(serializers.ModelSerializer): + class Meta: + model = DonationSection + fields = ['id', 'title', 'text'] + +class DonationButtonModelSerializer(serializers.ModelSerializer): + class Meta: + model = DonationButton + fields = ['id', 'text', 'url'] + +class GetDonationsSerializer(serializers.Serializer): + offset = serializers.IntegerField(default=None) + limit = serializers.IntegerField(default=None) \ No newline at end of file diff --git a/donation/templates/donation/base.html b/donation/templates/donation/base.html deleted file mode 100644 index 6423891b..00000000 --- a/donation/templates/donation/base.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} - -{% block title %}{% trans 'Пожертвование' %}{% endblock title %} - -{% block main %} -
- {% block content %}{% endblock content %} -
-{% endblock main %} \ No newline at end of file diff --git a/donation/templates/donation/completed.html b/donation/templates/donation/completed.html deleted file mode 100644 index 66f47586..00000000 --- a/donation/templates/donation/completed.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'donation/base.html' %} -{% load i18n %} - -{% block content %} -
-

{% trans 'Спасибо за пожертвование сайту!' %}

-

- {% trans 'Спасибо за пожертвование сайту, ваше пожертвование очень сильно поможет развитию и улучшению сайта!' %}
- {% trans 'Чтобы узнать, было ли ваше пожертвование получено сайтом, вы можете написать основателю сайта в' %} Telegram {% trans 'и задать ему этот вопрос.' %} -

-
-{% endblock content %} \ No newline at end of file diff --git a/donation/templates/donation/index.html b/donation/templates/donation/index.html deleted file mode 100644 index 10e5cdc3..00000000 --- a/donation/templates/donation/index.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends 'donation/base.html' %} - -{% block content %} -{% for donation_section in donation_sections %} -
-

{{ donation_section.title }}

- {% autoescape off %}{{ donation_section.text }}{% endautoescape %} -
-{% endfor %} -
- {% for donation_button in donation_buttons %} - {{ donation_button.text }} - {% endfor %} -
-{% endblock content %} \ No newline at end of file diff --git a/donation/tests.py b/donation/tests.py index f2a8ad58..106a387b 100644 --- a/donation/tests.py +++ b/donation/tests.py @@ -1,6 +1,4 @@ from django.test import TestCase -from django.http import HttpResponse -from django import urls from .models import Donation, DonationSection, DonationButton @@ -43,19 +41,4 @@ def setUp(self) -> None: def test_fields(self) -> None: self.assertEqual(self.donation_button.text, 'Test') self.assertEqual(self.donation_button.url, 'https://example.com/') - self.assertEqual(self.donation_button.position, 1) - -class ViewsTests(TestCase): - def test_donation_view(self) -> None: - url: str = urls.reverse('donation:index') - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'donation/index.html') - - def test_donation_completed_view(self) -> None: - url: str = urls.reverse('donation:completed') - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'donation/completed.html') + self.assertEqual(self.donation_button.position, 1) \ No newline at end of file diff --git a/donation/translation.py b/donation/translation.py index 6d730c2b..db722bbe 100644 --- a/donation/translation.py +++ b/donation/translation.py @@ -5,8 +5,8 @@ @register(DonationSection) class DonationSectionTranslationOptions(TranslationOptions): - fields = ('title', 'text') + fields = ['title', 'text'] @register(DonationButton) class DonationButtonTranslationOptions(TranslationOptions): - fields = ('text',) + fields = ['text'] \ No newline at end of file diff --git a/donation/urls.py b/donation/urls.py index d9f595d1..8ffac34a 100644 --- a/donation/urls.py +++ b/donation/urls.py @@ -1,10 +1,10 @@ from django.urls import path -from .views import index_view, completed_view +from .views import DonationsAPIView, DonationButtonsAPIView, DonationSectionsAPIView -app_name = 'donation' urlpatterns = [ - path('', index_view, name='index'), - path('completed/', completed_view, name='completed'), -] + path('', DonationsAPIView.as_view(), name='donations'), + path('sections/', DonationSectionsAPIView.as_view(), name='donation-sections'), + path('buttons/', DonationButtonsAPIView.as_view(), name='donation-buttons'), +] \ No newline at end of file diff --git a/donation/views.py b/donation/views.py index 6caf2d68..293bbace 100644 --- a/donation/views.py +++ b/donation/views.py @@ -1,14 +1,57 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render +from rest_framework.views import APIView +from rest_framework.request import Request +from rest_framework.response import Response -from .models import DonationSection, DonationButton +from .models import Donation, DonationSection, DonationButton +from .serializers import ( + DonationModelSerializer, + DonationSectionModelSerializer, + DonationButtonModelSerializer, + GetDonationsSerializer, +) +from typing import Any -def index_view(request: HttpRequest) -> HttpResponse: - return render(request, 'donation/index.html', { - 'donation_sections': DonationSection.objects.all(), - 'donation_buttons': DonationButton.objects.all(), - }) -def completed_view(request: HttpRequest) -> HttpResponse: - return render(request, 'donation/completed.html') +class DonationsAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def post(self, request: Request) -> Response: + serializer = GetDonationsSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + validated_data: dict[str, Any] = serializer.validated_data + offset: int | None = validated_data['offset'] + limit: int | None = validated_data['limit'] + + return Response( + DonationModelSerializer( + Donation.objects.all()[offset:limit], + many=True, + ).data + ) + +class DonationSectionsAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def get(self, request: Request) -> Response: + return Response( + DonationSectionModelSerializer( + DonationSection.objects.all(), + many=True, + ).data + ) + +class DonationButtonsAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def get(self, request: Request) -> Response: + return Response( + DonationButtonModelSerializer( + DonationButton.objects.all(), + many=True, + ).data + ) \ No newline at end of file diff --git a/home/apps.py b/home/apps.py deleted file mode 100644 index 0b2ee12d..00000000 --- a/home/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class HomeConfig(AppConfig): - name = 'home' diff --git a/home/migrations/__init__.py b/home/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/home/static/home/index/src/main.css b/home/static/home/index/src/main.css deleted file mode 100644 index eaa2a9d3..00000000 --- a/home/static/home/index/src/main.css +++ /dev/null @@ -1,41 +0,0 @@ -.btn-new-update { - font-size: 14px; - background-color: #ffdb59; - box-shadow: 0 0 6px #ffe073; -} - -.btn-new-update:hover { - background-color: #f5d256; -} - -.about-site, -.information-about-site, -.donations { - width: 100%; -} - -@media (min-width: 992px) { - .about-site { - width: 60%; - } - - .information-about-site { - width: 40%; - } - - .donations { - width: 50%; - } -} - -.sum, .date { - width: 30%; -} - -.btn-support-site { - background-color: #2bd987; -} - -.btn-support-site:hover { - background-color: #28cc7f; -} \ No newline at end of file diff --git a/home/templates/home/index.html b/home/templates/home/index.html deleted file mode 100644 index e17409c3..00000000 --- a/home/templates/home/index.html +++ /dev/null @@ -1,65 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Бесплатный конструктор Telegram ботов' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'HOME:INDEX' %} -{% endblock styles %} - -{% block main %} -
- {% with updates.first as last_update %} - {% if last_update %} -
- {% trans 'Новое обновление:' %} - {{ last_update.version }} -
- {% endif %} - {% endwith %} -
-

Constructor Telegram Bots

-

{% trans 'Сайт, с помощью которого вы можете легко, бесплатно и без каких-либо знаний в программирование, сделать своего многофункционального Telegram бота.' %}

-
-
-

{% trans 'Информация о сайте' %}

- {% trans 'Количество пользователей' as info_area_text %} - {% include 'widgets/info_area.html' with class='mb-1' value=users.count text=info_area_text %} - {% trans 'Количество добавленных Telegram ботов' as info_area_text %} - {% include 'widgets/info_area.html' with value=telegram_bots.count text=info_area_text %} -
-
-

{% trans 'Список пожертвований' %}

- - - - - - - - - - {% if donations %} - {% for donation in donations %} - - - - - - {% endfor %} - {% else %} - - - - {% endif %} - -
{% trans 'Сумма' %}Telegram{% trans 'Дата' %}
{{ donation.sum }}€{{ donation.telegram_url }}{{ donation.date }}
{% trans 'Ещё не было сделано пожертвований' %}
- {% trans 'Поддержать сайт' %} -
-
-{% endblock main %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'HOME:INDEX' %} -{% endblock scripts %} \ No newline at end of file diff --git a/home/tests.py b/home/tests.py deleted file mode 100644 index 7ec11175..00000000 --- a/home/tests.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.test import TestCase -from django.http import HttpResponse -from django import urls - - -class ViewsTests(TestCase): - def test_home_view(self) -> None: - url: str = urls.reverse('home:index') - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'home/index.html') diff --git a/home/urls.py b/home/urls.py deleted file mode 100644 index f03ecfc4..00000000 --- a/home/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path - -from .views import index_view - - -app_name = 'home' -urlpatterns = [ - path('', index_view, name='index'), -] diff --git a/home/views.py b/home/views.py deleted file mode 100644 index 32088a1e..00000000 --- a/home/views.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render - -from user.models import User -from telegram_bot.models import TelegramBot -from updates.models import Update -from donation.models import Donation - - -def index_view(request: HttpRequest) -> HttpResponse: - return render(request, 'home/index.html', { - 'users': User.objects.all(), - 'telegram_bots': TelegramBot.objects.all(), - 'updates': Update.objects.all(), - 'donations': Donation.objects.all(), - }) diff --git a/instruction/admin.py b/instruction/admin.py index ebddfaf3..c646d571 100644 --- a/instruction/admin.py +++ b/instruction/admin.py @@ -9,7 +9,7 @@ @admin.register(InstructionSection) class InstructionSectionAdmin(TranslationAdmin): - list_display = ('title', 'position') + list_display = ['title', 'position'] - fields = ('title', 'text', 'position') - formfield_overrides = {models.TextField: {'widget': TinyMCE}} + fields = ['title', 'text', 'position'] + formfield_overrides = {models.TextField: {'widget': TinyMCE}} \ No newline at end of file diff --git a/instruction/apps.py b/instruction/apps.py index f1544acb..0aa30445 100644 --- a/instruction/apps.py +++ b/instruction/apps.py @@ -6,4 +6,4 @@ class InstructionConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'instruction' - verbose_name = _('Инструкция') + verbose_name = _('Инструкция') \ No newline at end of file diff --git a/instruction/models.py b/instruction/models.py index 482eafaf..3c51602d 100644 --- a/instruction/models.py +++ b/instruction/models.py @@ -21,4 +21,4 @@ class Meta: verbose_name_plural = _('Разделы') def __str__(self) -> str: - return self.title + return self.title \ No newline at end of file diff --git a/instruction/serializers.py b/instruction/serializers.py new file mode 100644 index 00000000..839604c8 --- /dev/null +++ b/instruction/serializers.py @@ -0,0 +1,9 @@ +from rest_framework import serializers + +from .models import InstructionSection + + +class InstructionSectionModelSerializer(serializers.ModelSerializer): + class Meta: + model = InstructionSection + fields = ['id', 'title', 'text'] \ No newline at end of file diff --git a/instruction/templates/instruction/index.html b/instruction/templates/instruction/index.html deleted file mode 100644 index 61b74d58..00000000 --- a/instruction/templates/instruction/index.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} - -{% block title %}{% trans 'Инструкция' %}{% endblock title %} - -{% block main %} -
- {% for instruction_section in instruction_sections %} -
-

{{ instruction_section.title }}

- {% autoescape off %}{{ instruction_section.text }}{% endautoescape %} -
- {% endfor %} -
-{% endblock main %} \ No newline at end of file diff --git a/instruction/tests.py b/instruction/tests.py index ce1d9abe..9bd3e6e9 100644 --- a/instruction/tests.py +++ b/instruction/tests.py @@ -24,4 +24,4 @@ def test_instruction_view(self) -> None: response: HttpResponse = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'instruction/index.html') + self.assertTemplateUsed(response, 'instruction/index.html') \ No newline at end of file diff --git a/instruction/translation.py b/instruction/translation.py index d34e91bc..5e2c90dc 100644 --- a/instruction/translation.py +++ b/instruction/translation.py @@ -5,4 +5,4 @@ @register(InstructionSection) class InstructionSectionTranslationOptions(TranslationOptions): - fields = ('title', 'text') + fields = ['title', 'text'] \ No newline at end of file diff --git a/instruction/urls.py b/instruction/urls.py index 09298676..c05fb60d 100644 --- a/instruction/urls.py +++ b/instruction/urls.py @@ -1,9 +1,8 @@ from django.urls import path -from .views import index_view +from .views import InstructionSectionsAPIView -app_name = 'instruction' urlpatterns = [ - path('', index_view, name='index'), -] + path('sections/', InstructionSectionsAPIView.as_view(), name='instruction-sections'), +] \ No newline at end of file diff --git a/instruction/views.py b/instruction/views.py index 24a355a8..34be8636 100644 --- a/instruction/views.py +++ b/instruction/views.py @@ -1,8 +1,19 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render +from rest_framework.views import APIView +from rest_framework.request import Request +from rest_framework.response import Response from .models import InstructionSection +from .serializers import InstructionSectionModelSerializer -def index_view(request: HttpRequest) -> HttpResponse: - return render(request, 'instruction/index.html', {'instruction_sections': InstructionSection.objects.all()}) +class InstructionSectionsAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def get(self, request: Request) -> Response: + return Response( + InstructionSectionModelSerializer( + InstructionSection.objects.all(), + many=True, + ).data + ) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index edc5d070..3dea64ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2368 +1,26 @@ { - "name": "constructor-telegram-bots", + "name": "Constructor-Telegram-Bots", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "constructor-telegram-bots", "dependencies": { - "@monaco-editor/react": "^4.6.0", - "@types/bootstrap": "^5.2.9", - "@types/qrcode": "^1.5.5", - "@types/react": "^18.2.39", - "@types/react-dom": "^18.2.17", - "bootstrap": "^5.3.2", - "bootstrap-icons": "^1.11.1", - "clipboard": "^2.0.11", - "css-loader": "^6.8.1", - "exports-loader": "^4.0.0", - "mini-css-extract-plugin": "^2.7.6", - "monaco-editor": "^0.44.0", - "monaco-editor-webpack-plugin": "^7.1.0", - "qrcode": "^1.5.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "ts-loader": "^9.5.0", - "ts-node": "^10.9.1", - "typescript": "^5.2.2", - "webpack": "^5.89.0", - "webpack-bundle-tracker": "^2.0.1", - "webpack-cli": "^5.1.4" + "@types/js-cookie": "^3.0.6", + "cd": "^0.3.3" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "engines": { - "node": ">=10.0.0" - } + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==" }, - "node_modules/@jridgewell/gen-mapping": { + "node_modules/cd": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "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==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@monaco-editor/loader": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", - "integrity": "sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==", - "dependencies": { - "state-local": "^1.0.6" - }, - "peerDependencies": { - "monaco-editor": ">= 0.21.0 < 1" - } - }, - "node_modules/@monaco-editor/react": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.6.0.tgz", - "integrity": "sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==", - "dependencies": { - "@monaco-editor/loader": "^1.4.0" - }, - "peerDependencies": { - "monaco-editor": ">= 0.25.0 < 1", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" - }, - "node_modules/@types/bootstrap": { - "version": "5.2.9", - "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.9.tgz", - "integrity": "sha512-Fcg4nORBKaVUAG4F0ePWcatWQVfr3NAT9XIN+hl1PaiAwb4tq55+iua9R3exsbB3yyfhyQlHYg2foTlW86J+RA==", - "dependencies": { - "@popperjs/core": "^2.9.2" - } - }, - "node_modules/@types/eslint": { - "version": "8.44.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", - "integrity": "sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "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==" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" - }, - "node_modules/@types/node": { - "version": "20.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", - "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" - }, - "node_modules/@types/qrcode": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", - "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/react": { - "version": "18.2.39", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", - "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.17", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", - "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", - "engines": { - "node": ">=14.15.0" - }, - "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "engines": { - "node": ">=0.4.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==", - "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/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "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==", - "engines": { - "node": ">=8" - } - }, - "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==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "resolved": "https://registry.npmjs.org/cd/-/cd-0.3.3.tgz", + "integrity": "sha512-X2y0Ssu48ucdkrNgCdg6k3EZWjWVy/dsEywUUTeZEIW31f3bQfq65Svm+TzU1Hz+qqhdmyCdjGhUvRsSKHl/mw==", "engines": { "node": "*" } - }, - "node_modules/bootstrap": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", - "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "peerDependencies": { - "@popperjs/core": "^2.11.8" - } - }, - "node_modules/bootstrap-icons": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.1.tgz", - "integrity": "sha512-F0DDp7nKUX+x/QtpfRZ+XHFya60ng9nfdpdS59vDDfs4Uhuxp7zym/QavMsu/xx51txkoM9eVmpE7D08N35blw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ] - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "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.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001561", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz", - "integrity": "sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==", - "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": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/chalk/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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/clipboard": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", - "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", - "dependencies": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "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==" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "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==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.21", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.580", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.580.tgz", - "integrity": "sha512-T5q3pjQon853xxxHUq3ZP68ZpvJHuSMY2+BZaW3QzjS4HvNuvsMmZ/+lU+nCrftre1jFZ+OSlExynXWBihnXzw==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", - "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.0.tgz", - "integrity": "sha512-lcCr3v3OLezdfFyx9r5NRYHOUTQNnFEQ9E87Mx8Kc+iqyJNkO7MJoB4GQRTlIMw9kLLTwGw0OAkm4BQQud/d9g==" - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "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==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/exports-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-4.0.0.tgz", - "integrity": "sha512-4iqFFIAnlVAbkAUMHhWceyxK6N6dMDWpQFbSHLmiayGEPMXl2bgWD4D11GYi1VNuEQwJaHGdATcPYTnXpwzSmw==", - "dependencies": { - "source-map": "^0.6.1" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.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==" - }, - "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==" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "bin": { - "flat": "cli.js" - } - }, - "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==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "node_modules/good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", - "dependencies": { - "delegate": "^3.1.2" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", - "engines": { - "node": ">=10.13.0" - } - }, - "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==", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "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/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "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==" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - }, - "node_modules/lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==" - }, - "node_modules/lodash.frompairs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.frompairs/-/lodash.frompairs-4.0.1.tgz", - "integrity": "sha512-dvqe2I+cO5MzXCMhUnfYFa9MD+/760yx2aTAN1lqEcEkf896TxgrX373igVdqSJj6tQd0jnSLE1UMuKufqqxFw==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "node_modules/lodash.topairs": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.topairs/-/lodash.topairs-4.3.0.tgz", - "integrity": "sha512-qrRMbykBSEGdOgQLJJqVSdPWMD7Q+GJJ5jMRfQYb+LTLsw3tYVIabnCzRqTJb2WTo17PG5gNzXuFaZgYH/9SAQ==" - }, - "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": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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/mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/monaco-editor": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", - "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==" - }, - "node_modules/monaco-editor-webpack-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.1.0.tgz", - "integrity": "sha512-ZjnGINHN963JQkFqjjcBtn1XBtUATDZBMgNQhDQwd78w2ukRhFXAPNgWuacaQiDZsUr4h1rWv5Mv6eriKuOSzA==", - "dependencies": { - "loader-utils": "^2.0.2" - }, - "peerDependencies": { - "monaco-editor": ">= 0.31.0", - "webpack": "^4.5.0 || 5.x" - } - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "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/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "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==", - "engines": { - "node": ">=8" - } - }, - "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==", - "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==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "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.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qrcode": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", - "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", - "dependencies": { - "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "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/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", - "dependencies": { - "resolve": "^1.20.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "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-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/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/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/state-local": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz", - "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "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==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", - "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-loader": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.0.tgz", - "integrity": "sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==", - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "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==", - "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==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-bundle-tracker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-tracker/-/webpack-bundle-tracker-2.0.1.tgz", - "integrity": "sha512-BLPR98I+u/3sExW098tWzmKXeNyOQGMgbLg/eDwYgKKNohde93H2AMmSbRJv4NWn7Ltlryn7gP4XeAG5RP0vGg==", - "dependencies": { - "lodash.assign": "^4.2.0", - "lodash.defaults": "^4.2.0", - "lodash.foreach": "^4.5.0", - "lodash.frompairs": "^4.0.1", - "lodash.get": "^4.4.2", - "lodash.topairs": "^4.3.0", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", - "colorette": "^2.0.14", - "commander": "^10.0.1", - "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "engines": { - "node": ">=14" - } - }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", - "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" - }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } } } } diff --git a/package.json b/package.json index 4fbae450..9504da25 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,6 @@ { - "name": "constructor-telegram-bots", - "private": true, - "scripts": { - "dev": "webpack --mode=development -c ./webpack.config.ts", - "build": "webpack --mode=production -c ./webpack.config.ts" - }, "dependencies": { - "@monaco-editor/react": "^4.6.0", - "@types/bootstrap": "^5.2.9", - "@types/qrcode": "^1.5.5", - "@types/react": "^18.2.39", - "@types/react-dom": "^18.2.17", - "bootstrap": "^5.3.2", - "bootstrap-icons": "^1.11.1", - "clipboard": "^2.0.11", - "css-loader": "^6.8.1", - "exports-loader": "^4.0.0", - "mini-css-extract-plugin": "^2.7.6", - "monaco-editor": "^0.44.0", - "monaco-editor-webpack-plugin": "^7.1.0", - "qrcode": "^1.5.3", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "ts-loader": "^9.5.0", - "ts-node": "^10.9.1", - "typescript": "^5.2.2", - "webpack": "^5.89.0", - "webpack-bundle-tracker": "^2.0.1", - "webpack-cli": "^5.1.4" + "@types/js-cookie": "^3.0.6", + "cd": "^0.3.3" } } diff --git a/personal_cabinet/__init__.py b/personal_cabinet/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/personal_cabinet/apps.py b/personal_cabinet/apps.py deleted file mode 100644 index b745b88e..00000000 --- a/personal_cabinet/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class PersonalCabinetConfig(AppConfig): - name = 'personal_cabinet' diff --git a/personal_cabinet/migrations/__init__.py b/personal_cabinet/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/personal_cabinet/static/personal_cabinet/index/src/main.tsx b/personal_cabinet/static/personal_cabinet/index/src/main.tsx deleted file mode 100644 index 9ca188b3..00000000 --- a/personal_cabinet/static/personal_cabinet/index/src/main.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import './modals/add_telegram_bot_modal'; - -import Toast from 'global_modules/toast'; -import { TelegramBotsApi } from 'telegram_bot_api/main'; -import TelegramBotCard from 'telegram_bot_frontend/components/TelegramBotCard'; -import { createRoot } from 'react-dom/client'; -import React from 'react'; - -declare const telegramBotNotAddedYetText: string; -declare const telegramBotCardFooterPersonalCabinetButtonText: string; - -export namespace TelegramBotCards { - const root = createRoot(document.querySelector('#telegramBots')!); - - export async function update(): Promise { - const response = await TelegramBotsApi.get(); - - if (response.ok) { - root.render(response.json.length > 0 ? ( - response.json.map(telegramBot => ( - - - - )) - ) : ( -
{telegramBotNotAddedYetText}
- )); - } else { - new Toast(response.json.message, response.json.level).show(); - } - } -} - -TelegramBotCards.update(); \ No newline at end of file diff --git a/personal_cabinet/static/personal_cabinet/index/src/modals/add_telegram_bot_modal.ts b/personal_cabinet/static/personal_cabinet/index/src/modals/add_telegram_bot_modal.ts deleted file mode 100644 index 0860d59a..00000000 --- a/personal_cabinet/static/personal_cabinet/index/src/modals/add_telegram_bot_modal.ts +++ /dev/null @@ -1,33 +0,0 @@ -import Toast from 'global_modules/toast'; -import { TelegramBotApi } from 'telegram_bot_api/main'; -import { TelegramBotCards } from '../main'; -import { Modal } from 'bootstrap'; - -const modal = new Modal('#addTelegramBotModal'); -const modalToggleButtonElement = document.querySelector('#addTelegramBotModalButton')!; - -const apiTokenInputElement = document.querySelector('#addTelegramBotModalApiTokenInput')!; -const isPrivateCheckBoxElement = document.querySelector('#addTelegramBotModalIsPrivateCheckBox')!; -const addButtonElement = document.querySelector('#addTelegramBotModalAddTelegramBotButton')!; - -addButtonElement.addEventListener('click', async () => { - const response = await TelegramBotApi.create({ - api_token: apiTokenInputElement.value, - is_private: isPrivateCheckBoxElement.checked, - }); - - if (response.ok) { - TelegramBotCards.update(); - - modal.hide(); - } - - new Toast(response.json.message, response.json.level).show(); -}); - -modalToggleButtonElement.addEventListener('click', () => { - apiTokenInputElement.value = ''; - isPrivateCheckBoxElement.checked = false; - - modal.toggle(); -}); \ No newline at end of file diff --git a/personal_cabinet/templates/personal_cabinet/index/main.html b/personal_cabinet/templates/personal_cabinet/index/main.html deleted file mode 100644 index 65b7cc28..00000000 --- a/personal_cabinet/templates/personal_cabinet/index/main.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Личный кабинет' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'PERSONAL_CABINET:INDEX' %} -{% endblock styles %} - -{% block modals %} -{{ block.super }} -{% include 'personal_cabinet/index/modals/add_telegram_bot_modal.html' %} -{% endblock modals %} - -{% block main_class %}{% endblock main_class %} - -{% block main %} -
-
-

{% trans 'Добавленные Telegram боты' %}

- {% trans 'Добавить Telegram бота' as add_button_text %} - {% include 'widgets/add_button.html' with extra_class='flex-grow-1 flex-lg-grow-0 align-self-center' id='addTelegramBotModalButton' text=add_button_text %} -
-
-
-{% endblock main %} - -{% block footer %} -{% with footer_extra_class="mt-auto" %} - {{ block.super }} -{% endwith %} -{% endblock footer %} - -{% block scripts_data %} -{{ block.super }} -const telegramBotNotAddedYetText = "{% trans 'Вы ещё не добавили Telegram бота' %}"; - -{% include 'telegram_bot/frontend/components/telegram_bot_card/scripts_data.html' %} - -const telegramBotCardFooterPersonalCabinetButtonText = "{% trans 'Меню Telegram бота' %}"; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'PERSONAL_CABINET:INDEX' %} -{% endblock scripts %} \ No newline at end of file diff --git a/personal_cabinet/templates/personal_cabinet/index/modals/add_telegram_bot_modal.html b/personal_cabinet/templates/personal_cabinet/index/modals/add_telegram_bot_modal.html deleted file mode 100644 index 5d54d3a6..00000000 --- a/personal_cabinet/templates/personal_cabinet/index/modals/add_telegram_bot_modal.html +++ /dev/null @@ -1,26 +0,0 @@ -{% load i18n %} - -{% with modal_id='addTelegramBotModal' %} - -{% endwith %} \ No newline at end of file diff --git a/personal_cabinet/tests.py b/personal_cabinet/tests.py deleted file mode 100644 index a9b3e1dc..00000000 --- a/personal_cabinet/tests.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.test import TestCase -from django.http import HttpResponse -from django import urls - -from user.models import User - - -class ViewsTests(TestCase): - def setUp(self) -> None: - self.user: User = User.objects.create(telegram_id=123456789, first_name='exg1o') - - def test_personal_cabinet_view(self) -> None: - url: str = urls.reverse('personal_cabinet:index') - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'personal_cabinet/index/main.html') diff --git a/personal_cabinet/urls.py b/personal_cabinet/urls.py deleted file mode 100644 index 3304a0ed..00000000 --- a/personal_cabinet/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path - -from .views import index_view - - -app_name = 'personal_cabinet' -urlpatterns = [ - path('', index_view, name='index'), -] diff --git a/personal_cabinet/views.py b/personal_cabinet/views.py deleted file mode 100644 index e9778db4..00000000 --- a/personal_cabinet/views.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render - -from django.contrib.auth.decorators import login_required - - -@login_required -def index_view(request: HttpRequest) -> HttpResponse: - return render(request, 'personal_cabinet/index/main.html') diff --git a/plugin/admin.py b/plugin/admin.py index 55fc6d68..1be37309 100644 --- a/plugin/admin.py +++ b/plugin/admin.py @@ -6,15 +6,15 @@ @admin.register(Plugin) class PluginAdmin(admin.ModelAdmin): date_hierarchy = 'added_date' - list_filter = ('is_checked', 'added_date') + list_filter = ['is_checked', 'added_date'] + list_display = ['id', 'user', 'telegram_bot', 'name', 'is_checked', 'added_date'] - list_display = ('id', 'user', 'telegram_bot', 'name', 'is_checked', 'added_date') - fields = ('user', 'telegram_bot', 'name', 'code', 'is_checked') + fields = ['user', 'telegram_bot', 'name', 'code', 'is_checked'] @admin.register(PluginLog) class PluginLogAdmin(admin.ModelAdmin): date_hierarchy = 'added_date' - list_filter = ('level', 'added_date') + list_filter = ['level', 'added_date'] + list_display = ['id', 'user', 'telegram_bot', 'plugin', 'message', 'level', 'added_date'] - list_display = ('id', 'user', 'telegram_bot', 'plugin', 'message', 'level', 'added_date') - fields = ('user', 'telegram_bot', 'plugin', 'message', 'level') + fields = ['user', 'telegram_bot', 'plugin', 'message', 'level'] \ No newline at end of file diff --git a/plugin/apps.py b/plugin/apps.py index c34bc86b..224a1158 100644 --- a/plugin/apps.py +++ b/plugin/apps.py @@ -9,4 +9,4 @@ class PluginConfig(AppConfig): verbose_name = _('Плагины') def ready(self) -> None: - from . import signals + from . import signals \ No newline at end of file diff --git a/plugin/decorators.py b/plugin/decorators.py index 9e551989..255a35e3 100644 --- a/plugin/decorators.py +++ b/plugin/decorators.py @@ -18,4 +18,4 @@ def wrapper(*args, **kwargs): return CustomResponse(_('Плагин не найден!'), status=404) return func(*args, **kwargs) - return wrapper + return wrapper \ No newline at end of file diff --git a/plugin/models.py b/plugin/models.py index 0a33223b..e207435f 100644 --- a/plugin/models.py +++ b/plugin/models.py @@ -41,4 +41,4 @@ class Meta: verbose_name_plural = _('Логи') def __str__(self) -> str: - return self.plugin.name + return self.plugin.name \ No newline at end of file diff --git a/plugin/serializers.py b/plugin/serializers.py index 20b60221..cf9e3964 100644 --- a/plugin/serializers.py +++ b/plugin/serializers.py @@ -21,14 +21,14 @@ def to_representation(self, instance: Plugin | PluginLog) -> dict[str, Any]: class PluginModelSerializer(ModelSerializer): class Meta: model = Plugin - fields = ('id', 'name', 'code', 'is_checked') + fields = ['id', 'name', 'code', 'is_checked'] class PluginLogModelSerializer(ModelSerializer): plugin_name = serializers.CharField(max_length=255, source='plugin.name') class Meta: model = PluginLog - fields = ('id', 'plugin_name', 'message', 'level') + fields = ['id', 'plugin_name', 'message', 'level'] class CreatePluginSerializer(serializers.Serializer): name = serializers.CharField(max_length=255, error_messages={ @@ -53,4 +53,4 @@ class UpdatePluginSerializer(serializers.Serializer): class AddPluginLogSerializer(serializers.Serializer): message = serializers.CharField() - level = serializers.ChoiceField(choices=['info', 'success', 'danger']) + level = serializers.ChoiceField(choices=['info', 'success', 'danger']) \ No newline at end of file diff --git a/plugin/signals.py b/plugin/signals.py index c0b681b4..2db5d776 100644 --- a/plugin/signals.py +++ b/plugin/signals.py @@ -19,4 +19,4 @@ def post_save_plugin_signal_handler(instance: Plugin, **kwargs: Any) -> None: @receiver(post_delete, sender=Plugin) def post_delete_plugin_signal_handler(instance: Plugin, **kwargs: Any) -> None: if instance.is_checked: - env_delete_plugin(plugin=instance) + env_delete_plugin(plugin=instance) \ No newline at end of file diff --git a/plugin/static/plugin/api/main.ts b/plugin/static/plugin/api/main.ts deleted file mode 100644 index 77bc3373..00000000 --- a/plugin/static/plugin/api/main.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { ApiResponse as BaseApiResponse, makeRequest } from 'global_modules/api'; -import { TelegramBot as TelegramBotType } from 'telegram_bot_api/types'; -import * as Types from './types'; - -declare const userApiToken: string; - -namespace Base { - export const url = '/plugins/'; - export const headers: HeadersInit = {'Authorization': `Token ${userApiToken}`} -} - -export namespace PluginsApi { - export const url = (telegramBotId: TelegramBotType['id']): string => `${Base.url}_/${telegramBotId}/`; - - export function get(telegramBotId: TelegramBotType['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } -} - -export namespace PluginApi { - export const url = (pluginId: Types.Plugin['id']): string => `${Base.url}${pluginId}/`; - - export function create(telegramBotId: TelegramBotType['id'], data: Types.Data.Plugin.Create): Promise> { - return makeRequest(PluginsApi.url(telegramBotId), 'POST', Base.headers, data); - } - export function update(pluginId: Types.Plugin['id'], data: Types.Data.Plugin.Update): Promise> { - return makeRequest(url(pluginId), 'PATCH', Base.headers, data); - } - export function delete_(pluginId: Types.Plugin['id']): Promise> { - return makeRequest(url(pluginId), 'DELETE', Base.headers); - } -} - -export namespace PluginsLogsApi { - export const url = (telegramBotId: TelegramBotType['id']): string => `${PluginsApi.url(telegramBotId)}logs/`; - - export function get(telegramBotId: TelegramBotType['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } -} \ No newline at end of file diff --git a/plugin/static/plugin/api/types.ts b/plugin/static/plugin/api/types.ts deleted file mode 100644 index 8013f1c6..00000000 --- a/plugin/static/plugin/api/types.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { ApiResponse as BaseApiResponse } from 'global_modules/api'; - -export interface Plugin { - id: number; - name: string; - code: string; - is_checked: boolean; - added_date: string; -} - -export interface PluginLog { - id: number; - plugin_name: string; - message: string; - level: 'success' | 'info' | 'danger'; -} - -export namespace Data { - export namespace Plugin { - export interface Create { - name: Plugin['name'], - code: Plugin['code']; - } - export type Update = Omit; - } -} - -export namespace ApiResponse { - export namespace Plugin { - export interface Create extends BaseApiResponse.Success { - plugin: Plugin; - } - export type Update = Create; - } -} \ No newline at end of file diff --git a/plugin/tests.py b/plugin/tests.py index 9a0fcbd0..e04c7222 100644 --- a/plugin/tests.py +++ b/plugin/tests.py @@ -173,4 +173,4 @@ def test_add_plugin_log_view(self) -> None: 'level': 'success', }, ) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 200) \ No newline at end of file diff --git a/plugin/urls.py b/plugin/urls.py index e6ee76f3..e6ac69cb 100644 --- a/plugin/urls.py +++ b/plugin/urls.py @@ -6,6 +6,6 @@ urlpatterns = [ path('_//', views.PluginsView.as_view(), name='plugins'), path('/', views.PluginView.as_view(), name='plugin'), - path('_//logs/', views.get_plugins_logs_view, name='plugins_logs'), - path('/logs/', views.add_plugin_log_view, name='plugin_logs'), -] + path('_//logs/', views.get_plugins_logs_view, name='plugins-logs'), + path('/logs/', views.add_plugin_log_view, name='plugin-logs'), +] \ No newline at end of file diff --git a/plugin/views.py b/plugin/views.py index a458d296..490f3a03 100644 --- a/plugin/views.py +++ b/plugin/views.py @@ -46,7 +46,12 @@ def post(self, request: Request, telegram_bot: TelegramBot) -> CustomResponse: @check_telegram_bot_id def get(self, request: Request, telegram_bot: TelegramBot) -> Response: - return Response(PluginModelSerializer(telegram_bot.plugins.all(), many=True).data) + return Response( + PluginModelSerializer( + telegram_bot.plugins.all(), + many=True, + ).data + ) class PluginView(APIView): authentication_classes = [TokenAuthentication] diff --git a/team/admin.py b/team/admin.py index d89ee572..cd2f0ac1 100644 --- a/team/admin.py +++ b/team/admin.py @@ -8,11 +8,11 @@ @admin.register(TeamMember) class TeamMemberAdmin(TranslationAdmin): date_hierarchy = 'joined_date' - list_filter = ('speciality', 'joined_date') + list_filter = ['speciality', 'joined_date'] - list_display = ('username_', 'speciality', 'joined_date') - fields = ('image', 'username', 'speciality', 'joined_date') + list_display = ['username_', 'speciality', 'joined_date'] + fields = ['image', 'username', 'speciality', 'joined_date'] @admin.display(description='@username', ordering='username') def username_(self, team_member: TeamMember) -> str: - return f'@{team_member.username}' + return f'@{team_member.username}' \ No newline at end of file diff --git a/team/apps.py b/team/apps.py index 97b3b9f3..a61d75a0 100644 --- a/team/apps.py +++ b/team/apps.py @@ -9,4 +9,4 @@ class TeamConfig(AppConfig): verbose_name = _('Команда') def ready(self) -> None: - from . import signals + from . import signals \ No newline at end of file diff --git a/team/models.py b/team/models.py index b8b50731..a1afdf94 100644 --- a/team/models.py +++ b/team/models.py @@ -16,4 +16,4 @@ class Meta: verbose_name_plural = _('Члены') def __str__(self) -> str: - return f'@{self.username}' + return f'@{self.username}' \ No newline at end of file diff --git a/team/serializers.py b/team/serializers.py new file mode 100644 index 00000000..6e09f3e5 --- /dev/null +++ b/team/serializers.py @@ -0,0 +1,20 @@ +from django.utils.translation import gettext as _ +from django.template import defaultfilters as filters + +from rest_framework import serializers + +from .models import TeamMember + +from typing import Any + + +class TeamMemberModelSerializer(serializers.ModelSerializer): + class Meta: + model = TeamMember + fields = ['id', 'image', 'username', 'speciality', 'joined_date'] + + def to_representation(self, instance: TeamMember) -> dict[str, Any]: + representation: dict[str, Any] = super().to_representation(instance) + representation['joined_date'] = f'{filters.date(instance.joined_date)} {filters.time(instance.joined_date)}' + + return representation \ No newline at end of file diff --git a/team/signals.py b/team/signals.py index 2da33ca9..5450164a 100644 --- a/team/signals.py +++ b/team/signals.py @@ -8,4 +8,4 @@ @receiver(post_delete, sender=TeamMember) def post_delete_team_member_signal_handler(instance: TeamMember, **kwargs: Any) -> None: - instance.image.delete(save=False) + instance.image.delete(save=False) \ No newline at end of file diff --git a/team/static/team/index/src/main.css b/team/static/team/index/src/main.css deleted file mode 100644 index c384f5d7..00000000 --- a/team/static/team/index/src/main.css +++ /dev/null @@ -1,6 +0,0 @@ -.team-member-image { - width: 150px; - height: 150px; - - border-radius: 50%; -} \ No newline at end of file diff --git a/team/templates/team/index.html b/team/templates/team/index.html deleted file mode 100644 index d63fa856..00000000 --- a/team/templates/team/index.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Команда' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TEAM:INDEX' %} -{% endblock styles %} - -{% block main %} -
-
- {% for team_member in team_members %} -
- {% if team_member.image %} - - {% endif %} - @{{ team_member.username }} - {{ team_member.speciality }} -
- {% endfor %} -
-
-{% endblock main %} \ No newline at end of file diff --git a/team/tests.py b/team/tests.py index 0fa78ae9..25f46070 100644 --- a/team/tests.py +++ b/team/tests.py @@ -28,4 +28,4 @@ def test_team_view(self) -> None: response: HttpResponse = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'team/index.html') + self.assertTemplateUsed(response, 'team/index.html') \ No newline at end of file diff --git a/team/translation.py b/team/translation.py index e156a978..05860d22 100644 --- a/team/translation.py +++ b/team/translation.py @@ -5,4 +5,4 @@ @register(TeamMember) class TeamMemberTranslationOptions(TranslationOptions): - fields = ('speciality',) + fields = ['speciality'] \ No newline at end of file diff --git a/team/urls.py b/team/urls.py index 996b1704..ea118f36 100644 --- a/team/urls.py +++ b/team/urls.py @@ -1,9 +1,8 @@ from django.urls import path -from .views import index_view +from .views import TeamMembersAPIView -app_name = 'team' urlpatterns = [ - path('', index_view, name='index'), -] + path('members/', TeamMembersAPIView.as_view(), name='team-members'), +] \ No newline at end of file diff --git a/team/views.py b/team/views.py index a484fe46..d7268ce4 100644 --- a/team/views.py +++ b/team/views.py @@ -1,8 +1,19 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render +from rest_framework.views import APIView +from rest_framework.request import Request +from rest_framework.response import Response from .models import TeamMember +from .serializers import TeamMemberModelSerializer -def index_view(request: HttpRequest) -> HttpResponse: - return render(request, 'team/index.html', {'team_members': TeamMember.objects.all()}) +class TeamMembersAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def get(self, request: Request) -> Response: + return Response( + TeamMemberModelSerializer( + TeamMember.objects.all(), + many=True, + ).data + ) \ No newline at end of file diff --git a/telegram_bot/admin.py b/telegram_bot/admin.py index 177f1668..6a900622 100644 --- a/telegram_bot/admin.py +++ b/telegram_bot/admin.py @@ -7,19 +7,16 @@ from .models import TelegramBot, TelegramBotUser from .tasks import start_telegram_bot as celery_start_telegram_bot -import sys - @admin.register(TelegramBot) class TelegramBotAdmin(admin.ModelAdmin): - search_fields = ('username',) + search_fields = ['username'] date_hierarchy = 'added_date' - list_filter = ('is_running', 'added_date') - - actions = ('start_telegram_bot_action', 'stop_telegram_bot_action') + list_filter = ['is_running', 'added_date'] + actions = ['start_telegram_bot_action', 'stop_telegram_bot_action'] + list_display = ['id', 'owner', 'username_', 'is_private', 'is_running', 'commands_count', 'users_count', 'added_date'] - list_display = ('id', 'owner', 'username_', 'is_private', 'is_running', 'commands_count', 'users_count', 'added_date') - fields = ('id', 'owner', 'username_', 'api_token', 'is_private', 'is_running', 'commands_count', 'users_count', 'added_date') + fields = ['id', 'owner', 'username_', 'api_token', 'is_private', 'is_running', 'commands_count', 'users_count', 'added_date'] @admin.display(description='@username', ordering='username') def username_(self, telegram_bot: TelegramBot) -> str: @@ -37,10 +34,7 @@ def users_count(self, telegram_bot: TelegramBot) -> int: def start_telegram_bot_action(self, request: HttpRequest, telegram_bots: list[TelegramBot]) -> None: for telegram_bot in telegram_bots: if not telegram_bot.is_running and telegram_bot.is_stopped: - if sys.platform == 'win32': - celery_start_telegram_bot(telegram_bot_id=telegram_bot.id) - else: - celery_start_telegram_bot.delay(telegram_bot_id=telegram_bot.id) + celery_start_telegram_bot.delay(telegram_bot_id=telegram_bot.id) messages.success(request, f"@{telegram_bot.username} {_('Telegram бот успешно включен.')}") else: @@ -64,15 +58,15 @@ def has_change_permission(self, *args, **kwargs) -> bool: @admin.register(TelegramBotUser) class TelegramBotUserAdmin(admin.ModelAdmin): - search_fields = ('user_id', 'full_name') + search_fields = ['user_id', 'full_name'] date_hierarchy = 'activated_date' - list_filter = ('activated_date',) + list_filter = ['activated_date'] + list_display = ['id', 'telegram_bot', 'user_id', 'full_name', 'is_allowed', 'activated_date'] - list_display = ('id', 'telegram_bot', 'user_id', 'full_name', 'is_allowed', 'activated_date') - fields = ('id', 'telegram_bot', 'user_id', 'full_name', 'is_allowed', 'activated_date') + fields = ['id', 'telegram_bot', 'user_id', 'full_name', 'is_allowed', 'activated_date'] def has_add_permission(self, *args, **kwargs) -> bool: return False def has_change_permission(self, *args, **kwargs) -> bool: - return False + return False \ No newline at end of file diff --git a/telegram_bot/api/__init__.py b/telegram_bot/api/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/telegram_bot/api/decorators.py b/telegram_bot/api/decorators.py deleted file mode 100644 index ad96d584..00000000 --- a/telegram_bot/api/decorators.py +++ /dev/null @@ -1,56 +0,0 @@ -from django.utils.translation import gettext as _ - -from constructor_telegram_bots.utils.drf import CustomResponse - -from ..models import ( - TelegramBot, - TelegramBotCommand, - TelegramBotCommandKeyboard, - TelegramBotCommandKeyboardButton, - TelegramBotUser, -) - -from functools import wraps - - -def check_telegram_bot_command_id(func): - @wraps(func) - def wrapper(*args, **kwargs): - telegram_bot: TelegramBot = kwargs['telegram_bot'] - telegram_bot_command_id: int = kwargs.pop('telegram_bot_command_id', 0) - - try: - kwargs['telegram_bot_command'] = telegram_bot.commands.get(id=telegram_bot_command_id) - except TelegramBotCommand.DoesNotExist: - return CustomResponse(_('Команда Telegram бота не найдена!'), status=404) - - return func(*args, **kwargs) - return wrapper - -def check_telegram_bot_command_keyboard_button_id(func): - @wraps(func) - def wrapper(*args, **kwargs): - telegram_bot_command: TelegramBotCommand = kwargs['telegram_bot_command'] - telegram_bot_command_keyboard: TelegramBotCommandKeyboard = telegram_bot_command.keyboard - telegram_bot_command_keyboard_button_id: int = kwargs.pop('telegram_bot_command_keyboard_button_id', 0) - - try: - kwargs['telegram_bot_command_keyboard_button'] = telegram_bot_command_keyboard.buttons.get(id=telegram_bot_command_keyboard_button_id) - except TelegramBotCommandKeyboardButton.DoesNotExist: - return CustomResponse(_('Кнопка клавиатуры команды Telegram бота не найдена!'), status=404) - - return func(*args, **kwargs) - return wrapper - -def check_telegram_bot_user_id(func): - def wrapper(*args, **kwargs): - telegram_bot: TelegramBot = kwargs['telegram_bot'] - telegram_bot_user_id: int = kwargs.pop('telegram_bot_user_id', 0) - - try: - kwargs['telegram_bot_user'] = telegram_bot.users.get(id=telegram_bot_user_id) - except TelegramBotUser.DoesNotExist: - return CustomResponse(_('Пользователь Telegram бота не найдена!'), status=404) - - return func(*args, **kwargs) - return wrapper diff --git a/telegram_bot/api/serializers/__init__.py b/telegram_bot/api/serializers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/telegram_bot/api/static/telegram_bot/api/main.ts b/telegram_bot/api/static/telegram_bot/api/main.ts deleted file mode 100644 index 9c482d60..00000000 --- a/telegram_bot/api/static/telegram_bot/api/main.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { ApiResponse as BaseApiResponse, makeRequest } from 'global_modules/api'; -import * as Types from './types'; - -declare const userApiToken: string; - -namespace Base { - export const url = '/api/telegram-bots/'; - export const headers: HeadersInit = {'Authorization': `Token ${userApiToken}`} -} - -export namespace TelegramBotsApi { - export const url = Base.url; - - export function get(): Promise> { - return makeRequest(url, 'GET', Base.headers); - } -} - -export namespace TelegramBotApi { - export const url = (telegramBotId: Types.TelegramBot['id']): string => `${TelegramBotsApi.url}${telegramBotId}/`; - - export function get(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } - export function create(data: Types.Data.TelegramBot.Create): Promise> { - return makeRequest(TelegramBotsApi.url, 'POST', Base.headers, data); - } - export function update( - telegramBotId: Types.TelegramBot['id'], - data: Types.Data.TelegramBot.Update, - ): Promise> { - return makeRequest(url(telegramBotId), 'PATCH', Base.headers, data); - } - export function delete_(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(url(telegramBotId), 'DELETE', Base.headers); - } - - export function start(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(`${url(telegramBotId)}start-or-stop/`, 'POST', Base.headers); - } - export const stop = start; - - export function updateDiagramCurrentScale( - telegramBotId: Types.TelegramBot['id'], - data: Types.Data.TelegramBot.UpdateDiagramCurrentScale, - ): Promise> { - return makeRequest(`${url(telegramBotId)}update-diagram-current-scale/`, 'PATCH', Base.headers, data); - } -} - -export namespace TelegramBotCommandsApi { - export const url = (telegramBotId: Types.TelegramBot['id']): string => `${TelegramBotApi.url(telegramBotId)}commands/`; - - export function get(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } -} - -export namespace TelegramBotCommandApi { - export const url = ( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - ): string => `${TelegramBotCommandsApi.url(telegramBotId)}${telegramBotCommandId}/`; - - export function get( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotCommandId), 'GET', Base.headers); - } - export function create( - telegramBotId: Types.TelegramBot['id'], - data: Types.Data.TelegramBotCommand.Create, - ): Promise> { - const formData = new FormData(); - formData.append('image', data.image); - formData.append('data', JSON.stringify(data.data)); - - return makeRequest(TelegramBotCommandsApi.url(telegramBotId), 'POST', Base.headers, formData); - } - export function update( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - data: Types.Data.TelegramBotCommand.Update, - ): Promise> { - const formData = new FormData(); - formData.append('image', data.image); - formData.append('data', JSON.stringify(data.data)); - - return makeRequest(url(telegramBotId, telegramBotCommandId), 'PATCH', Base.headers, formData); - } - export function delete_( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotCommandId), 'DELETE', Base.headers); - } - - export function updatePosition( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - data: Types.Data.TelegramBotCommand.UpdatePosition, - ): Promise> { - return makeRequest(`${url(telegramBotId, telegramBotCommandId)}update-position/`, 'PATCH', Base.headers, data); - } -} - -export namespace TelegramBotCommandKeyboardButtonApi { - export const url = ( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - telegramBotCommandKeyboardButtonId: Types.TelegramBotCommandKeyboardButton['id'], - ): string => `${TelegramBotCommandApi.url(telegramBotId, telegramBotCommandId)}keyboard-buttons/${telegramBotCommandKeyboardButtonId}/telegram-bot-command/`; - - export function connect( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - telegramBotCommandKeyboardButtonId: Types.TelegramBotCommandKeyboardButton['id'], - data: Types.Data.TelegramBotCommandKeyboardButton.Connect, - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotCommandId, telegramBotCommandKeyboardButtonId), 'POST', Base.headers, data); - } - export function disconnect( - telegramBotId: Types.TelegramBot['id'], - telegramBotCommandId: Types.TelegramBotCommand['id'], - telegramBotCommandKeyboardButtonId: Types.TelegramBotCommandKeyboardButton['id'], - data: Types.Data.TelegramBotCommandKeyboardButton.Disconnect, - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotCommandId, telegramBotCommandKeyboardButtonId), 'DELETE', Base.headers, data); - } -} - -export namespace TelegramBotUsersApi { - export const url = (telegramBotId: Types.TelegramBot['id']): string => `${TelegramBotApi.url(telegramBotId)}users/`; - - export function get(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } -} - -export namespace TelegramBotUserApi { - export const url = ( - telegramBotId: Types.TelegramBot['id'], - telegramBotUserId: Types.TelegramBotUser['id'], - ): string => `${TelegramBotUsersApi.url(telegramBotId)}${telegramBotUserId}/`; - - export function delete_( - telegramBotId: Types.TelegramBot['id'], - telegramBotUserId: Types.TelegramBotUser['id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotUserId), 'DELETE', Base.headers); - } -} - -export namespace TelegramBotAllowedUserApi { - export const url = ( - telegramBotId: Types.TelegramBot['id'], - telegramBotUserId: Types.TelegramBotUser['id'], - ): string => `${TelegramBotUserApi.url(telegramBotId, telegramBotUserId)}allowed-user/`; - - export function set( - telegramBotId: Types.TelegramBot['id'], - telegramBotUserId: Types.TelegramBotUser['id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotUserId), 'POST', Base.headers); - } - export function unset( - telegramBotId: Types.TelegramBot['id'], - telegramBotUserId: Types.TelegramBotUser['id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotUserId), 'DELETE', Base.headers); - } -} - -export namespace TelegramBotDatabaseRecordsApi { - export const url = (telegramBotId: Types.TelegramBot['id']): string => `${TelegramBotApi.url(telegramBotId)}database/records/`; - - export function get(telegramBotId: Types.TelegramBot['id']): Promise> { - return makeRequest(url(telegramBotId), 'GET', Base.headers); - } -} - -export namespace TelegramBotDatabaseRecordApi { - export const url = ( - telegramBotId: Types.TelegramBot['id'], - telegramBotDatabaseRecordId: Types.TelegramBotDatabaseRecord['_id'], - ): string => `${TelegramBotDatabaseRecordsApi.url(telegramBotId)}${telegramBotDatabaseRecordId}/`; - - export function create( - telegramBotId: Types.TelegramBot['id'], - data: Types.Data.TelegramBotDatabaseRecord.Create, - ): Promise> { - return makeRequest(TelegramBotDatabaseRecordsApi.url(telegramBotId), 'POST', Base.headers, data); - } - export function update( - telegramBotId: Types.TelegramBot['id'], - telegramBotDatabaseRecordId: Types.TelegramBotDatabaseRecord['_id'], - data: Types.Data.TelegramBotDatabaseRecord.Update, - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotDatabaseRecordId), 'PATCH', Base.headers, data); - } - export function delete_( - telegramBotId: Types.TelegramBot['id'], - telegramBotDatabaseRecordId: Types.TelegramBotDatabaseRecord['_id'], - ): Promise> { - return makeRequest(url(telegramBotId, telegramBotDatabaseRecordId), 'DELETE', Base.headers); - } -} \ No newline at end of file diff --git a/telegram_bot/api/static/telegram_bot/api/types.ts b/telegram_bot/api/static/telegram_bot/api/types.ts deleted file mode 100644 index a161d4b1..00000000 --- a/telegram_bot/api/static/telegram_bot/api/types.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { ObjectAsJson, ApiResponse as BaseApiResponse } from 'global_modules/api'; - -export interface TelegramBot { - id: number; - username: string | null; - api_token: string; - is_private: boolean; - is_running: boolean; - is_stopped: boolean; - commands_count: number; - users_count: number; - added_date: string; -} - -interface TelegramBotCommandCommand { - text: string; - is_show_in_menu: boolean; - description: string | null; -} - -interface TelegramBotCommandMessageText { - text: string; -} - -export interface TelegramBotCommandKeyboardButton { - id: number; - row: number | null; - text: string; - url: string | null; - - telegram_bot_command_id: number | null; - start_diagram_connector: number | null; - end_diagram_connector: number | null; -} - -interface TelegramBotCommandKeyboard { - mode: 'default' | 'inline' | 'payment'; - buttons: TelegramBotCommandKeyboardButton[]; -} - -interface TelegramBotCommandApiRequest { - url: string; - method: 'get' | 'post' | 'put' | 'patch' | 'delete'; - headers: ObjectAsJson | null; - data: ObjectAsJson | null; -} - -export interface TelegramBotCommand { - id: number; - name: string; - command: TelegramBotCommandCommand | null; - image: string | null; - message_text: TelegramBotCommandMessageText; - keyboard: TelegramBotCommandKeyboard | null; - api_request: TelegramBotCommandApiRequest | null; - database_record: ObjectAsJson | null; - - x: number; - y: number; -} - -export interface TelegramBotUser { - id: number; - user_id: number; - full_name: string | null; - is_allowed: boolean; - activated_date: string; -} - -export interface TelegramBotDatabaseRecord extends ObjectAsJson { - _id: number; -} - -export namespace Data { - export namespace TelegramBot { - export interface Create { - api_token: TelegramBot['api_token']; - is_private: TelegramBot['is_private']; - } - export interface Update { - api_token: TelegramBot['api_token'] | null; - is_private: TelegramBot['is_private'] | null; - } - - export interface UpdateDiagramCurrentScale { - diagram_current_scale: number; - } - } - - export namespace TelegramBotCommand { - type CreateTelegramBotCommandKeyboardButton = Omit; - - interface CreateTelegramBotCommandKeyboard extends Omit { - buttons: CreateTelegramBotCommandKeyboardButton[]; - } - - interface CreateTelegramBotCommand extends Omit { - keyboard: CreateTelegramBotCommandKeyboard | null; - } - - export interface Create { - image: Blob; - data: CreateTelegramBotCommand; - } - - type UpdateTelegramBotCommandKeyboardButton = Omit; - - interface UpdateTelegramBotCommandKeyboard extends Omit { - buttons: UpdateTelegramBotCommandKeyboardButton[]; - } - - interface UpdateTelegramBotCommand extends Omit { - keyboard: UpdateTelegramBotCommandKeyboard | null; - } - - export interface Update { - image: Blob; - data: UpdateTelegramBotCommand; - } - - export interface UpdatePosition { - x: number; - y: number; - } - } - - export namespace TelegramBotCommandKeyboardButton { - export type Connect = Omit; - export type Disconnect = Connect; - } - - export namespace TelegramBotDatabaseRecord { - export interface Create { - record: Omit; - } - export type Update = Create; - } -} - -export namespace ApiResponse { - export namespace TelegramBot { - export interface Create extends BaseApiResponse.Success { - telegram_bot: TelegramBot; - } - } - - export namespace TelegramBotDatabaseRecord { - export interface Create extends BaseApiResponse.Success { - record: TelegramBotDatabaseRecord; - } - export type Update = Create; - } -} \ No newline at end of file diff --git a/telegram_bot/api/tests.py b/telegram_bot/api/tests.py deleted file mode 100644 index 15ab3634..00000000 --- a/telegram_bot/api/tests.py +++ /dev/null @@ -1,996 +0,0 @@ -from django.http import HttpResponse -from django import urls - -from ..tests import BaseTestCase -from ..services import database_telegram_bot - - -class TelegramBotsViewTests(BaseTestCase): - url: str = urls.reverse('telegram_bots') - - def test_post_method(self) -> None: - response: HttpResponse = self.client.post(self.url) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post( - self.url, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '', - 'is_private': False, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '123456789:qwertyuiop', - 'is_private': False, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.post( - self.url, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '987654321:dwawdadwa', - 'is_private': False, - }, - ) - self.assertEqual(response.status_code, 200) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('telegram_bot', kwargs={'telegram_bot_id': 0}) - - def test_patch_method(self) -> None: - response: HttpResponse = self.client.patch(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.patch( - self.url_2, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': None, - 'is_private': None, - }, - ) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': None, - 'is_private': None, - }, - ) - self.assertEqual(response.status_code, 500) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '', - 'is_private': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '123456789:qwertyuiop', - 'is_private': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': '987654321:dwawdadwa', - 'is_private': None, - }, - ) - self.assertEqual(response.status_code, 200) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': None, - 'is_private': False, - }, - ) - self.assertEqual(response.status_code, 200) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'api_token': None, - 'is_private': True, - }, - ) - self.assertEqual(response.status_code, 200) - - def test_delete_method(self) -> None: - response: HttpResponse = self.client.delete(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.delete(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.get(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class StartOrStopTelegramBotViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('start_or_stop_telegram_bot', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('start_or_stop_telegram_bot', kwargs={'telegram_bot_id': 0}) - - def test_start_or_stop_telegram_bot_view(self) -> None: - response: HttpResponse = self.client.post(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class UpdateTelegramBotDiagramCurrentScaleViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('update_telegram_bot_diagram_current_scale', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('update_telegram_bot_diagram_current_scale', kwargs={'telegram_bot_id': 0}) - - def test_patch_method(self) -> None: - response: HttpResponse = self.client.patch(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.patch(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={'diagram_current_scale': 0.8}, - ) - self.assertEqual(response.status_code, 200) - -class TelegramBotCommandsViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_commands', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('telegram_bot_commands', kwargs={'telegram_bot_id': 0}) - - def test_post_method(self) -> None: - response: HttpResponse = self.client.post(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': '', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': ''}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': { - 'text': '', - 'is_show_in_menu': False, - 'description': None - }, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': { - 'text': '/start', - 'is_show_in_menu': True, - 'description': '' - }, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': ''}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': None, - 'row': None, - 'text': '', - 'url': None, - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': None, - 'row': None, - 'text': '1', - 'url': '', - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': None, - 'row': None, - 'text': '1', - 'url': '-', - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': { - 'url': '', - 'method': 'get', - 'headers': None, - 'data': None, - }, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': { - 'url': 'test', - 'method': 'get', - 'headers': None, - 'data': None, - }, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 200) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.get(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotCommandViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_command', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': self.telegram_bot_command.id, - }) - self.url_2: str = urls.reverse('telegram_bot_command', kwargs={ - 'telegram_bot_id': 0, - 'telegram_bot_command_id': self.telegram_bot_command.id, - }) - self.url_3: str = urls.reverse('telegram_bot_command', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': 0, - }) - - def test_patch_method(self) -> None: - response: HttpResponse = self.client.patch(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.patch(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': '', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': ''}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': { - 'text': '', - 'is_show_in_menu': False, - 'description': None, - }, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': { - 'text': '/start', - 'is_show_in_menu': True, - 'description': '', - }, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': '1', - 'row': None, - 'text': '', - 'url': None, - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': '1', - 'row': None, - 'text': '1', - 'url': '', - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': { - 'mode': 'default', - 'buttons': [ - { - 'id': '1', - 'row': None, - 'text': '1', - 'url': '-', - }, - ], - }, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': { - 'url': '', - 'method': 'get', - 'headers': None, - 'data': None, - }, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'blank') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': { - 'url': 'test', - 'method': 'get', - 'headers': None, - 'data': None, - }, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json()['code'], 'invalid') - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'name': 'Test', - 'command': None, - 'message_text': {'text': 'Test...'}, - 'keyboard': None, - 'api_request': None, - 'database_record': None, - }, - ) - self.assertEqual(response.status_code, 200) - - def test_delete_method(self) -> None: - response: HttpResponse = self.client.delete(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.delete(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.get(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.get(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class UpdateTelegramBotCommandPositionViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('update_telegram_bot_command_position', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': self.telegram_bot_command.id, - }) - self.url_2: str = urls.reverse('update_telegram_bot_command_position', kwargs={ - 'telegram_bot_id': 0, - 'telegram_bot_command_id': self.telegram_bot_command.id, - }) - self.url_3: str = urls.reverse('update_telegram_bot_command_position', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': 0, - }) - - def test_patch_method(self) -> None: - response: HttpResponse = self.client.patch(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.patch(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.patch( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'x': 123, - 'y': 321, - }, - ) - self.assertEqual(response.status_code, 200) - -class TelegramBotCommandKeyboardButtonTelegramBotCommandViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - telegram_bot_command_keyboard_button_id: int = self.telegram_bot_command.keyboard.buttons.all()[0].id - - self.url_1: str = urls.reverse('telegram_bot_command_keyboard_button_telegram_bot_command', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': self.telegram_bot_command.id, - 'telegram_bot_command_keyboard_button_id': telegram_bot_command_keyboard_button_id, - }) - self.url_2: str = urls.reverse('telegram_bot_command_keyboard_button_telegram_bot_command', kwargs={ - 'telegram_bot_id': 0, - 'telegram_bot_command_id': self.telegram_bot_command.id, - 'telegram_bot_command_keyboard_button_id': telegram_bot_command_keyboard_button_id, - }) - self.url_3: str = urls.reverse('telegram_bot_command_keyboard_button_telegram_bot_command', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': 0, - 'telegram_bot_command_keyboard_button_id': telegram_bot_command_keyboard_button_id, - }) - self.url_4: str = urls.reverse('telegram_bot_command_keyboard_button_telegram_bot_command', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_command_id': self.telegram_bot_command.id, - 'telegram_bot_command_keyboard_button_id': 0, - }) - - def test_post_method(self) -> None: - response: HttpResponse = self.client.post(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post(self.url_4, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post( - self.url_3, - headers=self.base_headers, - content_type='application/json', - data={ - 'telegram_bot_command_id': 0, - 'start_diagram_connector': 'test', - 'end_diagram_connector': 'test', - }, - ) - self.assertEqual(response.status_code, 404) - - telegram_bot_command: TelegramBotCommand = TelegramBotCommand.objects.create( - telegram_bot=self.telegram_bot, - name='Test', - command=None, - image=None, - message_text={'text': 'Test...'}, - keyboard = None, - api_request = None, - database_record = None, - ) - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={ - 'telegram_bot_command_id': telegram_bot_command.id, - 'start_diagram_connector': 'test', - 'end_diagram_connector': 'test', - }, - ) - self.assertEqual(response.status_code, 200) - - def test_delete_method(self) -> None: - response: HttpResponse = self.client.delete(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.delete(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_4, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotUsersViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_users', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('telegram_bot_users', kwargs={'telegram_bot_id': 0}) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.get(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotUserViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_user', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_user_id': self.telegram_bot_user.id, - }) - self.url_2: str = urls.reverse('telegram_bot_user', kwargs={ - 'telegram_bot_id': 0, - 'telegram_bot_user_id': self.telegram_bot_user.id, - }) - self.url_3: str = urls.reverse('telegram_bot_user', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_user_id': 0, - }) - - def test_delete_method(self) -> None: - response: HttpResponse = self.client.delete(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.delete(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotAllowedUserViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_allowed_user', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_user_id': self.telegram_bot_user.id, - }) - self.url_2: str = urls.reverse('telegram_bot_allowed_user', kwargs={ - 'telegram_bot_id': 0, - 'telegram_bot_user_id': self.telegram_bot_user.id, - }) - self.url_3: str = urls.reverse('telegram_bot_allowed_user', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'telegram_bot_user_id': 0, - }) - - def test_post_method(self) -> None: - response: HttpResponse = self.client.post(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - - def test_delete_method(self) -> None: - response: HttpResponse = self.client.delete(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.delete(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_3, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.delete(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - -class TelegramBotDatabeseRecordsViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_databese_records', kwargs={'telegram_bot_id': self.telegram_bot.id}) - self.url_2: str = urls.reverse('telegram_bot_databese_records', kwargs={'telegram_bot_id': 0}) - - def tearDown(self) -> None: - database_telegram_bot.delete_collection(self.telegram_bot) - - def test_post_method(self) -> None: - response: HttpResponse = self.client.post(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.post(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - response: HttpResponse = self.client.post( - self.url_1, - headers=self.base_headers, - content_type='application/json', - data={'record': {'key': 'value'}}, - ) - self.assertEqual(response.status_code, 200) - - def test_get_method(self) -> None: - response: HttpResponse = self.client.get(self.url_1) - self.assertEqual(response.status_code, 401) - - response: HttpResponse = self.client.get(self.url_2, headers=self.base_headers) - self.assertEqual(response.status_code, 404) - - database_telegram_bot.insert_record(self.telegram_bot, {'key': 'value'}) - - response: HttpResponse = self.client.get(self.url_1, headers=self.base_headers) - self.assertEqual(response.status_code, 200) - self.assertJSONEqual(response.content, [{'_id': 1, 'key': 'value'}]) - -class TelegramBotDatabeseRecordViewTests(BaseTestCase): - def setUp(self) -> None: - super().setUp() - - self.url_1: str = urls.reverse('telegram_bot_databese_record', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'record_id': 1, - }) - self.url_2: str = urls.reverse('telegram_bot_databese_record', kwargs={ - 'telegram_bot_id': 0, - 'record_id': 0, - }) - self.url_3: str = urls.reverse('telegram_bot_databese_record', kwargs={ - 'telegram_bot_id': self.telegram_bot.id, - 'record_id': 0, - }) - - def tearDown(self) -> None: - database_telegram_bot.delete_collection(self.telegram_bot) - - def test_patch_method(self) -> None: - # TODO: Надо написать тесты для PATCH метода. - pass - - def test_delete_method(self) -> None: - # TODO: Надо написать тесты для DELETE метода. - pass diff --git a/telegram_bot/api/urls.py b/telegram_bot/api/urls.py deleted file mode 100644 index a8d9a8b2..00000000 --- a/telegram_bot/api/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.urls import path - -from . import views - - -app_name = 'api' -urlpatterns = [ - path('', views.TelegramBotsView.as_view(), name='telegram_bots'), # POST, GET - path('/', views.TelegramBotView.as_view(), name='telegram_bot'), # PATCH, DELETE, GET - path('/start-or-stop/', views.start_or_stop_telegram_bot, name='start_or_stop_telegram_bot'), # POST - path('/update-diagram-current-scale/', views.update_telegram_bot_diagram_current_scale, name='update_telegram_bot_diagram_current_scale'), # PATCH - - path('/commands/', views.TelegramBotCommandsView.as_view(), name='telegram_bot_commands'), # POST, GET - path('/commands//', views.TelegramBotCommandView.as_view(), name='telegram_bot_command'), # PATCH, DELETE, GET - path('/commands//update-position/', views.update_telegram_bot_command_position, name='update_telegram_bot_command_position'), # PATCH - path('/commands//keyboard-buttons//telegram-bot-command/', views.TelegramBotCommandKeyboardButtonTelegramBotCommandView.as_view(), name='telegram_bot_command_keyboard_button_telegram_bot_command'), # POST, DELETE - - path('/users/', views.TelegramBotUsersView.as_view(), name='telegram_bot_users'), # GET - path('/users//', views.TelegramBotUserView.as_view(), name='telegram_bot_user'), # DELETE - path('/users//allowed-user/', views.TelegramBotAllowedUserView.as_view(), name='telegram_bot_allowed_user'), # POST, DELETE - - path('/database/records/', views.TelegramBotDatabeseRecordsView.as_view(), name='telegram_bot_databese_records'), # POST, GET - path('/database/records//', views.TelegramBotDatabeseRecordView.as_view(), name='telegram_bot_databese_record'), # PATCH, DELETE -] diff --git a/telegram_bot/apps.py b/telegram_bot/apps.py index b52fd778..edd0f77b 100644 --- a/telegram_bot/apps.py +++ b/telegram_bot/apps.py @@ -9,4 +9,4 @@ class TelegramBotConfig(AppConfig): verbose_name = _('Telegram боты') def ready(self) -> None: - from . import signals + from . import signals \ No newline at end of file diff --git a/telegram_bot/decorators.py b/telegram_bot/decorators.py index 90a7af44..188176f3 100644 --- a/telegram_bot/decorators.py +++ b/telegram_bot/decorators.py @@ -1,10 +1,8 @@ -from django.http import HttpRequest from django.utils.translation import gettext as _ from rest_framework.request import Request from constructor_telegram_bots.utils.drf import CustomResponse -from constructor_telegram_bots.utils.shortcuts import render_success_or_error from .models import TelegramBot @@ -14,23 +12,55 @@ def check_telegram_bot_id(func): @wraps(func) def wrapper(*args, **kwargs): - request: HttpRequest | Request = args[-1] + request: Request = args[-1] telegram_bot_id: int = kwargs.pop('telegram_bot_id', 0) try: kwargs['telegram_bot'] = request.user.telegram_bots.get(id=telegram_bot_id) except TelegramBot.DoesNotExist: - status = 404 - - if isinstance(request, HttpRequest): - return render_success_or_error( - request, - 'Telegram бот не найден!', - _('Автоматический переход на главную страницу через 3 секунды.'), - status=404, - ) - else: - return CustomResponse(_('Telegram бот не найден!'), status=status) + return CustomResponse(_('Telegram бот не найден!'), status=404) return func(*args, **kwargs) return wrapper + +def check_telegram_bot_command_id(func): + @wraps(func) + def wrapper(*args, **kwargs): + telegram_bot: TelegramBot = kwargs['telegram_bot'] + telegram_bot_command_id: int = kwargs.pop('telegram_bot_command_id', 0) + + try: + kwargs['telegram_bot_command'] = telegram_bot.commands.get(id=telegram_bot_command_id) + except TelegramBotCommand.DoesNotExist: + return CustomResponse(_('Команда Telegram бота не найдена!'), status=404) + + return func(*args, **kwargs) + return wrapper + +def check_telegram_bot_command_keyboard_button_id(func): + @wraps(func) + def wrapper(*args, **kwargs): + telegram_bot_command: TelegramBotCommand = kwargs['telegram_bot_command'] + telegram_bot_command_keyboard: TelegramBotCommandKeyboard = telegram_bot_command.keyboard + telegram_bot_command_keyboard_button_id: int = kwargs.pop('telegram_bot_command_keyboard_button_id', 0) + + try: + kwargs['telegram_bot_command_keyboard_button'] = telegram_bot_command_keyboard.buttons.get(id=telegram_bot_command_keyboard_button_id) + except TelegramBotCommandKeyboardButton.DoesNotExist: + return CustomResponse(_('Кнопка клавиатуры команды Telegram бота не найдена!'), status=404) + + return func(*args, **kwargs) + return wrapper + +def check_telegram_bot_user_id(func): + def wrapper(*args, **kwargs): + telegram_bot: TelegramBot = kwargs['telegram_bot'] + telegram_bot_user_id: int = kwargs.pop('telegram_bot_user_id', 0) + + try: + kwargs['telegram_bot_user'] = telegram_bot.users.get(id=telegram_bot_user_id) + except TelegramBotUser.DoesNotExist: + return CustomResponse(_('Пользователь Telegram бота не найдена!'), status=404) + + return func(*args, **kwargs) + return wrapper \ No newline at end of file diff --git a/telegram_bot/frontend/__init__.py b/telegram_bot/frontend/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/telegram_bot/frontend/static/telegram_bot/frontend/components/TelegramBotCard.tsx b/telegram_bot/frontend/static/telegram_bot/frontend/components/TelegramBotCard.tsx deleted file mode 100644 index eb362e70..00000000 --- a/telegram_bot/frontend/static/telegram_bot/frontend/components/TelegramBotCard.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import Toast from 'global_modules/toast'; -import { TelegramBotApi } from 'telegram_bot_api/main'; -import { TelegramBot } from 'telegram_bot_api/types'; -import React from 'react'; - -declare const telegramBotCardHeaderIsRunningText: string; -declare const telegramBotCardHeaderIsNotRunningText: string; -declare const telegramBotCardBodyTableLineApiTokenText: string; -declare const telegramBotCardBodyTableLineApiTokenInputPlaceholderText: string; -declare const telegramBotCardBodyTableLineIsPrivateText: string; -declare const telegramBotCardBodyTableLineDateAddedText: string; - -type TelegramBotContextType = { - telegramBot: TelegramBot; - setTelegramBot: React.Dispatch>; -} - -export const TelegramBotContext = React.createContext(null); - -const buttonWithOnlyIconStyle: React.CSSProperties = { - cursor: 'pointer', - fontSize: '20px', -} - -export function TelegramBotCardHeader(): React.JSX.Element { - const telegramBotContext = React.useContext(TelegramBotContext)!; - const telegramBot = telegramBotContext.telegramBot; - - let color: 'success' | 'danger', text: string; - - if (!telegramBot.is_running && telegramBot.is_stopped) { - [color, text] = ['danger', telegramBotCardHeaderIsNotRunningText]; - } else { - [color, text] = ['success', telegramBotCardHeaderIsRunningText]; - } - - return
{text}
; -} - -export function TelegramBotCardBody(): React.JSX.Element { - const telegramBotContext = React.useContext(TelegramBotContext)!; - const [telegramBot, setTelegramBot] = [telegramBotContext.telegramBot, telegramBotContext.setTelegramBot]; - const [apiTokenIsEditing, setApiTokenIsEditing] = React.useState(false); - const [apiTokenInputValue, setApiTokenInputValue] = React.useState(telegramBot.api_token); - - function toggleApiToken (): void { - if (!apiTokenIsEditing) { - setApiTokenInputValue(telegramBot.api_token); - } - - setApiTokenIsEditing(!apiTokenIsEditing); - } - - async function handleApiTokenSaveButtonClick(): Promise { - const response = await TelegramBotApi.update(telegramBot.id, { - api_token: apiTokenInputValue, - is_private: null, - }); - - if (response.ok) { - setTelegramBot({...telegramBot, api_token: apiTokenInputValue}); - toggleApiToken(); - } - - new Toast(response.json.message, response.json.level).show(); - } - - async function handleIsPrivateCheckboxChange(event: {target: {checked: boolean}}): Promise { - const response = await TelegramBotApi.update(telegramBot.id, { - api_token: null, - is_private: event.target.checked, - }); - - if (response.ok) { - setTelegramBot({...telegramBot, is_private: event.target.checked}); - } - - new Toast(response.json.message, response.json.level).show(); - } - - return ( -
- - - - - - - - - - - - - - - - - - - -
@username: - @{telegramBot.username} -
{telegramBotCardBodyTableLineApiTokenText}: -
- {apiTokenIsEditing ? ( - setApiTokenInputValue(event.target.value)} - placeholder={telegramBotCardBodyTableLineApiTokenInputPlaceholderText} - value={apiTokenInputValue} - /> - ) : ( - {telegramBot.api_token} - )} -
- {apiTokenIsEditing ? ( - <> - - - - ) : ( - - )} -
-
-
{telegramBotCardBodyTableLineIsPrivateText}: -
- -
-
{telegramBotCardBodyTableLineDateAddedText}:{telegramBot.added_date}
-
- ); -} - -interface TelegramBotCardProps { - telegramBotInitial: TelegramBot, - children?: React.JSX.Element, -} - -export default function TelegramBotCard({telegramBotInitial, children}: TelegramBotCardProps): React.JSX.Element { - const [telegramBot, setTelegramBot] = React.useState(telegramBotInitial); - - return ( -
- - - - {children} - -
- ); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/animation/main.css b/telegram_bot/frontend/static/telegram_bot_menu/animation/main.css deleted file mode 100644 index 55626610..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/animation/main.css +++ /dev/null @@ -1,19 +0,0 @@ -.btn-toggle i::before { - transition: transform .40s ease; - transform-origin: 0.5em 50%; - transform: rotate(180deg); -} - -.btn-toggle[aria-expanded="true"] i::before { - transform: rotate(360deg); -} - -.btn-update[aria-updating="true"] i::before { - animation-name: btn-update; - animation-duration: 1s; - animation-iteration-count: 1; -} - -@keyframes btn-update { - 0% {transform: rotate(360deg)} -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/animation/main.ts b/telegram_bot/frontend/static/telegram_bot_menu/animation/main.ts deleted file mode 100644 index d3870ad1..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/animation/main.ts +++ /dev/null @@ -1,10 +0,0 @@ -import './main.css'; - -document.querySelectorAll('.btn-update').forEach(updateButtonElement => { - updateButtonElement.addEventListener('click', (): void => { - if (updateButtonElement.getAttribute('aria-updating') === 'false') { - updateButtonElement.setAttribute('aria-updating', 'true'); - setTimeout((): void => updateButtonElement.setAttribute('aria-updating', 'false'), 900); - } - }) -}); \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/AddRecordModalBody.tsx b/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/AddRecordModalBody.tsx deleted file mode 100644 index d384c4d4..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/AddRecordModalBody.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import Toast from 'global_modules/toast'; -import { updateEditorLayout, defaultEditorOptions } from 'global_modules/monaco_editor'; -import { TelegramBotDatabaseRecordApi } from 'telegram_bot_api/main'; -import monaco from 'monaco-editor'; -import Editor from '@monaco-editor/react'; -import React from 'react'; - -declare const telegramBotId: number; - -const buttonWithOnlyIconStyle: React.CSSProperties = { - fontSize: '20px', -} - -interface AddRecordModalBodyProps { - onAdd: () => void; - onCancel: () => void; -} - -export default function AddRecordModalBody({onAdd, onCancel}: AddRecordModalBodyProps): React.JSX.Element { - const editorRef = React.useRef(); - - function resetEditorValue(): void { - editorRef.current!.setValue(JSON.stringify({key: 'value'}, null, 4)); - - updateEditorLayout(editorRef.current!); - } - - function handleEditorDidMount(editor: monaco.editor.IStandaloneCodeEditor): void { - editorRef.current = editor; - - resetEditorValue(); - updateEditorLayout(editorRef.current); - } - - function handleEditorChange(): void { - updateEditorLayout(editorRef.current!); - } - - async function handleAddButtonClick(): Promise { - const response = await TelegramBotDatabaseRecordApi.create(telegramBotId, {record: JSON.parse(editorRef.current!.getValue())}) - - if (response.ok) { - resetEditorValue(); - - onAdd(); - } - - new Toast(response.json.message, response.json.level).show(); - } - - function handleCancelButtonClick(): void { - resetEditorValue(); - - onCancel(); - } - - return ( -
-
- -
-
- - -
-
- ); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/RecordListGroupItem.tsx b/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/RecordListGroupItem.tsx deleted file mode 100644 index d4eb5172..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/database/src/components/RecordListGroupItem.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import Toast from 'global_modules/toast'; -import { askConfirmModal } from 'global_modules/modals/ask_confirm_modal'; -import { updateEditorLayout, defaultEditorOptions } from 'global_modules/monaco_editor'; -import { TelegramBotDatabaseRecordApi } from 'telegram_bot_api/main'; -import { TelegramBotDatabaseRecord } from 'telegram_bot_api/types'; -import { RecordListGroup } from '../main'; -import monaco from 'monaco-editor'; -import Editor from '@monaco-editor/react'; -import React from 'react'; - -declare const telegramBotId: number; -declare const telegramBotDatabaseRecordIsNotJson: string; -declare const askConfirmModalDeleteTelegramBotDatabaseRecordTitle: string; -declare const askConfirmModalDeleteTelegramBotDatabaseRecordText: string; - -const buttonWithOnlyIconStyle: React.CSSProperties = { - fontSize: '20px', -} - -interface RecordListGroupItemProps { - recordInitial: TelegramBotDatabaseRecord; -} - -export default function RecordListGroupItem({recordInitial}: RecordListGroupItemProps): React.JSX.Element { - const [record, setRecord] = React.useState(recordInitial); - const [recordIsEditing, setRecordIsEditing] = React.useState(false); - - const editorRef = React.useRef(); - - function handleEditorDidMount(editor: monaco.editor.IStandaloneCodeEditor): void { - editorRef.current = editor; - - updateEditorLayout(editorRef.current); - } - - function handleEditorChange(): void { - if (!recordIsEditing) { - setRecordIsEditing(true); - } - - updateEditorLayout(editorRef.current!, !recordIsEditing); - } - - async function handleSaveEditedRecordButtonClick(): Promise { - try { - const response = await TelegramBotDatabaseRecordApi.update(telegramBotId, record._id, {record: JSON.parse(editorRef.current!.getValue())}); - - if (response.ok) { - setRecordIsEditing(false); - setRecord(response.json.record); - - updateEditorLayout(editorRef.current!, true); - } - - new Toast(response.json.message, response.json.level).show(); - } catch { - new Toast(telegramBotDatabaseRecordIsNotJson, 'danger').show(); - } - } - - function handleCancelEditRecordButtonClick(): void { - setRecordIsEditing(false); - - editorRef.current!.setValue(JSON.stringify(record, null, 4)); - - updateEditorLayout(editorRef.current!, true); - } - - function handleDeleteRecordButtonClick(): void { - askConfirmModal( - askConfirmModalDeleteTelegramBotDatabaseRecordTitle, - askConfirmModalDeleteTelegramBotDatabaseRecordText, - async (): Promise => { - const response = await TelegramBotDatabaseRecordApi.delete_(telegramBotId, record._id); - - if (response.ok) { - RecordListGroup.update(); - } - - new Toast(response.json.message, response.json.level).show(); - } - ); - } - - return ( -
-
-
- -
-
- {recordIsEditing && ( -
- - -
- )} - -
-
-
- ); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/database/src/main.tsx b/telegram_bot/frontend/static/telegram_bot_menu/database/src/main.tsx deleted file mode 100644 index 7190d242..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/database/src/main.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import Toast from 'global_modules/toast'; -import { TelegramBotDatabaseRecordsApi } from 'telegram_bot_api/main'; -import { TelegramBotDatabaseRecord } from 'telegram_bot_api/types'; -import RecordListGroupItem from './components/RecordListGroupItem'; -import AddRecordModalBody from './components/AddRecordModalBody'; -import { Collapse, Modal } from 'bootstrap'; -import { createRoot } from 'react-dom/client'; -import React from 'react'; - -declare const telegramBotId: number; - -const collapseButtonElement = document.querySelector('#telegramBotDatabaseRecordsСollapseButton')!; -const updateButtonElement = document.querySelector('#telegramBotDatabaseRecordsUpdateButton')!; -const addButtonElement = document.querySelector('#telegramBotDatabaseRecordsAddButton')!; - -export namespace RecordListGroup { - const element = document.querySelector('#telegramBotDatabaseRecords')!; - const collapse = Collapse.getOrCreateInstance(element, {toggle: true}); - - const root = createRoot(element); - - interface AppProps { - records: TelegramBotDatabaseRecord[]; - } - - function App({records}: AppProps): React.JSX.Element { - const [isVisible, setIsVisible] = React.useState(true); - - React.useEffect(() => { - element.addEventListener('shown.bs.collapse', () => setIsVisible(true)); - element.addEventListener('hidden.bs.collapse', () => setIsVisible(false)); - }, []); - - return <>{isVisible && records.map(record => )}; - } - - export async function update(): Promise { - const response = await TelegramBotDatabaseRecordsApi.get(telegramBotId); - - if (response.ok) { - root.render(); - } else { - new Toast(response.json.message, response.json.level).show(); - } - } - - update(); - - collapseButtonElement.addEventListener('click', (): void => { - collapse.toggle(); - - updateButtonElement.classList.toggle('disabled'); - addButtonElement.classList.toggle('disabled'); - }); -} - -export namespace AddRecordModal { - const root = createRoot(document.querySelector('#addRecordModalBody')!); - - const modalElement = document.querySelector('#addRecordModal')!; - const modal = Modal.getOrCreateInstance(modalElement); - - export function App(): React.JSX.Element { - const [isVisible, setIsVisible] = React.useState(false); - - React.useEffect(() => { - modalElement.addEventListener('shown.bs.modal', () => setIsVisible(true)); - modalElement.addEventListener('hidden.bs.modal', () => setIsVisible(false)); - addButtonElement.addEventListener('click', () => modal.show()); - }, []); - - async function handleOnAdd(): Promise { - modal.hide() - - await RecordListGroup.update(); - } - - return isVisible ? modal.hide()} /> : <>; - } - - root.render(); -} - -updateButtonElement.addEventListener('click', async (): Promise => await RecordListGroup.update()); \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/default/src/main.css b/telegram_bot/frontend/static/telegram_bot_menu/default/src/main.css deleted file mode 100644 index 28b9292e..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/default/src/main.css +++ /dev/null @@ -1,9 +0,0 @@ -#telegramBotMenuNavbar .nav-link { - transition: color .15s ease-in-out, background-color .15s ease-in-out; -} - -#telegramBotMenuNavbar .nav-link.active, -#telegramBotMenuNavbar .nav-link:hover { - color: var(--bs-light)!important; - background-color: var(--bs-dark); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/index/src/components/TelegramBotCardFooter.tsx b/telegram_bot/frontend/static/telegram_bot_menu/index/src/components/TelegramBotCardFooter.tsx deleted file mode 100644 index c6318807..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/index/src/components/TelegramBotCardFooter.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import Toast from 'global_modules/toast'; -import { askConfirmModal } from 'global_modules/modals/ask_confirm_modal'; -import { TelegramBotApi } from 'telegram_bot_api/main'; -import { TelegramBotContext } from 'telegram_bot_frontend/components/TelegramBotCard'; -import React from 'react'; - -declare const personalCabinetUrl: string; -declare const askConfirmModalDeleteTelegramBotTitle: string; -declare const askConfirmModalDeleteTelegramBotText: string; -declare const telegramBotCardFooterStartButtonText: string; -declare const telegramBotCardFooterStopButtonText: string; -declare const telegramBotCardFooterDeleteButtonText: string; - -export default function TelegramBotCardFooter(): React.JSX.Element { - const telegramBotContext = React.useContext(TelegramBotContext)!; - const telegramBot = telegramBotContext.telegramBot; - - function handleDeleteButtonClick(): void { - askConfirmModal( - askConfirmModalDeleteTelegramBotTitle, - askConfirmModalDeleteTelegramBotText, - async (): Promise => { - const response = await TelegramBotApi.delete_(telegramBot.id); - - if (response.ok) { - setTimeout((): string => window.location.href = personalCabinetUrl, 2000); - } - - new Toast(response.json.message, response.json.level).show(); - }, - ); - } - - return ( -
- {!telegramBot.is_running && telegramBot.is_stopped ? ( - - ) : ( - - )} - -
- ); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/index/src/main.tsx b/telegram_bot/frontend/static/telegram_bot_menu/index/src/main.tsx deleted file mode 100644 index f40abb0e..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/index/src/main.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Toast from 'global_modules/toast'; -import { TelegramBotApi } from 'telegram_bot_api/main'; -import TelegramBotCard from 'telegram_bot_frontend/components/TelegramBotCard'; -import TelegramBotCardFooter from './components/TelegramBotCardFooter'; -import { createRoot } from 'react-dom/client'; -import React from 'react'; - -declare const telegramBotId: number; - -const root = createRoot(document.querySelector('#telegramBotCard')!); - -TelegramBotApi.get(telegramBotId).then(response => { - if (response.ok) { - root.render( - - - - ); - } else { - new Toast(response.json.message, response.json.level).show(); - } -}); \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/users/src/components/UserListGroupItem.tsx b/telegram_bot/frontend/static/telegram_bot_menu/users/src/components/UserListGroupItem.tsx deleted file mode 100644 index 16ec3c09..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/users/src/components/UserListGroupItem.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import Toast from 'global_modules/toast'; -import { askConfirmModal } from 'global_modules/modals/ask_confirm_modal'; -import { TelegramBotUserApi, TelegramBotAllowedUserApi } from 'telegram_bot_api/main'; -import { TelegramBotUser } from 'telegram_bot_api/types'; -import { UserListGroup } from '../main'; -import React from 'react'; - -declare const telegramBotId: number; -declare const telegramBotIsPrivate: boolean; -declare const askConfirmModalDeleteTelegramBotUserTitle: string; -declare const askConfirmModalDeleteTelegramBotUserText: string; - -const buttonWithOnlyIconStyle: React.CSSProperties = { - fontSize: '20px', -} - -interface UserListGroupItemProps { - userInitial: TelegramBotUser; -} - -export default function UserListGroupItem({userInitial}: UserListGroupItemProps): React.JSX.Element { - const [user, setUser] = React.useState(userInitial); - - async function handleSetOrUnsetAllowedButtonClick(): Promise { - const response = await TelegramBotAllowedUserApi[(user.is_allowed) ? 'unset' : 'set'](telegramBotId, user.id); - - if (response.ok) { - setUser({...user, is_allowed: !user.is_allowed}); - } - - new Toast(response.json.message, response.json.level).show(); - } - - function handleDeleteButtonClick(): void { - askConfirmModal( - askConfirmModalDeleteTelegramBotUserTitle, - askConfirmModalDeleteTelegramBotUserText, - async (): Promise => { - const response = await TelegramBotUserApi.delete_(telegramBotId, user.id); - - if (response.ok) { - UserListGroup.update(); - } - - new Toast(response.json.message, response.json.level).show(); - }, - ); - } - - return ( -
-
-

[{user.activated_date}]: {user.user_id} - {user.full_name}

-
- {telegramBotIsPrivate && ( - - )} - -
-
-
- ); -} \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/users/src/main.tsx b/telegram_bot/frontend/static/telegram_bot_menu/users/src/main.tsx deleted file mode 100644 index 686aa6f7..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/users/src/main.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Toast from 'global_modules/toast'; -import { TelegramBotUsersApi } from 'telegram_bot_api/main'; -import UserListGroupItem from './components/UserListGroupItem'; -import { createRoot } from 'react-dom/client'; -import React from 'react'; - -declare const telegramBotId: number; -declare const telegramBotNotActivatedYetText: string; - -export namespace UserListGroup { - const root = createRoot(document.querySelector('#telegramBotUsers')!); - - const collapseButtonElement = document.querySelector('#telegramBotUsersСollapseButton')!; - const updateButtonElement = document.querySelector('#telegramBotUsersUpdateButton')!; - - export async function update(): Promise { - const response = await TelegramBotUsersApi.get(telegramBotId); - - if (response.ok) { - root.render(response.json.length > 0 ? ( - response.json.map(user => ) - ) : ( -
{telegramBotNotActivatedYetText}
- )); - } else { - new Toast(response.json.message, response.json.level).show(); - } - } - - collapseButtonElement.addEventListener('click', (): boolean => updateButtonElement.classList.toggle('disabled')); - updateButtonElement.addEventListener('click', async (): Promise => await update()); -} - -UserListGroup.update(); \ No newline at end of file diff --git a/telegram_bot/frontend/static/telegram_bot_menu/variables/src/main.ts b/telegram_bot/frontend/static/telegram_bot_menu/variables/src/main.ts deleted file mode 100644 index d346d21e..00000000 --- a/telegram_bot/frontend/static/telegram_bot_menu/variables/src/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Toast from 'global_modules/toast'; -import ClipboardJS from 'clipboard'; - -declare const successMessageTextForClipboard: string; -declare const errorMessageTextForClipboard: string; - -const clipboard = new ClipboardJS('.btn-clipboard'); -clipboard.on('success', (): void => new Toast(successMessageTextForClipboard, 'success').show()); -clipboard.on('error', (): void => new Toast(errorMessageTextForClipboard, 'danger').show()); \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot/frontend/components/telegram_bot_card/scripts_data.html b/telegram_bot/frontend/templates/telegram_bot/frontend/components/telegram_bot_card/scripts_data.html deleted file mode 100644 index 9823d2c5..00000000 --- a/telegram_bot/frontend/templates/telegram_bot/frontend/components/telegram_bot_card/scripts_data.html +++ /dev/null @@ -1,10 +0,0 @@ -{% load i18n %} - -const telegramBotCardHeaderIsRunningText = "{% trans 'Telegram бот включен' %}"; -const telegramBotCardHeaderIsNotRunningText = "{% trans 'Telegram бот выключен' %}"; - -const telegramBotCardBodyTableLineApiTokenText = "{% trans 'API-токен' %}"; -const telegramBotCardBodyTableLineIsPrivateText = "{% trans 'Приватный' %}"; -const telegramBotCardBodyTableLineDateAddedText = "{% trans 'Добавлен' %}"; - -const telegramBotCardBodyTableLineApiTokenInputPlaceholderText = "{% trans 'Введите API-токен Telegram бота' %}"; \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/base.html b/telegram_bot/frontend/templates/telegram_bot_menu/base.html deleted file mode 100644 index 1a2cbb34..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/base.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TELEGRAM_BOT_MENU:DEFAULT' %} -{% endblock styles %} - -{% block main_class %}{% endblock main_class %} - -{% block main %} -
- - {% block content %}{% endblock content %} -
-{% endblock main %} - -{% block footer %} -{% with footer_extra_class="mt-auto" %} - {{ block.super }} -{% endwith %} -{% endblock footer %} - -{% block scripts_data %} -{{ block.super }} -const telegramBotId = {{ telegram_bot.id }}; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'TELEGRAM_BOT_MENU:DEFAULT' %} -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/database/main.html b/telegram_bot/frontend/templates/telegram_bot_menu/database/main.html deleted file mode 100644 index 62b9a954..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/database/main.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'telegram_bot_menu/base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'База данных' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TELEGRAM_BOT_MENU:DATABASE' %} -{% endblock styles %} - -{% block modals %} -{{ block.super }} -{% include 'telegram_bot_menu/database/modals/add_record_modal.html' %} -{% endblock modals %} - -{% block content %} -
-
- {% with id='telegramBotDatabaseRecords' %} - {% trans 'Добавить запись' as add_button_text %} - {% include 'telegram_bot_menu/object_tools.html' with id=id show_add_button=True add_button_text=add_button_text %} -
-
-
- {% endwith %} -
-
-{% endblock content %} - -{% block scripts_data %} -{{ block.super }} -const telegramBotDatabaseNotHaveRecordsText = "{% trans 'В базе данных вашего Telegram бота ещё нет никаких записей' %}"; - -const telegramBotDatabaseRecordIsNotJson = "{% trans 'Запись базы данных должна быть в формате JSON!' %}"; - -const askConfirmModalDeleteTelegramBotDatabaseRecordTitle = "{% trans 'Удаление записи из базы данных' %}"; -const askConfirmModalDeleteTelegramBotDatabaseRecordText = "{% trans 'Вы точно хотите удалить запись из базы данных Telegram бота?' %}"; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'TELEGRAM_BOT_MENU:DATABASE' %} -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/database/modals/add_record_modal.html b/telegram_bot/frontend/templates/telegram_bot_menu/database/modals/add_record_modal.html deleted file mode 100644 index 34d75dfc..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/database/modals/add_record_modal.html +++ /dev/null @@ -1,15 +0,0 @@ -{% load i18n %} - -{% with modal_id='addRecordModal' %} - -{% endwith %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/index.html b/telegram_bot/frontend/templates/telegram_bot_menu/index.html deleted file mode 100644 index 086b4f43..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/index.html +++ /dev/null @@ -1,49 +0,0 @@ -{% extends 'telegram_bot_menu/base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Telegram бот' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TELEGRAM_BOT_MENU:INDEX' %} -{% endblock styles %} - -{% block content %} -
-
-
-
- {% trans 'Количество пользователей' as info_area_text %} - {% include 'widgets/info_area.html' with class='col-6' value=telegram_bot.users.count text=info_area_text %} - - {% trans 'Количество команд' as info_area_text %} - {% include 'widgets/info_area.html' with class='col-6' value=telegram_bot.commands.count text=info_area_text %} - - {% comment %} {% trans 'Активность за 24 ч.' as info_area_text %} - {% include 'widgets/info_area.html' with class='col-6' value='0' text=info_area_text %} {% endcomment %} -
-
-
-{% endblock content %} - -{% block scripts_data %} -{{ block.super }} -const personalCabinetUrl = "{% url 'personal_cabinet:index' %}"; - -{% include 'telegram_bot/frontend/components/telegram_bot_card/scripts_data.html' %} - -const startTelegramBotMessage = "{% trans 'Вы успешно включили Telegram бота.' %}"; -const stopTelegramBotMessage = "{% trans 'Вы успешно выключили Telegram бота.' %}"; - -const askConfirmModalDeleteTelegramBotTitle = "{% trans 'Удаление Telegram бота' %}"; -const askConfirmModalDeleteTelegramBotText = "{% trans 'Вы точно хотите удалить Telegram бота?' %}"; - -const telegramBotCardFooterStartButtonText = "{% trans 'Включить Telegram бота' %}"; -const telegramBotCardFooterStopButtonText = "{% trans 'Выключить Telegram бота' %}"; - -const telegramBotCardFooterDeleteButtonText = "{% trans 'Удалить Telegram бота' %}"; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'TELEGRAM_BOT_MENU:INDEX' %} -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/object_tools.html b/telegram_bot/frontend/templates/telegram_bot_menu/object_tools.html deleted file mode 100644 index ba260f69..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/object_tools.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- - -
- {% if show_add_button %} - {% include 'widgets/add_button.html' with size='sm' id=id|add:'AddButton' text=add_button_text %} - {% endif %} -
\ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/command_offcanvas.html b/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/command_offcanvas.html deleted file mode 100644 index 55fef6a5..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/command_offcanvas.html +++ /dev/null @@ -1,96 +0,0 @@ -{% load i18n %} - -
-
-
- -
-
-
-
{% trans "Название команды" %}
- -
-
-
{% trans "Команда" context "Command" %}
-
- - - - -
-
-
-
{% trans "Изображение" %}
-
- - -
-
-
-
{% trans "Текст сообщения" %}
- -
-
-
{% trans "Клавиатура" %}
-
-
- - - - - {% comment %} - {% endcomment %} -
-
-
-
- -
-
-
-
-
{% trans "API-запрос" %}
-
- -
- {% with 'telegramBotCommandOffcanvasApiRequestMethods' as radio_name %} - - - - - - - - - - - {% endwith %} -
-
- - -
- - -
-
-
-
{% trans "Запись в базу данных" %}
-
-
-
-
{% trans "Доступные дополнения" %}
-
- - - - - -
-
-
-
- - -
-
\ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/diagram.html b/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/diagram.html deleted file mode 100644 index 87d55297..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/diagram.html +++ /dev/null @@ -1,24 +0,0 @@ -{% load i18n %} - -
-
- -
- -
- {% trans "Добавить команду" as add_button_text %} - {% include 'widgets/add_button.html' with size="sm" id="telegramBotCommandOffcanvasButton" text=add_button_text %} -
-
- - - - - - - -
\ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/main.html b/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/main.html deleted file mode 100644 index 3325a647..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_constructor/main.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'base_telegram_bot_menu.html' %} -{% load static %} -{% load i18n %} - -{% block title %}{% trans "Конструктор" %}{% endblock title %} - -{% block animation_styles %}{% endblock animation_styles %} - -{% block styles %} -{{ block.super }} - - -{% endblock styles %} - -{% block content %} -{% include 'telegram_bot_constructor/command_offcanvas.html' %} -{% include 'telegram_bot_constructor/diagram.html' %} -{% endblock content %} - -{% block animation_scripts %}{% endblock animation_scripts %} - -{% block scripts %} -{{ block.super }} - - - - -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_plugins.html b/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_plugins.html deleted file mode 100644 index 2d41de58..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/telegram_bot_plugins.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends 'base_telegram_bot_menu.html' %} -{% load static %} -{% load i18n %} - -{% block title %}{% trans "Плагины" %}{% endblock title %} - -{% block content %} -
-
{% trans "Список плагинов" %}
-
- {% trans "Добавить плагин" as add_button_text %} - {% include 'object_tools.html' with id="telegramBotPlugins" show_add_button=True add_button_text=add_button_text %} -
-
-
-
-
-
-
{% trans "Логи плагинов" %}
-
- {% include 'object_tools.html' with id="telegramBotPluginsLogs" show_add_button=False %} -
-
-
-
-
-{% endblock content %} - -{% block scripts %} -{{ block.super }} - - - -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/users.html b/telegram_bot/frontend/templates/telegram_bot_menu/users.html deleted file mode 100644 index 495cafd2..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/users.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends 'telegram_bot_menu/base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Список пользователей' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TELEGRAM_BOT_MENU:USERS' %} -{% endblock styles %} - -{% block content %} -
-
- {% with id='telegramBotUsers' %} - {% include 'telegram_bot_menu/object_tools.html' with id=id show_add_button=False %} -
-
-
- {% endwith %} -
-
-{% endblock content %} - -{% block scripts_data %} -{{ block.super }} -const telegramBotIsPrivate = {{ telegram_bot.is_private|lower }}; - -const telegramBotNotActivatedYetText = "{% trans 'Вашего Telegram бота ещё никто не активировал' %}"; - -const askConfirmModalDeleteTelegramBotUserTitle = "{% trans 'Удаление пользователя' %}"; -const askConfirmModalDeleteTelegramBotUserText = "{% trans 'Вы точно хотите удалить пользователя Telegram бота?' %}"; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'TELEGRAM_BOT_MENU:USERS' %} -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/variables/main.html b/telegram_bot/frontend/templates/telegram_bot_menu/variables/main.html deleted file mode 100644 index 1a71f6bb..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/variables/main.html +++ /dev/null @@ -1,51 +0,0 @@ -{% extends 'telegram_bot_menu/base.html' %} -{% load i18n %} -{% load render_bundle from webpack_loader %} - -{% block title %}{% trans 'Список переменных' %}{% endblock title %} - -{% block styles %} -{% render_bundle 'main' 'css' 'TELEGRAM_BOT_MENU:VARIABLES' %} -{% endblock styles %} - -{% block content %} -
- - - {% trans 'ID пользователя' as user_id_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_id_header data='{{ user_id }}' %} - - {% trans 'Имя пользователя' as user_first_name_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_first_name_header data='{{ user_first_name }}' %} - - {% trans 'Фамилия пользователя' as user_last_name_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_last_name_header data='{{ user_last_name }}' %} - - {% trans '@username пользователя' as user_username_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_username_header data='{{ user_username }}' %} - - {% trans 'ID сообщения пользователя' as user_message_id_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_message_id_header data='{{ user_message_id }}' %} - - {% trans 'Текст сообщения пользователя' as user_message_text_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=user_message_text_header data='{{ user_message_text }}' %} - - {% trans 'Данные из базы данных' as database_records_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=database_records_header data='{{ database_records }}' %} - - {% trans 'Ответ с API-запроса' as api_response_header %} - {% include 'telegram_bot_menu/variables/table_cell.html' with header=api_response_header data='{{ api_response }}' %} - -
-
-{% endblock content %} - -{% block scripts_data %} -{{ block.super }} -const successMessageTextForClipboard = "{% trans 'Вы успешно скопировали переменную в буфер обмена.' %}"; -const errorMessageTextForClipboard = "{% trans 'При попытки скопировать переменную в буфер обмена, непредвиденная ошибка!' %}"; -{% endblock scripts_data %} - -{% block scripts %} -{% render_bundle 'main' 'js' 'TELEGRAM_BOT_MENU:VARIABLES' %} -{% endblock scripts %} \ No newline at end of file diff --git a/telegram_bot/frontend/templates/telegram_bot_menu/variables/table_cell.html b/telegram_bot/frontend/templates/telegram_bot_menu/variables/table_cell.html deleted file mode 100644 index 1af50583..00000000 --- a/telegram_bot/frontend/templates/telegram_bot_menu/variables/table_cell.html +++ /dev/null @@ -1,9 +0,0 @@ - - {{ header }}: - -
- {{ data }} - -
- - \ No newline at end of file diff --git a/telegram_bot/frontend/tests.py b/telegram_bot/frontend/tests.py deleted file mode 100644 index b6f84f29..00000000 --- a/telegram_bot/frontend/tests.py +++ /dev/null @@ -1,106 +0,0 @@ -from django.test import TestCase -from django.http import HttpResponse -from django import urls - -from user.models import User -from telegram_bot.models import TelegramBot - - -class ViewsTests(TestCase): - def setUp(self) -> None: - self.user: User = User.objects.create(telegram_id=123456789, first_name='exg1o') - self.telegram_bot: TelegramBot = TelegramBot.objects.create( - owner=self.user, - api_token='123456789:qwertyuiop', - is_private=True, - ) - - def test_telegram_bot_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot.html') - - def test_telegram_bot_variables_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot_variables', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot_variables.html') - - def test_telegram_bot_users_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot_users', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot_users.html') - - def test_telegram_bot_database_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot_database', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot_database.html') - - def test_telegram_bot_plugins_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot_plugins', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot_plugins.html') - - def test_telegram_bot_constructor_view(self) -> None: - url: str = urls.reverse( - 'telegram_bot_menu:telegram_bot_constructor', - kwargs={'telegram_bot_id': self.telegram_bot.id}, - ) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'telegram_bot_constructor/main.html') diff --git a/telegram_bot/frontend/urls.py b/telegram_bot/frontend/urls.py deleted file mode 100644 index a8bfa68a..00000000 --- a/telegram_bot/frontend/urls.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.urls import path - -from .views import CustomTemplateView - - -app_name = 'frontend' -urlpatterns = [ - path('', CustomTemplateView.as_view(template_name='telegram_bot_menu/index.html'), name='index'), - path('variables/', CustomTemplateView.as_view(template_name='telegram_bot_menu/variables/main.html'), name='variables'), - path('users/', CustomTemplateView.as_view(template_name='telegram_bot_menu/users.html'), name='users'), - path('database/', CustomTemplateView.as_view(template_name='telegram_bot_menu/database/main.html'), name='database'), - path('plugins/', CustomTemplateView.as_view(template_name='telegram_bot_menu/plugins.html'), name='plugins'), - path('constructor/', CustomTemplateView.as_view(template_name='telegram_bot_menu/constructor.html'), name='constructor'), -] diff --git a/telegram_bot/frontend/views.py b/telegram_bot/frontend/views.py deleted file mode 100644 index 8b91bcf0..00000000 --- a/telegram_bot/frontend/views.py +++ /dev/null @@ -1,13 +0,0 @@ -from django.http import HttpRequest, HttpResponse -from django.views.generic.base import TemplateView -from django.utils.decorators import method_decorator -from django.contrib.auth.decorators import login_required - -from telegram_bot.decorators import check_telegram_bot_id - - -class CustomTemplateView(TemplateView): - @method_decorator(login_required) - @check_telegram_bot_id - def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: - return super().get(request, *args, **kwargs) diff --git a/telegram_bot/api/functions.py b/telegram_bot/functions.py similarity index 94% rename from telegram_bot/api/functions.py rename to telegram_bot/functions.py index 0dce1f47..a7319e29 100644 --- a/telegram_bot/api/functions.py +++ b/telegram_bot/functions.py @@ -16,4 +16,4 @@ def get_image_from_request(request: Request) -> InMemoryUploadedFile | str | Non if 'image' in request.FILES: return request.FILES['image'] elif 'image' in request.POST: - return request.POST['image'] + return request.POST['image'] \ No newline at end of file diff --git a/telegram_bot/models.py b/telegram_bot/models.py index 7c971528..e9a223df 100644 --- a/telegram_bot/models.py +++ b/telegram_bot/models.py @@ -341,4 +341,4 @@ class Meta: verbose_name_plural = _('Пользователи') def __str__(self) -> str: - return self.full_name if self.full_name else str(self.user_id) + return self.full_name if self.full_name else str(self.user_id) \ No newline at end of file diff --git a/home/__init__.py b/telegram_bot/serializers/__init__.py similarity index 100% rename from home/__init__.py rename to telegram_bot/serializers/__init__.py diff --git a/telegram_bot/api/serializers/models.py b/telegram_bot/serializers/models.py similarity index 100% rename from telegram_bot/api/serializers/models.py rename to telegram_bot/serializers/models.py diff --git a/telegram_bot/api/serializers/regulars.py b/telegram_bot/serializers/regulars.py similarity index 97% rename from telegram_bot/api/serializers/regulars.py rename to telegram_bot/serializers/regulars.py index b4ad8285..20cf735e 100644 --- a/telegram_bot/api/serializers/regulars.py +++ b/telegram_bot/serializers/regulars.py @@ -34,8 +34,10 @@ class UpdateTelegramBotSerializer(CreateTelegramBotSerializer): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) - self.fields['api_token'].allow_null = True - self.fields['is_private'].allow_null = True + self.fields['api_token'].required = False + self.fields['api_token'].default = None + self.fields['is_private'].required = False + self.fields['is_private'].default = None def validate_api_token(self, api_token: str | None) -> str | None: if api_token is not None: diff --git a/telegram_bot/signals.py b/telegram_bot/signals.py index 58f8e156..8ae3e7f9 100644 --- a/telegram_bot/signals.py +++ b/telegram_bot/signals.py @@ -18,4 +18,4 @@ def post_delete_telegram_bot_signal_handler(instance: TelegramBot, **kwargs: Any @receiver(post_delete, sender=TelegramBotCommand) def post_delete_telegram_bot_command_signal_handler(instance: TelegramBotCommand, **kwargs: Any) -> None: - instance.image.delete(save=False) + instance.image.delete(save=False) \ No newline at end of file diff --git a/telegram_bot/tasks.py b/telegram_bot/tasks.py index 8f2479a1..d21cdfd3 100644 --- a/telegram_bot/tasks.py +++ b/telegram_bot/tasks.py @@ -51,4 +51,4 @@ def start_all_telegram_bots() -> None: target=start_telegram_bot_, args=(UserTelegramBot(django_telegram_bot),), daemon=True, - ).start() + ).start() \ No newline at end of file diff --git a/telegram_bot/tests.py b/telegram_bot/tests.py index 028f319d..f0c40c59 100644 --- a/telegram_bot/tests.py +++ b/telegram_bot/tests.py @@ -125,4 +125,4 @@ class TelegramBotUserModelTests(BaseTestCase): def test_fields(self) -> None: self.assertEqual(self.telegram_bot_user.user_id, 123456789) self.assertEqual(self.telegram_bot_user.full_name, 'Test user') - self.assertEqual(self.telegram_bot_user.is_allowed, False) + self.assertEqual(self.telegram_bot_user.is_allowed, False) \ No newline at end of file diff --git a/telegram_bot/urls.py b/telegram_bot/urls.py index 2ea8f067..2dcddc35 100644 --- a/telegram_bot/urls.py +++ b/telegram_bot/urls.py @@ -1,8 +1,37 @@ -from django.urls import path, include +from django.urls import path + +from .views import ( + TelegramBotsView, + TelegramBotView, + start_or_stop_telegram_bot, + update_telegram_bot_diagram_current_scale, + TelegramBotCommandsView, + TelegramBotCommandView, + update_telegram_bot_command_position, + TelegramBotCommandKeyboardButtonTelegramBotCommandView, + TelegramBotUsersView, + TelegramBotUserView, + TelegramBotAllowedUserView, + TelegramBotDatabeseRecordsView, + TelegramBotDatabeseRecordView, +) -app_name = 'telegram_bot' urlpatterns = [ - path('telegram-bot-menu//', include('telegram_bot.frontend.urls')), - path('api/telegram-bots/', include('telegram_bot.api.urls')), -] + path('', TelegramBotsView.as_view(), name='telegram_bots'), # POST, GET + path('/', TelegramBotView.as_view(), name='telegram_bot'), # PATCH, DELETE, GET + path('/start-or-stop/', start_or_stop_telegram_bot, name='start_or_stop_telegram_bot'), # POST + path('/update-diagram-current-scale/', update_telegram_bot_diagram_current_scale, name='update_telegram_bot_diagram_current_scale'), # PATCH + + path('/commands/', TelegramBotCommandsView.as_view(), name='telegram_bot_commands'), # POST, GET + path('/commands//', TelegramBotCommandView.as_view(), name='telegram_bot_command'), # PATCH, DELETE, GET + path('/commands//update-position/', update_telegram_bot_command_position, name='update_telegram_bot_command_position'), # PATCH + path('/commands//keyboard-buttons//telegram-bot-command/', TelegramBotCommandKeyboardButtonTelegramBotCommandView.as_view(), name='telegram_bot_command_keyboard_button_telegram_bot_command'), # POST, DELETE + + path('/users/', TelegramBotUsersView.as_view(), name='telegram_bot_users'), # GET + path('/users//', TelegramBotUserView.as_view(), name='telegram_bot_user'), # DELETE + path('/users//allowed-user/', TelegramBotAllowedUserView.as_view(), name='telegram_bot_allowed_user'), # POST, DELETE + + path('/database/records/', TelegramBotDatabeseRecordsView.as_view(), name='telegram_bot_databese_records'), # POST, GET + path('/database/records//', TelegramBotDatabeseRecordView.as_view(), name='telegram_bot_databese_record'), # PATCH, DELETE +] \ No newline at end of file diff --git a/telegram_bot/api/views.py b/telegram_bot/views.py similarity index 97% rename from telegram_bot/api/views.py rename to telegram_bot/views.py index fdb8b751..2f4cef1d 100644 --- a/telegram_bot/api/views.py +++ b/telegram_bot/views.py @@ -10,15 +10,15 @@ from constructor_telegram_bots.utils.drf import CustomResponse -from ..models import ( +from .models import ( TelegramBot, TelegramBotCommand, TelegramBotCommandKeyboardButton, TelegramBotUser, ) -from ..decorators import check_telegram_bot_id from .decorators import ( + check_telegram_bot_id, check_telegram_bot_command_id, check_telegram_bot_command_keyboard_button_id, check_telegram_bot_user_id, @@ -42,12 +42,11 @@ UpdateTelegramBotDatabeseRecordSerializer, ) -from ..services import database_telegram_bot -from ..tasks import start_telegram_bot as celery_start_telegram_bot +from .services import database_telegram_bot +from .tasks import start_telegram_bot as celery_start_telegram_bot from typing import Any import json -import sys class TelegramBotsView(APIView): @@ -72,6 +71,10 @@ class TelegramBotView(APIView): authentication_classes = [TokenAuthentication] permission_classes = [IsAuthenticated] + @check_telegram_bot_id + def get(self, request: Request, telegram_bot: TelegramBot) -> Response: + return Response(TelegramBotModelSerializer(telegram_bot).data) + @check_telegram_bot_id def patch(self, request: Request, telegram_bot: TelegramBot) -> CustomResponse: serializer = UpdateTelegramBotSerializer(data=request.data, context={'user': request.user}) @@ -103,10 +106,6 @@ def delete(self, request: Request, telegram_bot: TelegramBot) -> CustomResponse: return CustomResponse(_('Вы успешно удалили Telegram бота.')) - @check_telegram_bot_id - def get(self, request: Request, telegram_bot: TelegramBot) -> Response: - return Response(TelegramBotModelSerializer(telegram_bot).data) - @api_view(['POST']) @authentication_classes([TokenAuthentication]) @permission_classes([IsAuthenticated]) @@ -114,10 +113,7 @@ def get(self, request: Request, telegram_bot: TelegramBot) -> Response: def start_or_stop_telegram_bot(request: Request, telegram_bot: TelegramBot) -> CustomResponse: if not settings.TEST: if not telegram_bot.is_running and telegram_bot.is_stopped: - if sys.platform == 'win32': - celery_start_telegram_bot(telegram_bot_id=telegram_bot.id) - else: - celery_start_telegram_bot.delay(telegram_bot_id=telegram_bot.id) + celery_start_telegram_bot.delay(telegram_bot_id=telegram_bot.id) elif telegram_bot.is_running and not telegram_bot.is_stopped: telegram_bot.stop() diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 7cf2b2ec..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "module": "CommonJS", - "target": "ES2015", - "moduleResolution": "node", - "esModuleInterop": true, - "allowJs": true, - "jsx": "react", - "strict": true, - "paths": { - "global_modules/*": ["./constructor_telegram_bots/static/global_modules/*"], - "telegram_bot_api/*": ["./telegram_bot/api/static/telegram_bot/api/*"], - "telegram_bot_frontend/*": ["./telegram_bot/frontend/static/telegram_bot/frontend/*"] - } - }, - "include": ["./**/*.ts", "./**/*.tsx"], - "exclude": ["./node_modules"] -} \ No newline at end of file diff --git a/updates/admin.py b/updates/admin.py index 1e6e15b8..697174fb 100644 --- a/updates/admin.py +++ b/updates/admin.py @@ -10,8 +10,7 @@ @admin.register(Update) class UpdateAdmin(TranslationAdmin): date_hierarchy = 'added_date' + list_display = ['version', 'added_date'] - list_display = ('version', 'added_date') - - fields = ('image', 'version', 'description') - formfield_overrides = {models.TextField: {'widget': TinyMCE}} + fields = ['image', 'version', 'description'] + formfield_overrides = {models.TextField: {'widget': TinyMCE}} \ No newline at end of file diff --git a/updates/apps.py b/updates/apps.py index 2232d3f1..7e649c4e 100644 --- a/updates/apps.py +++ b/updates/apps.py @@ -6,4 +6,4 @@ class UpdatesConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'updates' - verbose_name = _('Обновления') + verbose_name = _('Обновления') \ No newline at end of file diff --git a/updates/decorators.py b/updates/decorators.py deleted file mode 100644 index 90c98a03..00000000 --- a/updates/decorators.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.http import HttpRequest -from django.utils.translation import gettext as _ - -from constructor_telegram_bots.utils.shortcuts import render_success_or_error - -from .models import Update - -from functools import wraps - - -def check_update_id(func): - @wraps(func) - def wrapper(*args, **kwargs): - request: HttpRequest = args[0] - update_id: int = kwargs.pop('update_id', 0) - - try: - kwargs['update'] = Update.objects.get(id=update_id) - except Update.DoesNotExist: - return render_success_or_error( - request, - 'Обновление не найдено!', - _('Автоматический переход на главную страницу через 3 секунды.'), - status=404, - ) - - return func(*args, **kwargs) - return wrapper diff --git a/updates/models.py b/updates/models.py index b266105e..2239c3df 100644 --- a/updates/models.py +++ b/updates/models.py @@ -16,4 +16,4 @@ class Meta: verbose_name_plural = _('Обновления') def __str__(self) -> str: - return self.version + return self.version \ No newline at end of file diff --git a/updates/serializers.py b/updates/serializers.py new file mode 100644 index 00000000..7057648a --- /dev/null +++ b/updates/serializers.py @@ -0,0 +1,23 @@ +from django.template import defaultfilters as filters + +from rest_framework import serializers + +from .models import Update + +from typing import Any + + +class UpdateModelSerializer(serializers.ModelSerializer): + class Meta: + model = Update + fields = ['id', 'image', 'version', 'description', 'added_date'] + + def to_representation(self, instance: Update) -> dict[str, Any]: + representation: dict[str, Any] = super().to_representation(instance) + representation['added_date'] = f'{filters.date(instance.added_date)} {filters.time(instance.added_date)}' + + return representation + +class GetUpdatesSerializer(serializers.Serializer): + offset = serializers.IntegerField(default=None) + limit = serializers.IntegerField(default=None) \ No newline at end of file diff --git a/updates/templates/update.html b/updates/templates/update.html deleted file mode 100644 index 4a58e1b8..00000000 --- a/updates/templates/update.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}{{ update.title }}{% endblock title %} - -{% block main %} -
-
- {% if update.image %}{{ update.version }}{% endif %} -
{% autoescape off %}{{ update.description }}{% endautoescape %}
-
-
-{% endblock main %} \ No newline at end of file diff --git a/updates/templates/updates.html b/updates/templates/updates.html deleted file mode 100644 index 085d4b72..00000000 --- a/updates/templates/updates.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} - -{% block title %}{% trans 'Обновления' %}{% endblock title %} - -{% block main %} -
-
- {% for update in updates %} - -
-
- - {{ update.added_date }} -
-

{{ update.version }}

-
-
- {% endfor %} -
-
-{% endblock main %} \ No newline at end of file diff --git a/updates/tests.py b/updates/tests.py index 921f5bd2..047190db 100644 --- a/updates/tests.py +++ b/updates/tests.py @@ -33,4 +33,4 @@ def test_update_view(self) -> None: response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'update.html') + self.assertTemplateUsed(response, 'update.html') \ No newline at end of file diff --git a/updates/translation.py b/updates/translation.py index 313a3dad..0e33303e 100644 --- a/updates/translation.py +++ b/updates/translation.py @@ -5,4 +5,4 @@ @register(Update) class UpdateTranslationOptions(TranslationOptions): - fields = ('description',) + fields = ['description'] \ No newline at end of file diff --git a/updates/urls.py b/updates/urls.py index ea553632..bbd96e2e 100644 --- a/updates/urls.py +++ b/updates/urls.py @@ -1,9 +1,8 @@ from django.urls import path -from . import views +from .views import UpdatesAPIView urlpatterns = [ - path('', views.updates_view, name='updates'), - path('/', views.update_view, name='update'), -] + path('updates/', UpdatesAPIView.as_view(), name='updates'), +] \ No newline at end of file diff --git a/updates/views.py b/updates/views.py index b4a62f13..7d8942e8 100644 --- a/updates/views.py +++ b/updates/views.py @@ -1,13 +1,26 @@ -from django.http import HttpRequest, HttpResponse -from django.shortcuts import render +from rest_framework.views import APIView +from rest_framework.request import Request +from rest_framework.response import Response from .models import Update -from .decorators import check_update_id +from .serializers import UpdateModelSerializer, GetUpdatesSerializer -def updates_view(request: HttpRequest) -> HttpResponse: - return render(request, 'updates.html', {'updates': Update.objects.all()}) +class UpdatesAPIView(APIView): + authentication_classes = [] + permission_classes = [] -@check_update_id -def update_view(request: HttpRequest, **context) -> HttpResponse: - return render(request, 'update.html', context) + def post(self, request: Request) -> Response: + serializer = GetUpdatesSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + validated_data: dict = serializer.validated_data + offset: int | None = validated_data['offset'] + limit: int | None = validated_data['limit'] + + return Response( + UpdateModelSerializer( + Update.objects.all()[offset:limit], + many=True, + ).data + ) \ No newline at end of file diff --git a/user/admin.py b/user/admin.py index 5e22b09f..92fbd9a5 100644 --- a/user/admin.py +++ b/user/admin.py @@ -6,18 +6,17 @@ @admin.register(User) class UserAdmin(admin.ModelAdmin): - search_fields = ('telegram_id', 'first_name') + search_fields = ['telegram_id', 'first_name'] date_hierarchy = 'joined_date' - list_filter = ('is_staff', 'last_login', 'joined_date') + list_filter = ['is_staff', 'last_login', 'joined_date'] + list_display = ['id', 'telegram_id', 'first_name', 'telegram_bots_count', 'is_staff', 'last_login', 'joined_date'] - list_display = ('id', 'telegram_id', 'first_name', 'telegram_bots_count', 'is_staff', 'last_login', 'joined_date') - - fields = ('id', 'telegram_id', 'first_name', 'telegram_bots_count', 'is_staff', 'groups', 'last_login', 'joined_date') - readonly_fields = ('id', 'telegram_id', 'first_name', 'telegram_bots_count', 'last_login', 'joined_date') + fields = ['id', 'telegram_id', 'first_name', 'telegram_bots_count', 'is_staff', 'groups', 'last_login', 'joined_date'] + readonly_fields = ['id', 'telegram_id', 'first_name', 'telegram_bots_count', 'last_login', 'joined_date'] @admin.display(description=_('Количество Telegram ботов')) def telegram_bots_count(self, user: User) -> int: return user.telegram_bots.count() def has_add_permission(self, *args, **kwargs) -> bool: - return False + return False \ No newline at end of file diff --git a/user/apps.py b/user/apps.py index f3e9c360..0aaa67a1 100644 --- a/user/apps.py +++ b/user/apps.py @@ -9,4 +9,4 @@ class UserConfig(AppConfig): verbose_name = _('Пользователи') def ready(self) -> None: - from . import signals + from . import signals \ No newline at end of file diff --git a/user/models.py b/user/models.py index 47e31001..97271bb4 100644 --- a/user/models.py +++ b/user/models.py @@ -3,7 +3,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.conf import settings -from django import urls from constructor_telegram_bots.utils.other import generate_random_string @@ -45,10 +44,7 @@ def generate_login_url(self) -> str: if not self.confirm_code: self.generate_confirm_code() - return settings.SITE_DOMAIN + urls.reverse('user:login', kwargs={ - 'user_id': self.id, - 'confirm_code': self.confirm_code, - }) + return settings.SITE_DOMAIN + f'/login/{self.id}/{self.confirm_code}/' @property def login_url(self) -> str: @@ -69,4 +65,4 @@ def update_first_name(self) -> None: self.save() def __str__(self) -> str: - return self.first_name if self.first_name else str(self.telegram_id) + return self.first_name if self.first_name else str(self.telegram_id) \ No newline at end of file diff --git a/user/serializers.py b/user/serializers.py new file mode 100644 index 00000000..e5d133bd --- /dev/null +++ b/user/serializers.py @@ -0,0 +1,24 @@ +from django.utils.translation import gettext as _ +from django.template import defaultfilters as filters + +from rest_framework import serializers + +from .models import User + +from typing import Any + + +class UserModelSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = ['id', 'telegram_id', 'first_name', 'is_staff', 'joined_date'] + + def to_representation(self, instance: User) -> dict[str, Any]: + representation: dict[str, Any] = super().to_representation(instance) + representation['joined_date'] = f'{filters.date(instance.joined_date)} {filters.time(instance.joined_date)}' + + return representation + +class AuthTokenSerializer(serializers.Serializer): + user_id = serializers.IntegerField() + confirm_code = serializers.CharField() \ No newline at end of file diff --git a/user/signals.py b/user/signals.py index 66367ab9..43bc9b71 100644 --- a/user/signals.py +++ b/user/signals.py @@ -1,8 +1,6 @@ from django.db.models.signals import post_save, post_delete from django.dispatch import receiver -from rest_framework.authtoken.models import Token - from constructor_telegram_bots.environment import ( create_user as env_create_user, delete_user as env_delete_user, @@ -16,9 +14,8 @@ @receiver(post_save, sender=User) def post_save_user_signal_handler(instance: User, created: bool, **kwargs: Any) -> None: if created: - Token.objects.create(user=instance) env_create_user(user=instance) @receiver(post_delete, sender=User) def post_delete_user_signal_handler(instance: User, **kwargs: Any) -> None: - env_delete_user(user=instance) + env_delete_user(user=instance) \ No newline at end of file diff --git a/user/tasks.py b/user/tasks.py index 4e7d351f..4ca34e27 100644 --- a/user/tasks.py +++ b/user/tasks.py @@ -9,4 +9,4 @@ def update_users_first_name() -> None: for user in User.objects.all(): user.update_first_name() - time.sleep(0.5) + time.sleep(0.5) \ No newline at end of file diff --git a/user/tests.py b/user/tests.py index 3e6d7378..3373d96a 100644 --- a/user/tests.py +++ b/user/tests.py @@ -1,5 +1,4 @@ from django.test import TestCase -from django.http import HttpResponse from django import urls from django.conf import settings @@ -36,37 +35,4 @@ def test_login_url(self) -> None: self.user.refresh_from_db() self.assertIsNone(self.user.confirm_code) - self.assertIsNotNone(self.user.last_login) - -class ViewsTests(BaseTestCase): - def test_user_login_view(self) -> None: - login_urls: dict[str, int] = { - urls.reverse('user:login', kwargs={ - 'user_id': 0, - 'confirm_code': 1, - }): 404, - urls.reverse('user:login', kwargs={ - 'user_id': self.user.id, - 'confirm_code': 0, - }): 401, - } - - for login_url, response_status_code in login_urls.items(): - response: HttpResponse = self.client.get(login_url) - self.assertEqual(response.status_code, response_status_code) - self.assertTemplateUsed(response, 'base_success_or_error.html') - - response: HttpResponse = self.client.get(self.user.login_url) - self.assertEqual(response.status_code, 302) - - def test_user_logout_view(self) -> None: - url: str = urls.reverse('user:logout') - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 302) - - self.client.get(self.user.login_url) - - response: HttpResponse = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'base_success_or_error.html') + self.assertIsNotNone(self.user.last_login) \ No newline at end of file diff --git a/user/urls.py b/user/urls.py index 1d7b12f9..f4bb1325 100644 --- a/user/urls.py +++ b/user/urls.py @@ -1,10 +1,13 @@ -from django.urls import path +from django.urls import path, include -from . import views +from .views import UserLoginAPIView, UserLogoutAPIView, UsersAPIView, UserAPIView -app_name = 'user' urlpatterns = [ - path('login///', views.user_login_view, name='login'), - path('logout/', views.user_logout_view, name='logout'), -] + path('user/', include([ + path('', UserAPIView.as_view(), name='user'), + path('login/', UserLoginAPIView.as_view(), name='user-login'), + path('logout/', UserLogoutAPIView.as_view(), name='user-logout'), + ])), + path('users/', UsersAPIView.as_view(), name='users'), +] \ No newline at end of file diff --git a/user/views.py b/user/views.py index cbfa9ba0..f264ed1a 100644 --- a/user/views.py +++ b/user/views.py @@ -1,48 +1,77 @@ -from django.http import HttpRequest, HttpResponse from django.utils.translation import gettext as _ -from django import urls -from django.shortcuts import render, redirect -from django.contrib.auth import login, logout -from django.contrib.auth.decorators import login_required + +from rest_framework.views import APIView +from rest_framework.authentication import TokenAuthentication +from rest_framework.permissions import IsAuthenticated +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.authtoken.models import Token + +from constructor_telegram_bots.utils.drf import CustomResponse from .models import User +from .serializers import UserModelSerializer, AuthTokenSerializer + +from typing import Any + + +class UserLoginAPIView(APIView): + authentication_classes = [] + permission_classes = [] + + def post(self, request: Request) -> CustomResponse: + serializer = AuthTokenSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + validated_data: dict[str, Any] = serializer.validated_data + user_id: int = validated_data['user_id'] + confirm_code: str = validated_data['confirm_code'] + + try: + user: User = User.objects.get(id=user_id) + except User.DoesNotExist: + return CustomResponse(_('Не удалось найти пользователя!'), status=404) + + if user.confirm_code != confirm_code: + return CustomResponse(_('Неверный код подтверждения!'), status=401) + + user.confirm_code = None + user.save() + + auth_token, created = Token.objects.get_or_create(user=user) + + response = CustomResponse(_('Вы успешно вошли в аккаунт.')) + response.set_cookie('auth-token', auth_token.key) + return response -def user_login_view(request: HttpRequest, user_id: int, confirm_code: str) -> HttpResponse: - context = { - 'title': _('Ошибка авторизации'), - 'meta': {'refresh': {'url': urls.reverse('home')}}, - 'content': {'text': _('Автоматический переход на главную страницу через 3 секунды.')}, - } +class UserLogoutAPIView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [IsAuthenticated] - try: - user: User = User.objects.get(id=user_id) - except User.DoesNotExist: - context['content']['heading'] = _('Не удалось найти пользователя!') + def post(self, request: Request) -> CustomResponse: + request.user.auth_token.delete() - return render(request, 'base_success_or_error.html', context, status=404) + response = CustomResponse(_('Вы успешно вышли из своего аккаунта.')) + response.delete_cookie('auth-token') - if user.confirm_code != confirm_code: - context['content']['heading'] = _('Неверный код подтверждения!') + return response - return render(request, 'base_success_or_error.html', context, status=401) +class UsersAPIView(APIView): + authentication_classes = [] + permission_classes = [] - user.confirm_code = None - user.save() + def get(self, request: Request) -> Response: + return Response({'users_count': User.objects.count()}) - login(request, user) +class UserAPIView(APIView): + authentication_classes = [TokenAuthentication] + permission_classes = [IsAuthenticated] - return redirect('personal_cabinet:index') + def get(self, request: Request) -> Response: + return Response(UserModelSerializer(request.user).data) -@login_required -def user_logout_view(request: HttpRequest) -> HttpResponse: - logout(request) + def delete(self, request: Request) -> CustomResponse: + request.user.delete() - return render(request, 'base_success_or_error.html', { - 'title': _('Выход из аккаунта'), - 'meta': {'refresh': {'url': urls.reverse('home')}}, - 'content': { - 'heading': _('Успешный выход из аккаунта'), - 'text': _('Автоматический переход на главную страницу через 3 секунды.'), - }, - }) + return CustomResponse(_('Вы успешно удалили свой аккаунт.')) \ No newline at end of file diff --git a/webpack.config.ts b/webpack.config.ts deleted file mode 100644 index 8ac17a4e..00000000 --- a/webpack.config.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Configuration } from 'webpack'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import BundleTracker from 'webpack-bundle-tracker'; -import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin'; - -const mainAppStaticDirPath = `${__dirname}/constructor_telegram_bots/static`; -const defaultEntryFilePath = `${mainAppStaticDirPath}/default/src/main.ts`; - -const baseConfig: Configuration = { - entry: [defaultEntryFilePath], - output: {filename: 'js/[name].min.js', clean: true}, - module: { - rules: [ - {test: /\.(ts|tsx)$/, use: ['ts-loader']}, - {test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader']}, - ], - }, - resolve: { - extensions: ['.js', '.ts', '.tsx', '.css'], - alias: { - global_modules: `${mainAppStaticDirPath}/global_modules/`, - telegram_bot_api: `${__dirname}/telegram_bot/api/static/telegram_bot/api/`, - telegram_bot_frontend: `${__dirname}/telegram_bot/frontend/static/telegram_bot/frontend/`, - }, - }, - plugins: [new MiniCssExtractPlugin({filename: 'css/[name].min.css'})], - optimization: {splitChunks: {chunks: 'all'}}, -} - -function generateConfig(outputPath: string, statsFileName: string, extraConfig?: Configuration): Configuration { - return { - ...baseConfig, - ...extraConfig, - output: { - ...baseConfig.output, - ...(extraConfig?.output || {}), - path: `${__dirname}/${outputPath}`, - publicPath: `/static${outputPath.split('static')[1]}/`, - }, - plugins: [ - ...baseConfig.plugins as any[], - ...(extraConfig?.plugins || []), - new BundleTracker({path: './webpack_stats/', filename: `${statsFileName}.webpack.stats.json`}), - ], - } -} - -namespace TelegramBotMenu { - const staticDirRelativePath = 'telegram_bot/frontend/static/telegram_bot_menu'; - const staticDirAbsolutePath = `${__dirname}/${staticDirRelativePath}`; - const animationEntryFilePath = `${staticDirAbsolutePath}/animation/main.ts`; - const defaultEntryFilesPath = [...baseConfig.entry as string[], `${staticDirAbsolutePath}/default/src/main.css`]; - - export const configs: Configuration[] = [ - generateConfig(`${staticDirRelativePath}/default/dist`, 'default.telegram-bot-menu', { - entry: defaultEntryFilesPath, - }), - generateConfig(`${staticDirRelativePath}/index/dist`, 'index.telegram-bot-menu', { - entry: [...defaultEntryFilesPath, `${staticDirAbsolutePath}/index/src/main.tsx`], - }), - generateConfig(`${staticDirRelativePath}/variables/dist`, 'variables.telegram-bot-menu', { - entry: [...defaultEntryFilesPath, `${staticDirAbsolutePath}/variables/src/main.ts`], - }), - generateConfig(`${staticDirRelativePath}/users/dist`, 'users.telegram-bot-menu', { - entry: [...defaultEntryFilesPath, animationEntryFilePath, `${staticDirAbsolutePath}/users/src/main.tsx`], - }), - generateConfig(`${staticDirRelativePath}/database/dist`, 'database.telegram-bot-menu', { - entry: [...defaultEntryFilesPath, animationEntryFilePath, `${staticDirAbsolutePath}/database/src/main.tsx`], - plugins: [new MonacoWebpackPlugin()], - }), - ] -} - -export default [ - generateConfig('constructor_telegram_bots/static/default/dist', 'default'), - generateConfig('home/static/home/index/dist', 'index.home', { - entry: [...baseConfig.entry as string[], `${__dirname}/home/static/home/index/src/main.css`], - }), - generateConfig('team/static/team/index/dist', 'index.team', { - entry: [...baseConfig.entry as string[], `${__dirname}/team/static/team/index/src/main.css`], - }), - generateConfig('personal_cabinet/static/personal_cabinet/index/dist', 'index.personal-cabinet', { - entry: [...baseConfig.entry as string[], `${__dirname}/personal_cabinet/static/personal_cabinet/index/src/main.tsx`], - }), - ...TelegramBotMenu.configs, -] \ No newline at end of file