From f36ad4eb0dbb70993ae51971e93ca75fc65b3390 Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 21 Nov 2023 14:55:40 +0300 Subject: [PATCH 1/6] =?UTF-8?q?=D0=BE=D0=B1=D1=8A=D0=B5=D0=B4=D0=B8=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=B5=D1=82=D0=BE=D0=BA=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 12 + README.md | 56 ++- adminpanel/asgi.py | 16 + adminpanel/config.py | 23 ++ adminpanel/settings.py | 126 +++++++ adminpanel/urls.py | 11 + adminpanel/wsgi.py | 15 + adminpanelapp/admin.py | 40 +++ adminpanelapp/apps.py | 5 + adminpanelapp/models.py | 142 ++++++++ adminpanelapp/templates/send_telegram_message.html | 6 + adminpanelapp/tests.py | 3 + adminpanelapp/urls.py | 6 + adminpanelapp/views.py | 25 ++ auth_docs/test_doc.html | 120 +++++++ auth_docs/test_doc.odt | Bin 0 -> 18549 bytes bot_modules/access.py | 2 +- bot_modules/all_orders.py | 35 +- bot_modules/authorize.py | 397 +++++++++++++++++++++ bot_modules/backup.py | 2 +- bot_modules/bd_version.py | 51 +++ bot_modules/buttons.py | 2 +- bot_modules/comments.py | 7 +- bot_modules/groups.py | 4 +- bot_modules/groups_utils.py | 6 +- bot_modules/languages.py | 2 +- bot_modules/messages.py | 2 +- bot_modules/mod_simple_message.py | 7 +- bot_modules/mod_table_operate.py | 158 ++++++-- bot_modules/needs.py | 7 +- bot_modules/orders.py | 40 ++- bot_modules/orders_cat.py | 138 +++++++ bot_modules/profile.py | 2 +- bot_modules/projects.py | 7 +- bot_modules/start.py | 2 +- bot_modules/subscribes.py | 30 +- bot_modules/tasks.py | 7 +- bot_modules/user_in_groups.py | 2 +- bot_modules/users.py | 2 +- bot_modules/users_groups_agregator.py | 11 +- bot_sys/bd_table.py | 18 + bot_sys/bot_bd.py | 1 + bot_sys/bot_subscribes.py | 23 +- bot_sys/config.py | 4 +- bot_sys/user_access.py | 4 + config_auth_docs | 1 + main.py | 23 +- manage.py | 22 ++ requirements.txt | 7 +- template/bd_item.py | 2 +- template/bd_item_add.py | 6 +- template/docs_message.py | 93 +++++ template/file_message.py | 2 +- 53 files changed, 1595 insertions(+), 140 deletions(-) create mode 100644 adminpanel/asgi.py create mode 100644 adminpanel/config.py create mode 100644 adminpanel/settings.py create mode 100644 adminpanel/urls.py create mode 100644 adminpanel/wsgi.py create mode 100644 adminpanelapp/admin.py create mode 100644 adminpanelapp/apps.py create mode 100644 adminpanelapp/models.py create mode 100644 adminpanelapp/templates/send_telegram_message.html create mode 100644 adminpanelapp/tests.py create mode 100644 adminpanelapp/urls.py create mode 100644 adminpanelapp/views.py create mode 100644 auth_docs/test_doc.html create mode 100644 auth_docs/test_doc.odt create mode 100644 bot_modules/authorize.py create mode 100644 bot_modules/bd_version.py create mode 100644 bot_modules/orders_cat.py create mode 100644 config_auth_docs create mode 100644 manage.py create mode 100644 template/docs_message.py diff --git a/.gitignore b/.gitignore index e3f5dc5..f58b8f3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,15 @@ config_root_ids __pycache__ log.txt bot.db +<<<<<<< HEAD +adminpanelapp/migrations +__init__.py +.env +<<<<<<< HEAD +======= +tmp.py +>>>>>>> 46ad1a6aefd07c5f411d1921fa7145d938b56dd8 +======= +.idea/ +venv/ +>>>>>>> f39b738d22a536bddc60ea3016319ce06869a670 diff --git a/README.md b/README.md index 24d9c56..2cc30e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## TPlatformBot +# TPlatformBot ### Видеоинструкции @@ -8,6 +8,12 @@ Обзор возможностей пользователя - https://vk.com/video-210998646_456239042 +Проекты - https://vk.com/wall-210998646_139 + +Работа с заказами - https://vk.com/wall-210998646_137 + +Админ-панель - https://vk.com/wall-210998646_126 + ### Модульный Telegram-бот с возможностью редактирования прав доступа, как пользователям, так и группам пользователей Список модулей @@ -17,25 +23,25 @@ 3. Профиль пользователя 4. Права доступа 5. Пользователи и группы пользователей -4. Проекты -5. Задачи -6. Потребности -7. Комментарии -8. Языки (сообщения и кнопки) -9. Заказы -10. Подписки +6. Проекты +7. Задачи +8. Потребности +9. Комментарии +10. Языки (сообщения и кнопки) +11. Заказы +12. Подписки ---------- +--- Данный бот позволяет создать свою площадку для взаимодействия на некоммерческой основе в мессенджере Telegram и обмениваться ресурсами и компетенциями для реализации различных проектов. Сам бот разработан на языке программирования **Python** с использованием фреймворка **Aiogram**. База данных - **SQLite3**. ------- +--- **Установка, первичная настройка и запуск** ->Для работы требуется, как минимум, Python 3.8. +> Для работы требуется, как минимум, Python 3.8. *** Загрузка зависимостей *** @@ -45,7 +51,7 @@ `sudo apt-get install python3-modules-sqlite3` -`python3 -m pip install -r requirements.txt` +`python3 -m pip install -r requirements.txt` *** Запуск *** @@ -65,4 +71,28 @@ ## Тестовая версия Тестовая версия запущена по ссылке -http://t.me/Test_TPlatform_bot \ No newline at end of file +http://t.me/Test_TPlatform_bot + +## Запуск Админ панели + +### Создайте SECRET_KEY для джанго + +1. Создайте в корне проекта файл .env +2. Сгенерирйте секретный ключ. Для этого в терминале (python manage.py shell) выполните следующие команды. + + from django.core.management.utils import get_random_secret_key + get_random_secret_key() +3. Вставьте полученный ключ в файл .env + PLATFORM_ADMINPANEL_SECRET_KEY='ваш секретный ключ' + +### + +### Выполните миграции + +1. python manage.py migrate +2. Создайте суперпользователя + python manage.py createsuperuser +3. Введите имя пользователя, почту и пароль +4. Запустите сервер + python manage.py runserver. Можно запустить с параметром IP:PORT, например 127.0.0.1:8080 +5. Перейдите по адерсу http://127.0.0.1:8000/ (адрес выведется в терминале) и введите данные ранее созданного пользователя и пароль diff --git a/adminpanel/asgi.py b/adminpanel/asgi.py new file mode 100644 index 0000000..65ed7db --- /dev/null +++ b/adminpanel/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for adminpanel project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'adminpanel.settings') + +application = get_asgi_application() diff --git a/adminpanel/config.py b/adminpanel/config.py new file mode 100644 index 0000000..8444255 --- /dev/null +++ b/adminpanel/config.py @@ -0,0 +1,23 @@ +g_telegram_bot_api_token = '' +# --------------------------------------------------------- +# Файлы для настройки, которые не коммитятся в git +telegram_bot_api_token_file_name = 'config_telegram_bot_api_token' +# --------------------------------------------------------- +# Дополнительные функции +def GetFirstLineFromFile(a_FileName): + f = open(a_FileName, 'r') + result = f.readline() + f.close() + return result +def GetAllLinesFromFile(a_FileName): + f = open(a_FileName, 'r') + result = f.readlines() + f.close() + return result +# --------------------------------------------------------- +# Основные функции +def GetTelegramBotApiToken(): + global g_telegram_bot_api_token + if len(g_telegram_bot_api_token) == 0: + g_telegram_bot_api_token = str().strip(GetFirstLineFromFile(telegram_bot_api_token_file_name)) + return g_telegram_bot_api_token \ No newline at end of file diff --git a/adminpanel/settings.py b/adminpanel/settings.py new file mode 100644 index 0000000..82495b0 --- /dev/null +++ b/adminpanel/settings.py @@ -0,0 +1,126 @@ +""" +Django settings for adminpanel project. + +Generated by 'django-admin startproject' using Django 4.1.4. + +For more information on this file, see +https://docs.djangoproject.com/en/4.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/4.1/ref/settings/ +""" +import os +from pathlib import Path +from dotenv import load_dotenv + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +load_dotenv() +SECRET_KEY = os.getenv('PLATFORM_ADMINPANEL_SECRET_KEY') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = ['*'] + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'adminpanelapp', + +] + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'adminpanel.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'adminpanel.wsgi.application' + +# Database +# https://docs.djangoproject.com/en/4.1/ref/settings/#databases + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'bot.db'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + +# Internationalization +# https://docs.djangoproject.com/en/4.1/topics/i18n/ + +LANGUAGE_CODE = 'ru' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +ASGI_APPLICATION = 'adminpanelapp.asgi.application' +ASYNC_MODE = 'django' \ No newline at end of file diff --git a/adminpanel/urls.py b/adminpanel/urls.py new file mode 100644 index 0000000..6f7db62 --- /dev/null +++ b/adminpanel/urls.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from django.urls import path, include +from django.views.generic import RedirectView +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns = [ +path('admin/', admin.site.urls), +path('', include('adminpanelapp.urls')), +path('', RedirectView.as_view(url='/admin/adminpanelapp/orders'), name='') +] \ No newline at end of file diff --git a/adminpanel/wsgi.py b/adminpanel/wsgi.py new file mode 100644 index 0000000..f30157b --- /dev/null +++ b/adminpanel/wsgi.py @@ -0,0 +1,15 @@ +""" +WSGI config for adminpanel project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'adminpanel.settings') +application = get_wsgi_application() \ No newline at end of file diff --git a/adminpanelapp/admin.py b/adminpanelapp/admin.py new file mode 100644 index 0000000..b48d035 --- /dev/null +++ b/adminpanelapp/admin.py @@ -0,0 +1,40 @@ +from django.http import HttpResponseRedirect +from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME +from django.utils.safestring import mark_safe +from .models import Orders + +from django.contrib import admin, messages +from django.urls import reverse + +class OrdersAdmin(admin.ModelAdmin): + list_display = ('orderName', 'orderCreateDateTime', 'orderDesc', 'orderAddress', 'show_photo', 'show_photopay') + actions =['send_message'] + exclude = ['orderAccess', 'userID', 'orderPhoto', 'orderPhotoPay'] + + def show_photo(self, obj): + html = obj.get_photo_html() + return mark_safe(html) + + show_photo.short_description = 'Фото' + + def show_photopay(self, obj): + html = obj.get_photopay_html() + return mark_safe(html) + + show_photopay.short_description = 'Чек' + + def send_message(orders, request, queryset): + selected_objects = request.POST.getlist(ACTION_CHECKBOX_NAME) + if len(selected_objects) != 1: + messages.error(request, "Выберите только один объект") + return + + selected_user_id = int(selected_objects[0]) + obj = queryset.get(orderID=selected_user_id) + user_id = obj.userID + url = reverse('send_telegram_message', kwargs={'chat_id': user_id}) + return HttpResponseRedirect(url) + + send_message.short_description = 'Отправка сообщения' + +admin.site.register(Orders, OrdersAdmin) \ No newline at end of file diff --git a/adminpanelapp/apps.py b/adminpanelapp/apps.py new file mode 100644 index 0000000..f766249 --- /dev/null +++ b/adminpanelapp/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + +class AdminpanelappConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'adminpanelapp' \ No newline at end of file diff --git a/adminpanelapp/models.py b/adminpanelapp/models.py new file mode 100644 index 0000000..060fb63 --- /dev/null +++ b/adminpanelapp/models.py @@ -0,0 +1,142 @@ +import time +from urllib.parse import quote + +import requests +from django.db import models + +from bot_sys.config import GetTelegramBotApiToken + +class Orders(models.Model): + orderID = models.AutoField(primary_key=True, verbose_name='id заказа') + userID = models.CharField(max_length=100, verbose_name='id пользователя в tg', null=True) + orderName = models.CharField(max_length=100, verbose_name='наименование', null=True) + orderDesc = models.TextField(verbose_name='описание', null=True) + orderPhoto = models.ImageField(verbose_name='фото', null=True) + orderPhotoPay = models.ImageField(verbose_name='чек') + orderAddress = models.CharField(max_length=100, verbose_name='адрес доставки', blank=True, null=True) + orderAccess = models.CharField(max_length=100, verbose_name='доступ', blank=True, null=True) + orderCreateDateTime = models.DateTimeField(auto_now_add=True, null=True, verbose_name='дата и время создания') + orderStatus = models.CharField(max_length=100, verbose_name='статус заказа', blank=True, null=True) + + def get_photo_html(self, width=100, height=100, large_width=400, large_height=400): + file_id = self.orderPhoto + token = GetTelegramBotApiToken() + url = f"https://api.telegram.org/bot{token}/getFile?file_id={file_id}" + + response = requests.get(url) + data = response.json() + + if data['ok']: + file_path = data["result"]["file_path"] + photo_url = f"https://api.telegram.org/file/bot{token}/{quote(file_path, safe='')}" + + html = f""" + + + + + Увеличить фото + + + + + """ + return html + + + def get_photopay_html(self, width=100, height=100, large_width=400, large_height=400): + token = GetTelegramBotApiToken() + file_id = self.orderPhotoPay + url = f"https://api.telegram.org/bot{token}/getFile?file_id={file_id}" + + response = requests.get(url) + data = response.json() + + if data['ok']: + file_path = data["result"]["file_path"] + photo_url = f"https://api.telegram.org/file/bot{token}/{quote(file_path, safe='')}" + + html = f""" + + + + + Увеличить фото + + + + + """ + return html + + class Meta: + + verbose_name_plural = 'Заказы' + managed = False + db_table = 'orders' \ No newline at end of file diff --git a/adminpanelapp/templates/send_telegram_message.html b/adminpanelapp/templates/send_telegram_message.html new file mode 100644 index 0000000..4644d06 --- /dev/null +++ b/adminpanelapp/templates/send_telegram_message.html @@ -0,0 +1,6 @@ +
+{% csrf_token %} + + + +
\ No newline at end of file diff --git a/adminpanelapp/tests.py b/adminpanelapp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/adminpanelapp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/adminpanelapp/urls.py b/adminpanelapp/urls.py new file mode 100644 index 0000000..1e407b6 --- /dev/null +++ b/adminpanelapp/urls.py @@ -0,0 +1,6 @@ +from django.urls import path, include +from .views import send_telegram_message + +urlpatterns = [ + path('send_telegram_message//', send_telegram_message, name='send_telegram_message'), +] \ No newline at end of file diff --git a/adminpanelapp/views.py b/adminpanelapp/views.py new file mode 100644 index 0000000..a256528 --- /dev/null +++ b/adminpanelapp/views.py @@ -0,0 +1,25 @@ +from django.contrib import messages +from django.http import HttpResponseRedirect +import requests +from django.urls import reverse +from django.shortcuts import render +from bot_sys.config import GetTelegramBotApiToken + +def send_telegram_message(request, chat_id): + if request.method == 'POST': + message = request.POST.get('message') + + bot_token = GetTelegramBotApiToken() + url = f'https://api.telegram.org/bot{bot_token}/sendMessage?text={message}&chat_id={chat_id}' + + response = requests.get(url) + if response.status_code == 200: + messages.success(request, "Сообщение успешно отправлено") + back_url = reverse('') + return HttpResponseRedirect(back_url) + else: + messages.error(request, "Сообщение не отправлено") + back_url = reverse('') + return HttpResponseRedirect(back_url) + else: + return render(request, 'send_telegram_message.html') \ No newline at end of file diff --git a/auth_docs/test_doc.html b/auth_docs/test_doc.html new file mode 100644 index 0000000..3f326bf --- /dev/null +++ b/auth_docs/test_doc.html @@ -0,0 +1,120 @@ + + + + + + + + + + +

+
+ +

+

Регистрационные +данные

+


+ +

+


+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ ID пользователя

+

+ TableFieldDestiny.USER_ID +

+

+ Имя

+

+ TableFieldDestiny.USER_NAME

+

+ Фамилия

+

+ TableFieldDestiny.USER_FAMILY_NAME

+

+ Отчество

+

+ TableFieldDestiny.USER_MIDDLE_NAME

+

+ Дата рождения

+

+ TableFieldDestiny.USER_BIRTHDAY

+

+ Адрес

+

+ TableFieldDestiny.USER_ADDRESS

+

+ Контакты

+

+ TableFieldDestiny.USER_CONTACTS

+

+ Подтверждение

+

+ TableFieldDestiny.USER_CONFIRM

+

+ Доступ

+

+ TableFieldDestiny.ACCESS

+

+ Дата создания записи

+

+ TableFieldDestiny.CREATE_DATE

+
+


+ +

+ + \ No newline at end of file diff --git a/auth_docs/test_doc.odt b/auth_docs/test_doc.odt new file mode 100644 index 0000000000000000000000000000000000000000..92fa308fe04a9cd84a49e5d9c1399e8794930fb5 GIT binary patch literal 18549 zcmb_^19WCvwr)~MDy|q6+qTV$QL$~?wr$%sDzCvb3_d`lb3G@`&*#dfK|W`eync z1-1N7`TVmKf7OYVwuQdg|1w1@8%skQeOufAeHm@-wC(Kw8$IklDWkEuwxPZ)HJ`Da zxwe(@ar8Bu?jMICC8bwI~79o8xeJ>XWAHpp*2Na@(jA9gu^06^+)7v ztyInVD{RY)4dmD1W{dEyw z;8@{&#&^4JXsqMg;0B5^b|+a;&JQ@8p=)f#Sv3&a4YKWl4LH%>JmKKt!+v(Y7%h@w zee?-8GOS(MXWIi>?K8eP99oy;5fh8+K~M#I8k_A^=W4ziZt+Gg=ejQTGksSZ_;Ffk zbmvmXt?bV42X9mp?_ako>l_5kc*b)LpQ8@yuCc!hS4xY4g4I13O@jae0Qdp{0Q|iV z{8{z=tsCmwX;V3wn}y4bSgg>%wmpzTF)0S;<*Cr(lJmfD<{Npl@mPMAu+VFOCykQd zeRIFd+0Ns-B^n<;J^fO=y)`|Xic%%{wOyEj$OuRUwb-s+SSpZuiqnOJ8*%?h8C+{R zr~>dT_cO-^lxw&G}ER^O?m(2x7myrtTP5tag$^?i@kdkcXn$l&|M; zx+%I&sC6Rt8nQ^5MuJ+2xY#(+#-z72{qCV z87CMLj6h--^~J%8>;;mC>KQg;vn6i8#JR1#l3bo$tHwX#n^+O%UmQYm#gb3b6ope_ z&kc1q8XKey7`KJTwhHIBj$9qQ-ZzagDf;P}j#0y674Dwf7Mgq|3>`A#n<+oviZY>S8U!!9emcpUO3e3_il4?h9PE{iq!xSd-G5U)8ky5XF<^*+ zlh;Mi2RG`x_~Gi-d$x75{2f167+!O*tO9K-uhb;ktMs|ZM0Rpyp`f-iK@)?YTiUbEG$@gO&+Qb)KO&5_tCfCrBywe&#{t7P9BretRy5n}ujVJGk1&SbV zQLzzrkBn_h{o5uxdn+fEW|Gdtn&w@mu$OOBAbVVci&6>@Z*FdG4hrIr%uzc-$J)7q z<6jzL*E5rhVRY>1jl})1d|h+3jlw=C;7z+1 z>n8EOtSgneQ?&WMSsbJ$w;^?YExA#MsUAv)Y1AC9?{KtoaqwtsU$vjIaZ_7TDT(C= zX@yC^Nx*OM-CSR$$;ROzC1|y1V;(xT#{M2L-iYuvlceXBv(C2KtE34QyR2hDw?RWD zcDvG~A+iC_q>;A}?!2n3)!8T}C$PTAs9R}foSJar>odr|TIb}geYgQQopCu$Ggxs1 zb^vn)V9?XHYQGprK$I?Z8#kaaL|>#X1{ zO9Ro2=|WRhj463RSH5%a0+M7_u!GJ`R?2*T;H8@PO<#=sId71zdK!p$SjZOT{DlEp zKfVY9VNue6I4@Uzx4@$C7bIrUN^DG>{sh+ zQpK6j?R~fF^0tkm#`Tw>hQZTJ$gHpO0xaooz?>ITjQRE%R2Sps2fg+AdTq+Q*pd4V6|D$5{P3&W+un+Lh-#}S*f zHGbMV$r@5|KH@M81u&}<{~_4yIS|NBZtiv#$SI{0IsTU(T!ccKOC~3PNVf$b|E6nT zpqXw6>B{of5VTNw;RXg3@SzlUYkI2VRV32I0!C46xBlqpiy0*+9B7~)Fa8^jop|A+ zDr(23-mv%>25$s#Y#LKl-Qbq$;5gu}qr|lxgNrqa-$QlzBKu@v#EX>Bvsi|QC#6dC z*Ts#=H+i3jD5q73E>+rTN>}FhpgEB#K$y;8vUl5h8Vg{!qIZV4h!_ZbUoUE93FVtWP~3gNs`~NGnFk|##~{Eo$KM2>@`*>(n~yfI z(Cb^LsPGE;(a+{jj)oQ51ay50mypQSATGnc(cBf|z7=B;7yW2#GTFeJ~pAwv&t= z@z}+>$xjJWRTGVZyIo^HS+SfygMr`a_8U00n0tnT;Ul#`M&lUz{4qHrFE@!Rq#l!= zVV!HO-ltcAqWZ90C47kJ7k_Iz1~eGTfvn?sPA%(iQ(RRdnMKe!z*0EbiF4h^+8X1z ziX4q)>SB%gJ1ffhx@h9)v7wS+nm-!)(ZGM+oby_=CG3lvhVrX~mJ@}|UtC&rzQY(# z);H6?U5q-jrpz#?6)F0U`)wcZztAdT|gL|c>7Mql{s5t_Cr^2+DAFp z@RNYC=fWN9kwW^i%XwB7>|mH$3GKo|XXl7pe-Adt-^QB%E>vnhUSU=z4IM4Jk?ybs zSEVi-t9V&94O68d#7A2>-=48`EO3cX)^&W#>~EZH!K(_jl{|WthYi9>pT8rEkre#3 zHE{1o$@9r+m5qag3V=?BXxR^jDZqXN$iZnP@c#1IkLAVE_H)}1d?2;385j*I{rkDN zc-Qz$-eG&VIr* zl^yG{ZPMc%Ic(d`gw%AMta>?*1mCmwTxxoT`8CNtalL&Z2L%AQrTxcR>K|L0#cT%z zu#f%Buj|(?MBd2WT*pG&*vyvN?jKPqD+|M5X-Q#d2sDU~N1#PT1Y`jK08Ib@J^_Gz zOxply-t$%;!mG5nydWR|AQ1Q$NFV?hNC;49Bxrav6!1@|a9>c6Q6Z5DP|%6su^7@7dmr_xPNn4!NK!#ID zNJLOvNlaGtyO@Zqgq)hJxWacuK1nT6MFUZF>+h=i5;~5`+Ga|I4my&;MvB7v3bHop z!djYorrIiwIucHXN=Al8dZvy>*6wzu1|M4_R~utTdk1B6Zw=c(BQq~U`v7CNXgjw6 zE6*qk-*9v9cxRtbhrlG~@EniWB5!l$02_@!2Sa~1hiG@xXiw{45AR@amjoa4qyUGU zaM%23_u$}Q|FF2osK}6*l-RJKnDD6NnBcg$xPZjsko1~_wA}RkjL5vou%t zfyK6|m8P++w#nV@isZiPw85srzP8$_w!(=Y6}>-d`+l^JcGZsdwv7(9&v%tA4mPY! zwQY{K>`b-y_H_634-X9X_705>_V5j zEY43aEzYj2tPCvf&#dlDuN|$dZ;fuonDT??%!UW-aTEs-0b|kJAQxMdwDv&y}iA@f4Y0VyM2Cny1#mPzI%In z8(EOu0sz487Zu=@cUnG6hf$MzSi5Mh_^x+86?%l$@;yWC!BB>16 zu&2SM#*^U>Exu{1n}ecw^dKT+a2iA(ZwRQp36*aK?pTU&eC)ujmtj6&p9Fz8CmCVN zx^~?(AJPymr4}4gW4)eV!GvwzcGKE!_69C~4m~`uV|m%ca=-%S2+fiRgcr#Kp~>Kz zApVyG#|ZIXQV^Pd(cdM3aK72UOF2TgCVwW$UfYW|CK%fn3Y06EhScC!QulpeISHTKyLefk;+ zm{|D$ovNF(6z&MtV z3c2K)-$Vx(eOLMC&a%^#P{rI`A=|p!YUc=E^tUQa4rAXAv-w`B=h3YO`HfiyvH~Vh zo&{fSiPx}(Mw!qU+l!a)%M~BEWIJ5?7)-kGX^XMu&^wM6-$n;K zduoxE78;8lUFL+Rri>KOlS~Yys*|w5<28`si6dqkqLTNd9cv4~OwJ>IzvsniVgkF? zmWQw7ZwZ3b?f{e<*GJCh%3^0X9dLQh;fjFaY?I7E6dq*TC=(q|s}H#zZz3LEhWS6_ z7^_Gx`wG?z+g9eOj3sa6v97}?HFi;+r&CQ680bM~UWKRVWhN-8V4Ruy=@ZsXu2&z& zrxTYmJiBXNr;6%VH(Z{@gAZeMAZ*3#5RC<`u-Xr9b-7-@3t{^{TtX;V%v^&oz~<5zDZ-Nz~h-h&RIUL!83y z_b+Wv-{lwgWm>fqSAP~|2p65fFdaK1&hoI+Qy6~}pvIb+({h!{oDi>mmq#r{C9c>Y0(O`n)bVu*m=Z#{Q^18XCd!9s zh9oi?v5k@7+;JL$ zR*3y^#A4+BykDb!y@-FpZL}_aRU=vpxrAG5{PqvQ#c$k@KfhSvB>AloAIQkl7fDHa z1b)fD9CG!%vn0+my4k&Awi^2BA+nK9titAkp zGVx*~gi6_&n=6C~+6ZGL#M+1CrYq*7z9zy0PB-~{*DGY6K*GGLBm3(AUQu)9RdfyZ zV|`{^jkgIhMMY%Qj+Hiwlji$p!v;cg zMGt0Ai7k2?OE4K3v5|_GL_W-)tpf{$W0I;81G@4+;Vm+ROu*^bY-#$oN%Cosn6d0V zBFOfRW)a6PMnIJcjJ&x_#TD1XM-By0U9BbzlS9*A?|J;_HtZ07cCUbwt?J>IBmqV?-ku?KHa9?_%-|13g zl@P$nN%49N%Agt+Gm2vE7voHT%Y^e_Dc@;t@y37y)3hf4w$2fDY^r(e4YhtDUrkfySH}D)BD}7^V!k~=gmc1k;lS>zP7~)-#FouQS2e+;jTktjel-p zlr7raGE##%^=&{jLVDD-;oMKems{_n#)3^-_WPrpTG+RFquB=Co3r;Lsy83_% z4z#Scu*(7^j2}j44-hTsqa>T@!VN~$nbiH~%&M!y@(;{F1-(+uLr;zP>m7QjdFKgp z!^nW$YaaP+=H>zxO77Z`Jcw5>=4!di!mls_gu~G9lXhA<%Rp0OPBj~v9{avni5ND4RZ%uRfc=TD4z)?NIb+}In2Ju)H)!Xcp z3utJSUSTTcvCU3^Y@yxo;V0&T^sC-t4L6By6g*Y0;jTT;Uykpij<#J?0NU+c0%-|C zHfoM*Y<5g<6l8DsDh@7@DRR~$Gh7y*PC#`cH6%=LY5JzA_Ffe9BJ zY|CMZavg=#BhWlnFrE{BPg_u+l-!%G5KH>_VN|Y##sorv`U=G?(7S{V3 z%OS;&2TIHGbo$%7*@C#Tu@3MZ+&&*lHVv}^T=Q(QP)#_2RGbf;lv5{uww=pR zXNO3r^S?@UaAF5n~J9BHNiai~G&BIh{F15=3)-eW#E4E|$T5B4%(!fXD)- zzz=|INgu%W%q3W`6C0Ru2i5W~5KHhWas8gG@AaC433le1$=9XpK4-)HQiF=OoS2(j zvr7t}8Ik(3EaVMPo6Px_DcI#euf6s0@ND7)-2*ahH*@L-f{^5*RA1u5WHF6q_TZP3^LIxAJ2NA@BZ z!`AW+WHdc*{w=^7;4%Nbi$a0|>)aN;nAy}&#dC>O%!7{4y9oV2&Cw;nBt!)2IW>0O zISF+3IILlyvOP{X;4@f*yrQZCVzVp3ci)0+oN*vPPrR+JYr?z6UduqI5sZ=%BUl{c zOv3Nx?pC`d3yhL8vSx$Jq}dET^Pdad4Py|X~Kxn^0A`_*-|p$yM%1S{P+EUEgwDBPA#0W~+8Gwyh* zwaoy1%~_CK+bB9JIzND$db;VhNQny4>6`}&p6ONU=miR<@=q~_A&^>R-0{BUSO9US zRsjb6Vr@@5X7J7|8@|Bo&hxO=b4O?3Ixch#_3EnvK8|Tegl+Rho zFHmeQcmU7EPu8^{E$Y&53GPV3LDZ#{JvYTnyuc(hLW;-@~$jbi4kRyvJ z+)9K9zkS>#sD8;>7lcN+*VZeIKczAKG%~$z)Iz>923R-rTYV{&VVldaq2r|7b*6MD zGj(;5VgOO*^^o&i`A4OAGgM)T2suleZ{v1Ug_25cN(c!=j?Q|M%v?94D8mpe<-sdr zrC;&XFc%jwI)hZ%XJY@X?zGMHlmY~$lVl)eIS@_Gt`t zkoS>vyZBw~x9 z3aYcIfyH%t%|rFYql4Z?uODdWd2$}@MRiWo!GRoI9V@5_3a!)?6LH5|T*YSy^RzPO zCWs|SPkMo{i)T^^7IRJy035|M4$(AV!6BlY5=6q35}V=Gbl7NCt%-}RRE85dH;C3J z3EV%8k`iOvr6{lcyzfiBW{FuC%J;2#Gg@MAM3Ze(u%W6$f*o&?Gim%el9XqMd4fE& zJ}MZ3&cLX9p*94WO!-1TqXi{Y5IN9~Zv{gmR4^4EueQO`U71IOU|fFqq$m}wAWr;( zk7qgU{-wHvjROb+T5JAfPcu$6Y(pJ|T+~~EZurtR3ZwJZf@VtxZ{du)`qiW=8XxoB zr3;SZcTm}gSCd_;*!VLG3hug%q%7q+P?V3 zA5DOZb^R`qiKE0>;p{A_ydfnWhTxXuVbVj}Rz*2!9Z&KTOL|gEWpiesOym$#K zfKl|J{xM%uXy+^D*|VqwJrv>=){=n)n3YlT^n2^7Xst%~?X27sjYUzDxEi1D($1V- zFTL80E5c`aYbLp!hO{N-3RUc9H0Qvn>3G^{T#4zxFKW$9`<$|;5wW=xO&P*S(W{3p_Wwm@DEH6d2D?66Y&JoqN!USm!#(eue_~MkRrp(84qFj;DfwL7i)zw%Jy8Vm#P| zY<$mqR`{jMXdVvRG{97tNB-!V=QHUSwT>fi9{zoBEuttW;|)2Gufr{R!yDCw%S?91 z08l2H@6XD%2E-+#Ip@`+I2yDTauC}Z(XY~ordY|TMGkY`x2+se!$IeHJ#b~9I*}OG)idK{~W5?O2ijB9F%E)a95wJ1X4n0tE~=`}+$P9dt*dGL_Zn9R{@Iy4q@%c+y`ShCJ9&VW!(5Aqo%`T!z#D zZu)LdF;4|qld;tl`|}7-xruB2eU8pMO)+cnTQi=L)mhD7RxH^wSOaXtEo(f-w!5$( zeX)XmvbpZSw1MKm)EUL!^Z|)#alo?u1OnXg-X+-ItJT$hcAztzljURE`5Ly42DyXy zHM?V0bhjEyL{YCIsyxQQ1cGsFM*y5wZ(q3|k+K&n-$(B>9xI1NwGw6qo8hE}x|y*A z#x)hZi4S#|;DFGQlt3UgqRKF_G0t>1iFyvl4sG zpi7HiF0w<{$8x6j#yc&-7v8r=dU4PNCj?h#kOnws<6|NAcA8cce)`HeP3Bz#mZF7Y zM8`N-ZJCCssByB;3)ol9?+Kdz6AFTADR2#S?qKsWrcm<7v(Lf$ZH-F?J+-kprgI-^ zOx(8&7?})6nQkwXqlzL2XPl2|iR@!q0#OBxS<+{N-49EF+OQSnlmpHAxcNdaY7eSr zkJD-GjH6#sO=Ia-Ez^F7Z@^2pqjfz;hMC%#7-m(#b*C#OYwSm|N(bB^8~htKi5 ztDF5E2=U#?v811-X34c8`$j|OrRjq+$w2ogvEcK$o_QR4d-L?v?-54eF#2d_(gdCn;I6FOpb8_9AR%&@=YP_(ca+d zsX??%YSt3WGK*J=Q{YPOa}~2u`xYwgsuT@Y5Fho(d6n@sI)Q+*qjPX|LvCP{QUv^h z{{bC&%?RVu&XQm);@o)j$LdV=`AhvR4h_~I*p7GI#}9!g2lXB^Yrb?(U<}@KDOXPU zpg2iDO(0ZHqchHoJq|q~s`VvL(ZQv`Z#FwlMTLL*)YJaZw!g)jYuIcei1q-?Mn53A;cI77^CVFfzdLI5% z!ivoY!j^ML1Ou4V)nq1H%T+nz+2B&MS!O3Q`x%9OvIWnN zv!FP%#T2ngQa4Oyd+u4&?RBbPTTj(;b>3XAGh37V;%!%TcQKLjMjR@Fc`cXe{iXWx z1;^Ul{f%}3a%gO7iI?%AsPL5-rc3Buv-&xPB#JZ7Wq*5&i5SRy|^4zM61d;zZUeA$#!q3+I7_14@TgzGo0 z#g=t1o&v~nHC5%m?<`T>Blpff!V^{AW^IqPI+oK58E}~>QJKEZ59#MuoeeM{Fg)%zQ3Rz$sJsdOS{2}gV1tNC46|EI3G z!Dd;Nnb?^`n|MewX9z)=+GoQn1DIZCL)kGdt5vnt>SflF_ZqV_onxN2;_i9nd!El* z{gdUwlrcwew6n0%Jv2XCN~>vlDZWGKc0PAVYFkOpQZG=1`6qMR<_v=#Or#avgStt| zr@;WP9J?aVjoSskyCuQ+oqr7NMg}F?=Gl$cc_-T9&kGYXhA}bLSSx$%1qVpT(LIP(2wm+yUWrt@c`H(zPh(l0&!)~|bEgtdbI%VI>0{-~n7JI!k0i}Y6;u0L8(doH zD96u=j?Av)&Fo11mU44MyRh*weG9`l20&fea)$tfX9ZZw<}Q3mgp=lzx>h&*`E!R! zH$<(89s@^u&s1;pVdoz@CCIvjIf8O*?L>^fphpH_)ChTdK>=a)q33So?C1fo_9Obt zRxP2~QYTqRZU(X9SoK27NQiQ)>nW>0&A3s+KPN=Z9xE+oaDWyi7jaoBiGm<12*lsRKP`>%2PzfIddT-{EfB{+KNzmUo)mcw(05TzD8moN5P&k2|C4}KqzdjXaB>Xb* zBBUVn*e}%(s5tA?;HxBP9<=gytX4O-&9c()t-4M$3R`!t4TV5geK1AFe>33XwQY2qsipj zPzn;+_Q^`-5(LxxmiFqC;kP+`o`UX^a(2v@Kx*+egz^-bjA}-^Z?4LZB)W+x;kco6 zA^KRNp9*z?`IciQ(dctzl;}q0Kpt>P3Qu^rq{V_st$(Vv9I?UHb~xJ{Bt^7Si*s%` zx4}lB%m+3iB_U1o_E`;q0Y}jYg-CgvgQ|+2kT49^259{hp6@4MSIw7B1a42&=IJpE z=uzv$0!}L5=N;jRe7hmY?m~;b;xjkZpT(T_3)W}skw#$%DCWIzYwKz zztIeB8@0RUV!BnUB_yQ9S7;r+^_>Z=FXcK@%Dk)f^e_lbwa2kO{y5|dwT$qW@n7oZ ziiB-C=HXgXQcH;*3G;t~%xqQ$R|VZ3!Jv|aD)%e5oU|@OUx9-C=3`uY$em0XKE(6X zU9J6PD2_Jl$slp!yXwc+0F;c_D%%_jiOV{g_XpQIr|3TF2Beo7v-I65M~=Nv?k9`w zo&cedG)WACW`4-G1SNdpUO7cD4#Ow=EN}vs~@2pxT3~B7ktqh&Rf=F zakQlncQgx_rIGE{z6ej{PzT*U0WgtwlhyOnifQA*rG)AL&c+7BoKq+$HWK%t<&Hvu zkff=di~#Yrx3kDef%iA0ilI#8kSu6tXv5tqHbK3NZ^K4IT8L?pjjIx`mpm@Mav8bl zmfbNqnhEGbK8&VFtb__iG8?+AxN%@D&n)&A#Y5tWMg4RM7Z_yY)UiS3rm`NSC^@ z)Q_LHxmbKA10heWQYWCxtSu?W4|zk)d2UtUu8_JL6Kn8nTO8Wzz#c|#TIKPMo#Aw5 zZBBr$7Gcit;+Dr^f${NqDDS+!_8~HNek_JL;Pv=tv!*-O{zW>l{XAw!5p|d(-1wfm ziC>Fr1lpa{FLQ@4!yV z26x=8e^|Hyhzd#yRPbr}{Iw^-FVi?%J7+WfzZs~Xsi<16Fd=$uRMIe*S=JG-8^c!) zVX;A>Pg?L$Pk>O$AftpJiVP>dJ!8t|5sbv-GAP#qntFZOX5DSRWJihdc)jV+s-=t$ zf$%`@y&*}0%Lt0Q9y7l@+NnHbdwe=?UBDYL;!`LVDe}rF`!8<{hl)`yYabs zevb^wv31R@F%7aAoVx=C8rryKL3^`_nNDH}_5m*>VT(w-y5C4_=-icCH}gctO32OD z7D1)NP(qNl#t!2XD4y!1hOFjC{4TjS(s%L*$Q%VW<=_}A%d?V^_8P7dVLIH< z;#z1+M+Pp4jBfeeuAk z2w3*=GUE7NuywZ7z;3!KDJ!ApYhPO$o4p^ zJeADQ0CwaeHT(o`6M*0&8$)CN(6Zic;H2P*j&I?snU{5R3bb!>54ofh!K^f`^?Cdf z0b=+|V^?Go;&CDGc?#laL~oL^5kE^b;;ABgi9D=_KiSpIiH&p$qA&&F95}%SC52Ya z96sVJ5`9De&?_P(=LPfB6{SA~j5P8p1om9z0JAf7rYNHlU20ycc3M^%BFH`rDM|!L z2zq7eS4)9!bZWE<+mG?-8R)?yX++)!_8UcUuPK~(b2-;C*r1c+BWv4uNWEF%s`>%!l`~v(VUgyEP^DVr|U?zC`y2jOejMto& z7-Q5U{c9RXQm-+tAu~e=>o3-1YqMrT_lC#9QvL>fXCWC7(2RxdglN+jp1@}TSbKq_ zqPe_0R>;Fu_)poR;Ek!lsFHGv5T&6KU}4C0GM;$bBO$~sB`6HwAZ5U<+NRiFz+v>` zWJRD>!MrPW=qz^bSd6||8K9TFB7#8p*+*I$Knf~xc=KnmPc&j{h85~j-w7u!;j|9FokheV5f(Q5 zDw0yq3y^?fh(20a0d%J`6gkK-uTj0XL(94)aA7(aw)&UPDXAC?Wf06VtNM>%K$$30 z2lXN_{3e`nn-CPZKfOl2$-Pn|H#|4)m}b{E|M2d|(O`+Wt3HGHIO3yO+46NEnF-5- zTlxBv;(CI)|JBcaO6VxpHX`=Csq?LBOA(db#>vIBS7{r)Zl9KQlyqL)d6>0QU4OPJ zKzFr{DI0BPS=s}~FR=U5u))w}HUdj6)f1`q(;OT#nmLMMgx*i@v`L9C*~kNl+~SVi zs)q<2{VnvY{>g;Iz|U|LD3O7CjXe3CaLN0l%!?VonQ)YwoWa=1St}GA30Y@%>h67J zFhV89I23)|LmNE8JEE?6)ujWYP={7qX5hpZLn|7sy)vLg@2Og}<<%!ibCc=XvDSC& zY1$7HL1ZQi?4czGz9K6Jo=X>z=*1m*14Q7+^T|{byF;ixe0)Wvt7O}a zp#-=~SeO~O?P)zKJpink%5e$LJ}E4}yLlMB{kVjAIXzlmC0MKN@u_JA?3l}&`dr@j5gL3(1gS_M((MR(WE~n*@Yiz8 zJKfOs?xtpAYJtGE9c1J7A0h>q;nxDo!rHOIY!~tl_4m%hYUEuhlfX_s)WOn^*|0t5 zSn&mp`f#8?;_bu6q|(%56Vk|693eUjC#pW&KvWj{in+*aaGN~getBBp4yu#{h?XV3 zZ^=5l98>5_Tx?(CB(tj_4|5gK4X=cz>zvKR@NSrUw;G&iMbvcXTJTde1uIpcTij|? zu-V*3M)qhl%gq~GIh6G!lAg>1eOF0i?;gLloJ_i4a1qIPKa}TW>HTy&K}95O4>ffY zxFPAV7`u}Cltq%&b&a0E5(4UEWk9tasI;60Y+kNacLZSlte9_y`PIH{b_X6lRrqud z#ynH?!cy-YWUa6f_te$Y)@N+4`W38|>JTb}YF6mTSc#3#`+Kbr{up#h{P_BtgZ;Um zEiwCT0!*N1isJ+GFH8D!!^XSW4@>&x4}1B)UJF2etOax}E$n`I{(g9?&8cWwq6@-$ z9>}Ftz*`>FrY8^)iSG4QS0SS8Ho?1x%saZ?Pv4zYx4sP^P{MN{f@3{oYja4#A}@KdN&Co>-EDxx9V628pyEF;BJHJZ2NKIGk!6|ka(L*#~k+EK4n zqp(O)pAmxp%I_oGcq^i_8vE)GpI=^1NxvAbOo_|1i#P8uBJUc|t7}XY0y0FCr{}TG z!BOMV6bZEr5v&F&m4CV?3trpfq^WnAIA+Ce(4fpMM{kAd1V%%&+P&QiWC*%iPD2n> z)KnBHD5!$8ugx6L8M9vj%nM0+eAqS}!c4g$T$2bFEl~@e+9iBLvu`N59-9Po5U0!P zIC-I!p{S4_5rq&kQ}Aszo24?qiIXZ_B@6uL^FtLsw9CbwG!ktA^04AV zx)pD=*d%&tpgU=P4+7tt>FY2;-c%LDgGF# zN*!X$y5aXY<*vq`m|A9=;fTG=ZJgy(c01T_SV01n6R`|%O$fok2#Fov058m*vt{0H z`SFW-jjd@<_wTJ2$H21Y_&FMZ0B^!T<+9oU3jqZh^mRhw<7mYEWo09qiK%(-B8I95 znr7=sYUR?4$}alNi7D*5#lgPRVfXMNGntvmRJURV(BqnJsW{i?F0kM?IQXe$&t1Yc z7lpD+G4c>2A0n_VO>qlgAz)MQerdEb-$y0Xx2uLs!~%fB$MdtO(E4`txs)2GV|v ze(QPRbGn_;vQYS`DIOm*Q40LY*ww5}+kT{X$M@d%8PB~=j`w+PQbJH+3*fcyk$t}L zTfD73YVZ_z`*78BW-`x3((B80IEP<+t$iJXO{GtHyh)HPELS6#*f4U1g+TcW{dVHB zN$G6zQZV^U7MI`%)k#pl$!t0gN3Uuil|a7w9E*awJC3(UIZcfOVX?Lsh{9+QP7^O0e*rABQbZ8l`_J|z+2Lu%{cN5S@NPqZmt$Fp^pn`L>Vc;P2RR{ zuM>C}UJrmLfiR^E2wx)>cz#$7(7agCvf3vXTN$`#(E z23<@a$3h8K;i(C}BuPOv!`V6t+ERh0^)FlKIfIS=oF65%RhDPg7E|NEL98wT`Qofk zSbrJpsLyFXjd^KxKk|74k`P(Ljy@Ii+hE0es^{@LG~?aXQ|wLUD?(8@^(*~*`1}4# zv1iHCME0Rj=-{Udlfdyy;8=~zuM+NGdyJcs73e4Eaw$^MKKyyTj4DW)nW=}Cj3kll z(m9CY3MTXfKo_GBU=}xJi(Z-uTrOiQW*Oco{Z8hd9^N1yUr~TB!GUk*o?vE-l5d2{ z_4e0845&z40gEMR>P=Byg4szqSlEm(ed!a?%r!#phc6Qq12^7>Jl&y1Dve}3@-7rp zK~Fy4VP~B%&JyLDL*rH|riS+fng+j6Pk!yVk@_C!^~tuuW04uXetD})MdzJ@?-oGJN6s(HvgXsV?`Zy6>qd+Vl%FPEYBzE3!{6^e>#lcS zTGU(hlp{DbsfY2{dwN2TNKTtz_b@uaak^#CnN+cODpjU`_Mk0w_}ZO^@Qem#2w{WaNy$^4*W_zVD0NbsK~8>ElPMnX`Ymr_(x zi29#Y0w2>(dF+Hq4-HiRg?q^6Nl^P8gZK;NQBu-A%i71F@r=u3BzQn z{!r&dY?Nc5sbL7@qgMjiebz*mC>Qa)(h;Uno?N5pgOz8GTT z?>}%v?P2xG^6h!T%jG~3_cmNu$<}iHy(wF>!~IWs@5wyWH{pePvcK20+`QYrA?nqJ%-lKe?X2v02l-Xs zxTlmelpnt6guuV*8}Jh%z+ZEJd{p`$!atZm{$1-2kNnNO?zb%Q5&dh*kAF@3x7OdC z^nS~}e}eLx0_1;+()=eVzbQff8s!&7$M10Q5&icP{gEQ%uW^2ng!~S~A1(0jIR8o+ z^4CcJnj`H$LHZ+w$Y109YmSot1m|BVMgAJ;Uvo6`CrE#!82M|QUnC>H1LUXwyN>=Z z%8|c={ev~*k9-=x=oEejkq@wcjvF5oB>#Ac|DpLuiiTf&8^1%~hxg|P1Статус: #{orders.status_field} -Пользователь: #{orders.parent_id_field} +Пользователь: #{orders.user_id_field} Адрес доставки: #{orders.address_field} @@ -85,15 +85,16 @@ messages.update(orders.messages_order_status) messages.update(messages_notification) messages.update(cur_messages) -def GetCurItemsTemplate(a_Bot, a_TableName, a_StatusFieldName): +def GetCurItemsTemplate(a_Bot, a_TableName, a_StatusFieldName, a_ParentIDFieldName): def GetBDItems(a_Message, a_UserGroups, a_ParentID): - request = f'SELECT * FROM {a_TableName} WHERE {a_StatusFieldName} != ?' - return a_Bot.SQLRequest(request, param = ([str(orders.OrderStatus.FINISH)])) + request = f'SELECT * FROM {a_TableName} WHERE {a_ParentIDFieldName} = ? AND {a_StatusFieldName} != ?' + return a_Bot.SQLRequest(request, param = ([a_ParentID, str(orders.OrderStatus.FINISH)])) return GetBDItems -def GetBDItemsForUserTemplate(a_Bot, a_TableName): +def GetBDItemsForUserTemplate(a_Bot, a_TableName, a_ParentIDFieldName): def GetBDItems(a_Message, a_UserGroups, a_ParentID): - return bd_item.GetAllItemsTemplate(a_Bot, a_TableName)() + request = f'SELECT * FROM {a_TableName} WHERE {a_ParentIDFieldName} = ?' + return a_Bot.SQLRequest(request, param = ([a_ParentID])) return GetBDItems class DBItemForUserSelectSource(bd_item_select.DBItemSelectSource): @@ -103,19 +104,18 @@ class DBItemForUserSelectSource(bd_item_select.DBItemSelectSource): def GetItemsFunc(self): if self.m_OnlyCurrent: - return GetCurItemsTemplate(self.m_Bot, self.m_TableName, orders.status_field) - return GetBDItemsForUserTemplate(self.m_Bot, self.m_TableName) - - def IsFirst(self): - return True + return GetCurItemsTemplate(self.m_Bot, self.m_TableName, orders.status_field, self.m_ParentIDFieldName) + return GetBDItemsForUserTemplate(self.m_Bot, self.m_TableName, self.m_ParentIDFieldName) class ModuleAllOrders(orders.ModuleOrders): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetInitBDCommands(self): # уже сделано в ModuleUserOrders - return [] + return [ + access_utils.GetAccessForModuleRequest(self.GetName(), self.m_InitAccess, self.m_DefInitAccess), + ] def GetName(self): return module_name @@ -134,6 +134,7 @@ class ModuleAllOrders(orders.ModuleOrders): return n + ":" + str(a_Item[parent_field_id]), k, a async def OnChangeField(self, a_Field, a_ItemID, a_ItemData, a_EditUserID): + super().OnChangeField(a_Field, a_ItemID, a_ItemData, a_EditUserID) if a_Field.m_Destiny == bd_table.TableFieldDestiny.STATUS: key_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY) item = bd_item.GetBDItemsTemplate(self.m_Bot, self.m_Table.GetName(), key_field)(a_ItemID) @@ -142,10 +143,10 @@ class ModuleAllOrders(orders.ModuleOrders): return item = item[0] - parent_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + user_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_ID) status_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.STATUS) - print('OnChangeField', item, parent_field_id, status_field_id) - owner_id = item[parent_field_id] + print('OnChangeField', item, user_field_id, status_field_id) + owner_id = item[user_field_id] new_status = item[status_field_id] msg = self.GetMessage(mod_table_operate.NotificationMessage(new_status)) if not msg: diff --git a/bot_modules/authorize.py b/bot_modules/authorize.py new file mode 100644 index 0000000..02e4763 --- /dev/null +++ b/bot_modules/authorize.py @@ -0,0 +1,397 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Авторизация или регистрация в кооперативе или другой организации + +from bot_sys import bot_bd, keyboard, user_access, bd_table, bot_subscribes, config +from bot_modules import mod_table_operate, mod_simple_message, users_groups_agregator, groups_utils +from template import docs_message, bd_item, bd_item_select + +from enum import Enum +from enum import auto +# --------------------------------------------------------- +# БД +module_name = 'authorize' + +table_name = module_name +user_id_field = 'userID' +user_name_field = 'userName' +user_family_name_field = 'userFamilyName' +user_middle_name_field = 'userMiddleName' +user_birthday_field = 'userBirthday' +user_address_field = 'userAddress' +user_contacts_field = 'userContacts' +user_confirm_field = 'userConfirm' +user_auth_docs_field = 'authDocs' +user_photo_pay_field = 'photoPay' +access_field = 'authorizeAccess' +create_datetime_field = 'authorizeCreateDateTime' + +user_id_table_field = bd_table.TableField(user_id_field, bd_table.TableFieldDestiny.USER_ID, bd_table.TableFieldType.INT) + +class ConfirmStatus(Enum): + YES = auto() + NO = auto() + +table = bd_table.Table(table_name, [ + user_id_table_field, + bd_table.TableField(user_name_field, bd_table.TableFieldDestiny.USER_NAME, bd_table.TableFieldType.STR), + bd_table.TableField(user_family_name_field, bd_table.TableFieldDestiny.USER_FAMILY_NAME, bd_table.TableFieldType.STR), + bd_table.TableField(user_middle_name_field, bd_table.TableFieldDestiny.USER_MIDDLE_NAME, bd_table.TableFieldType.STR), + bd_table.TableField(user_birthday_field, bd_table.TableFieldDestiny.USER_BIRTHDAY, bd_table.TableFieldType.STR), + bd_table.TableField(user_address_field, bd_table.TableFieldDestiny.USER_ADDRESS, bd_table.TableFieldType.STR), + bd_table.TableField(user_contacts_field, bd_table.TableFieldDestiny.USER_CONTACTS, bd_table.TableFieldType.STR), + bd_table.TableField(user_confirm_field, bd_table.TableFieldDestiny.USER_CONFIRM, bd_table.TableFieldType.ENUM, a_Enum = ConfirmStatus), + bd_table.TableField(user_auth_docs_field, bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS, bd_table.TableFieldType.PHOTO), + bd_table.TableField(user_photo_pay_field, bd_table.TableFieldDestiny.PHOTO_PAY, bd_table.TableFieldType.PHOTO), + bd_table.TableField(access_field, bd_table.TableFieldDestiny.ACCESS, bd_table.TableFieldType.STR), + bd_table.TableField(create_datetime_field, bd_table.TableFieldDestiny.CREATE_DATE, bd_table.TableFieldType.STR), + ] + , + [ + [user_id_table_field], + ] + ) + +init_access = f'{user_access.user_access_group_new}=vea' +def_init_access = f'{user_access.user_access_group_new}=a' + +def GetAuthorizeItem(a_Bot, a_UserID): + items = bd_item.GetBDItemsTemplate(a_Bot, table_name, user_id_field)(a_UserID) + if len(items) == 1: + return items[0] + return None + +# --------------------------------------------------------- +# Сообщения и кнопки + +class ButtonNames(Enum): + LIST_AUTH_DOCS = auto() + +button_names = { + mod_simple_message.ButtonNames.START: "🔑 Авторизация", + mod_table_operate.ButtonNames.LIST: "≣ Список авторизаций пользователей", + mod_table_operate.ButtonNames.ADD: "📨 Заявка на вступление", + ButtonNames.LIST_AUTH_DOCS: "📨 Регистрационные документы", + mod_table_operate.ButtonNames.EDIT: "🛠 Редактировать свои данные", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_ID): "☐ Изменить id пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_NAME): "☐ Изменить имя пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_FAMILY_NAME): "☐ Изменить фамилию пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_MIDDLE_NAME): "☐ Изменить отчество пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_BIRTHDAY): "☐ Изменить дату рождения пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_ADDRESS): "☐ Изменить адрес пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_CONTACTS): "☐ Изменить контакты пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_CONFIRM): "☐ Изменить подтверждение пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.USER_ID): "☐ Изменить id пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.ACCESS): "✋ Доступ к авторизации пользователя", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS): "☐ Загрузить подписанные документы", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.PHOTO_PAY): "☐ Оплатить членский взнос", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.ACCESS): "✋ Доступ к авторизации пользователя", + mod_table_operate.ButtonNames.DEL: "❌ Удалить авторизацию пользователя", + mod_table_operate.EnumButton(ConfirmStatus.YES): "Да, все данные верны", + mod_table_operate.EnumButton(ConfirmStatus.NO): "Нет, данные не верны", +} + +class Messages(Enum): + LIST_AUTH_DOCS = auto() + LIST_AUTH_DOCS_ERROR = auto() + +messages = { + mod_simple_message.Messages.START: f''' +{button_names[mod_simple_message.ButtonNames.START]} + +''', + Messages.LIST_AUTH_DOCS: ''' +ваши регистрационные документы: +''', + Messages.LIST_AUTH_DOCS_ERROR: ''' +Ошибка получения документов. Обратитесь в техподдержку. +''', + mod_table_operate.Messages.SELECT: ''' +Пожалуйста, выберите пользователя: +''', + mod_table_operate.Messages.ERROR_FIND: ''' +❌ Ошибка, пользователь не найден +''', + mod_table_operate.Messages.OPEN: f''' +Пользователь: #{user_id_field} + +Имя: #{user_name_field} +Фамилия: #{user_family_name_field} +Отчество: #{user_middle_name_field} +Дата рождения: #{user_birthday_field} +Адрес: #{user_address_field} +Контакты: #{user_contacts_field} +Подтверждение авторизации: #{user_confirm_field} + +Время создания: #{create_datetime_field} +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_NAME): ''' +Авторизация. Шаг №1 + +Введите своё имя: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_FAMILY_NAME): ''' +Авторизация. Шаг №2 + +Введите свою фамилию: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_MIDDLE_NAME): ''' +Авторизация. Шаг №3 + +Введите своё отчество: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_BIRTHDAY): ''' +Авторизация. Шаг №4 + +Введите свою дату рождения в формате ДД.ММ.ГГГГ: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_ADDRESS): ''' +Авторизация. Шаг №5 + +Введите свой домашний адрес: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_CONTACTS): ''' +Авторизация. Шаг №6 + +Введите свои контакты: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.USER_CONFIRM): f''' +Авторизация. Шаг №7 + +Имя: #{user_name_field} +Фамилия: #{user_family_name_field} +Отчество: #{user_middle_name_field} +Дата рождения: #{user_birthday_field} +Адрес: #{user_address_field} +Контакты: #{user_contacts_field} +Подтверждение авторизации: #{user_confirm_field} + +Подтвердите свои данные: +''', + + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Вы успешно зарегистрированы! Посмотрите документы и отправьте фотографии подписанных документов''', + mod_table_operate.Messages.START_EDIT: ''' +Пожалуйста, выберите действие: +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' +Выберите пользователя, у которого вы хотите отредактировать данные. +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_NAME): f''' +Текущее имя пользователя: +#{user_name_field} + +Введите новое имя пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_FAMILY_NAME): f''' +Текущая фамилия пользователя: +#{user_family_name_field} + +Введите новую фамилию пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_MIDDLE_NAME): f''' +Текущее отчество пользователя: +#{user_middle_name_field} + +Введите новое отчество пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_BIRTHDAY): f''' +Текущая дата рождения пользователя: +#{user_birthday_field} + +Введите новую дату рождения пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_ADDRESS): f''' +Текущий адрес пользователя: +#{user_address_field} + +Введите новый адрес пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_CONTACTS): f''' +Текущие контакты пользователя: +#{user_contacts_field} + +Введите новые контакты пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.USER_CONFIRM): f''' +Текущее подтвержение пользователя: +#{user_confirm_field} + +Введите новое подтверждение пользователя: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS): f''' +Загрузите подписанный документ: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.PHOTO_PAY): f''' +Загрузите чек по оплате ЧВ: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.ACCESS): f''' +Текущий доступ к проекту: +#{access_field} + +{user_access.user_access_readme} + +Введите новую строку доступа: +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Данные успешно отредактированы!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' +Выберите пользователя, у которого вы хотите удалить авторизованные данные. +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Данные пользователя успешно удалены!''', +} + +messages_subscribes = { + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Данные по авторизации созданы''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Данные по авторизации отредактированы''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Данные по авторизации удалены''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Данные по авторизации отредактированы #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Данные по авторизации удалены #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Данные по авторизации созданы''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Данные по авторизации отредактированы''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Данные по авторизации удалены''', +} + +messages.update(messages_subscribes) + +messages_confirm_status = { + mod_table_operate.EnumMessageForView(ConfirmStatus.YES): f'''Да, все данные верны''', + mod_table_operate.EnumMessageForView(ConfirmStatus.NO): f'''Нет, данные не верны''', +} + +messages.update(messages_confirm_status) + +class ModuleAuthorize(mod_table_operate.TableOperateModule): + def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, def_init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + + def GetName(self): + return module_name + + def GetAccessForEditKeyboardButtons(self, a_Field): + cur_dict = { + bd_table.TableFieldDestiny.USER_ID: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_NAME: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_FAMILY_NAME: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_MIDDLE_NAME: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_BIRTHDAY: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_ADDRESS: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_CONTACTS: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.USER_CONFIRM: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.ACCESS: user_access.AccessMode.NONE, + bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS: user_access.AccessMode.ADD, + bd_table.TableFieldDestiny.PHOTO_PAY: user_access.AccessMode.ADD, + } + return cur_dict.get(a_Field.m_Destiny, super().GetAccessForEditKeyboardButtons(a_Field)) + + def GetButtonNameAndKeyValueAndAccess(self, a_Item): + key_name_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_ID) + name_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_NAME) + fam_name_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_FAMILY_NAME) + access_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS) + assert key_name_id != None + assert name_field_id != None + assert fam_name_field_id != None + assert access_field_id != None + return \ + a_Item[name_field_id] + ' ' + a_Item[fam_name_field_id] + '(' + str(a_Item[key_name_id]) +')',\ + a_Item[key_name_id],\ + a_Item[access_field_id] + + async def OnChangeField(self, a_Field, a_ItemID, a_ItemData, a_EditUserID): + super().OnChangeField(a_Field, a_ItemID, a_ItemData, a_EditUserID) + user_id_field_name = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.USER_ID) + user_id = a_ItemData[user_id_field_name] + user_confirm_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_CONFIRM) + auth_docs_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS) + pay_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.PHOTO_PAY) + item = GetAuthorizeItem(self.m_Bot, user_id) + if item and item[user_confirm_field_id] != '' and item[auth_docs_field_id] != '' and item[pay_field_id] != '': + users_groups_agregator.AddUserInGroup(self.m_Bot, user_id, user_access.user_access_group_auth_users) + + def GetStartButtons(self, a_Message, a_UserGroups): + user_id = str(a_Message.from_user.id) + item = GetAuthorizeItem(self.m_Bot, user_id) + user_confirm_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.USER_CONFIRM) + + cur_buttons = [] + + if item and item[user_confirm_field_id] == self.GetMessage(mod_table_operate.EnumMessageForView(ConfirmStatus.YES)).GetDesc(): + cur_buttons += [[ButtonNames.LIST_AUTH_DOCS, user_access.AccessMode.VIEW]] + cur_buttons += [[mod_table_operate.EditButton(bd_table.TableFieldDestiny.AUTH_PHOTO_DOCS), user_access.AccessMode.VIEW]] + cur_buttons += [[mod_table_operate.EditButton(bd_table.TableFieldDestiny.PHOTO_PAY), user_access.AccessMode.VIEW]] + else: + cur_buttons += [[mod_table_operate.ButtonNames.ADD, user_access.AccessMode.ADD]] + + return cur_buttons + [ + [mod_table_operate.ButtonNames.LIST, user_access.AccessMode.VIEW], + [mod_table_operate.ButtonNames.DEL, user_access.AccessMode.DELETE], + [mod_table_operate.ButtonNames.EDIT, user_access.AccessMode.EDIT], + ] + + def RegisterHandlers(self): + super().RegisterHandlers() + + def GetFilesFunc(a_user_id): + files = GetAuthDocs() + cur_dict = GetReplaceDictFunc(self.m_Bot, a_user_id) + result = {} + for f in files: + result.update({f: cur_dict}) + + return result + + button_name = self.GetButton(ButtonNames.LIST_AUTH_DOCS) + if button_name: + self.m_Bot.RegisterMessageHandler( + docs_message.DocFilesTemplate( + self.m_Bot, + GetFilesFunc, + self.GetMessage(Messages.LIST_AUTH_DOCS), + self.m_GetAccessFunc, + self.m_GetStartKeyboardButtonsFunc, + None, + self.GetMessage(Messages.LIST_AUTH_DOCS_ERROR), + access_mode = user_access.AccessMode.VIEW + ), + bd_item.GetCheckForTextFunc(button_name) + ) + + def AddBDItemFunc(self, a_ItemData, a_UserID): + a_ItemData[user_id_field] = a_UserID + a_ItemData[user_auth_docs_field] = '' + a_ItemData[user_photo_pay_field] = '' + result = super().AddBDItemFunc(a_ItemData, a_UserID) + return result + + def GetKeyFieldDestiny(self): + return bd_table.TableFieldDestiny.USER_ID + + def GetInitBDCommands(self): + return super(). GetInitBDCommands() + [ + groups_utils.CreateGroupRequest(user_access.user_access_group_auth_users) + ] + +def GetReplaceDictFunc(a_Bot, a_user_id): + item = GetAuthorizeItem(a_Bot, a_user_id) + if not item: + return None + result = {} + i = 0 + for f in table.GetFields(): + result.update({str(f.m_Destiny): str(item[i])}) + i += 1 + print(result) + return result + +auth_docs_file_name = 'config_auth_docs' + +g_auth_docs = [] + +def GetAuthDocs(): + global g_auth_docs + if len(g_auth_docs) == 0: + root_ids = config.GetAllLinesFromFile(auth_docs_file_name) + for i in root_ids: + g_auth_docs += [config.ClearReadLine(i)] + + return g_auth_docs diff --git a/bot_modules/backup.py b/bot_modules/backup.py index cf294a2..dc7b989 100644 --- a/bot_modules/backup.py +++ b/bot_modules/backup.py @@ -48,7 +48,7 @@ init_access = f'{user_access.user_access_group_new}=-' class ModuleBackup(mod_simple_message.SimpleMessageModule): def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(messages, button_names, init_access, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) self.m_BackupBDButtonName = self.CreateButton('backup bd', backup_bd_button_name) self.m_BackupBDMessage = self.CreateMessage('backup bd', backup_bd_message) diff --git a/bot_modules/bd_version.py b/bot_modules/bd_version.py new file mode 100644 index 0000000..2d5eff5 --- /dev/null +++ b/bot_modules/bd_version.py @@ -0,0 +1,51 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Версия БД +# Этот модуль нужен для того, чтобы проводить миграции на новую версию. Он записывает в БД номер текущей версии. + + +from bot_sys import bot_bd, keyboard, user_access, bd_table, bot_subscribes +from bot_modules import mod_table_operate, mod_simple_message + +# --------------------------------------------------------- +# БД +module_name = 'bd_version' + +table_name = module_name +base_version_number_field = 'baseVersionNumber' +sub_version_number_field = 'subVersionNumber' + +table_base_version_number_field = bd_table.TableField(base_version_number_field, bd_table.TableFieldDestiny.VERSION_NUMBER, bd_table.TableFieldType.INT) +table_sub_version_number_field = bd_table.TableField(sub_version_number_field, bd_table.TableFieldDestiny.SUB_VERSION_NUMBER, bd_table.TableFieldType.INT) + +table = bd_table.Table(table_name, [ + table_base_version_number_field, + table_sub_version_number_field, + ], + [ + [table_base_version_number_field, table_sub_version_number_field], + ]) + +init_access = f'{user_access.user_access_group_new}=-' + +# --------------------------------------------------------- +# Сообщения и кнопки + +button_names = { +} + +messages = { +} + +class ModuleBDVersion(mod_table_operate.TableOperateModule): + def __init__(self, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(table, messages, button_names, None, None, init_access, init_access, None, None, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + + def GetName(self): + return module_name + + def GetInitBDCommands(self): + return super(). GetInitBDCommands() + [ + f"INSERT OR IGNORE INTO {table_name} ({base_version_number_field}, {sub_version_number_field}) VALUES ('{1}', '{1}');" + ] diff --git a/bot_modules/buttons.py b/bot_modules/buttons.py index 63e77fa..09dbfda 100644 --- a/bot_modules/buttons.py +++ b/bot_modules/buttons.py @@ -128,7 +128,7 @@ messages = { class ModuleButtons(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/comments.py b/bot_modules/comments.py index 953169f..6f6be15 100644 --- a/bot_modules/comments.py +++ b/bot_modules/comments.py @@ -119,18 +119,21 @@ messages = { } messages_subscribes = { - mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ADD):f'''Комментарий создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Комментарий создан''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Комментарий отредактирован''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Комментарий удалён''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Комментарий отредактирован #item_id''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Комментарий удалён #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Комментарий создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Комментарий отредактирован''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Комментарий удалён''', } messages.update(messages_subscribes) class ModuleComments(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/groups.py b/bot_modules/groups.py index c82485c..4e10654 100644 --- a/bot_modules/groups.py +++ b/bot_modules/groups.py @@ -125,12 +125,12 @@ messages = { class ModuleGroups(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name def GetInitBDCommands(self): return super(). GetInitBDCommands() + [ - f"INSERT OR IGNORE INTO {table_name} ({name_field}, {access_field}, {create_datetime_field}) VALUES ('{user_access.user_access_group_new}', '{user_access.user_access_group_new}=-', {bot_bd.GetBDDateTimeNow()});" + groups_utils.CreateGroupRequest(user_access.user_access_group_new) ] diff --git a/bot_modules/groups_utils.py b/bot_modules/groups_utils.py index 1bc67a0..27b2bbe 100644 --- a/bot_modules/groups_utils.py +++ b/bot_modules/groups_utils.py @@ -3,7 +3,7 @@ # Группы пользователей -from bot_sys import user_access +from bot_sys import user_access, bot_bd table_name = 'user_groups' key_name = 'groupID' @@ -28,3 +28,7 @@ def GetUserGroupData(a_Bot, a_UserID): if len(i) > 0: groups += [i[0]] return user_access.UserGroups(a_UserID, groups) + +def CreateGroupRequest(a_GroupName): + return f"INSERT OR IGNORE INTO {table_name} ({name_field}, {access_field}, {create_datetime_field}) VALUES ('{a_GroupName}', '{user_access.user_access_group_new}=-', {bot_bd.GetBDDateTimeNow()});" + diff --git a/bot_modules/languages.py b/bot_modules/languages.py index 06d0835..b3022fb 100644 --- a/bot_modules/languages.py +++ b/bot_modules/languages.py @@ -126,7 +126,7 @@ messages = { class ModuleLanguages(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) self.m_LanguageIDs = {} def GetName(self): diff --git a/bot_modules/messages.py b/bot_modules/messages.py index 310b043..27ca51f 100644 --- a/bot_modules/messages.py +++ b/bot_modules/messages.py @@ -128,7 +128,7 @@ messages = { class ModuleMessages(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/mod_simple_message.py b/bot_modules/mod_simple_message.py index 0221977..8f5e9a3 100644 --- a/bot_modules/mod_simple_message.py +++ b/bot_modules/mod_simple_message.py @@ -17,9 +17,10 @@ class Messages(Enum): START = auto() class SimpleMessageModule(mod_interface.IModule): - def __init__(self, a_Messages, a_Buttons, a_InitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + def __init__(self, a_Messages, a_Buttons, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): self.m_ChildModuleNameList = a_ChildModuleNameList self.m_InitAccess = a_InitAccess + self.m_DefInitAccess = a_DefInitAccess self.m_Bot = a_Bot self.m_ModuleAgregator = a_ModuleAgregator self.m_BotMessages = a_BotMessages @@ -84,6 +85,8 @@ class SimpleMessageModule(mod_interface.IModule): def GetButtons(self, a_ModNameList): buttons = [] + if not a_ModNameList: + return buttons for n in a_ModNameList: m = self.m_ModuleAgregator.GetModule(n) b = m.GetModuleButtons() @@ -97,7 +100,7 @@ class SimpleMessageModule(mod_interface.IModule): def GetInitBDCommands(self): return [ - access_utils.GetAccessForModuleRequest(self.GetName(), self.m_InitAccess, self.m_InitAccess), + access_utils.GetAccessForModuleRequest(self.GetName(), self.m_InitAccess, self.m_DefInitAccess), ] def GetAccess(self): diff --git a/bot_modules/mod_table_operate.py b/bot_modules/mod_table_operate.py index acff162..4188812 100644 --- a/bot_modules/mod_table_operate.py +++ b/bot_modules/mod_table_operate.py @@ -51,6 +51,12 @@ class Messages(Enum): SELECT_TO_DELETE = auto() SUCCESS_DELETE = auto() +def GetCurItem(a_Bot, a_TableName, a_KeyName, a_KeyValue): + items = bd_item.GetBDItemsTemplate(a_Bot, a_TableName, a_KeyName)(a_KeyValue) + if len(items) == 1: + return items[0] + return None + create_fsm_create_cmd = ''' class FSMCreate{a_ModName}(StatesGroup): {items} @@ -83,8 +89,8 @@ def MakeFSMForEdit(a_ModName, a_FieldName): return _locals['fsm'] class TableOperateModule(mod_simple_message.SimpleMessageModule): - def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(a_Messages, a_Buttons, a_InitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(a_Messages, a_Buttons, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) self.m_Table = a_Table self.m_EditModuleNameList = a_EditModuleNameList self.m_ChildModName = a_ChildModName @@ -99,8 +105,8 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): return self.GetButtonNameAndKeyValueAndAccess(a_Item) self.m_GetButtonNameAndKeyValueAndAccessFunc = GetButtonNameAndKeyValueAndAccess - async def PreDelete(a_CallbackQuery, a_Item): - return await self.PreDelete(a_CallbackQuery, a_Item) + async def PreDelete(a_CallbackQuery, a_Item, a_None, table_name = self.m_Table.GetName()): + return await self.PreDelete(a_CallbackQuery, a_Item, a_None) self.m_PreDeleteFunc = PreDelete async def PostDelete(a_CallbackQuery, a_ItemID): @@ -116,23 +122,33 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): self.m_Table.GetInitTableRequest(), ] + super().GetInitBDCommands() + def GetStartButtons(self, a_Message, a_UserGroups): + return [ + [ButtonNames.LIST, user_access.AccessMode.VIEW], + [ButtonNames.ADD, user_access.AccessMode.ADD], + [ButtonNames.DEL, user_access.AccessMode.DELETE], + [ButtonNames.EDIT, user_access.AccessMode.EDIT], + ] + def GetStartKeyboardButtons(self, a_Message, a_UserGroups): mod_buttons = super().GetStartKeyboardButtons(a_Message, a_UserGroups) - cur_buttons = [ - keyboard.ButtonWithAccess(self.GetButton(ButtonNames.LIST), user_access.AccessMode.VIEW, self.GetAccess()), - keyboard.ButtonWithAccess(self.GetButton(ButtonNames.ADD), user_access.AccessMode.ADD, self.GetAccess()), - keyboard.ButtonWithAccess(self.GetButton(ButtonNames.DEL), user_access.AccessMode.DELETE, self.GetAccess()), - keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT), user_access.AccessMode.EDIT, self.GetAccess()), - ] + cur_buttons = [] + for b in self.GetStartButtons(a_Message, a_UserGroups): + bn = b[0] + ba = b[1] + cur_buttons += [keyboard.ButtonWithAccess(self.GetButton(bn), ba, self.GetAccess())] return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) + def GetAccessForEditKeyboardButtons(self, a_Field): + if a_Field.m_Destiny == bd_table.TableFieldDestiny.ACCESS or a_Field.m_Destiny == bd_table.TableFieldDestiny.DEFAULT_ACCESS: + return user_access.AccessMode.ACCEES_EDIT + return user_access.AccessMode.EDIT + def GetEditKeyboardButtons(self, a_Message, a_UserGroups): mod_buttons = keyboard.MakeButtons(self.m_Bot, self.GetButtons(self.m_EditModuleNameList), a_UserGroups) cur_buttons = [] for f in self.m_Table.GetFields(): - access = user_access.AccessMode.EDIT - if f.m_Destiny == bd_table.TableFieldDestiny.ACCESS or f.m_Destiny == bd_table.TableFieldDestiny.DEFAULT_ACCESS: - access = user_access.AccessMode.ACCEES_EDIT + access = self.GetAccessForEditKeyboardButtons(f) cur_buttons += [keyboard.ButtonWithAccess(self.GetButton(EditButton(f.m_Destiny)), access, self.GetAccess()),] return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) @@ -154,7 +170,7 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): return keyboard.MakeInlineKeyboardButtons(self.m_Bot, cur_buttons, a_UserGroups) def GetButtonNameAndKeyValueAndAccess(self, a_Item): - key_name_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.KEY) + key_name_id = self.GetKeyFieldID() name_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.NAME) access_field_id = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS) assert key_name_id != None @@ -182,13 +198,34 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): a_Msg.UpdatePhotoID(','.join(photos)) return a_Msg + def UpdateMessageByDict(self, a_Msg, a_Lang, a_ItemDict, a_EnablePhoto = False): + a_Msg.UpdateDesc(self.m_Table.ReplaceAllFieldTagsByDict(a_Msg.GetDesc(), a_ItemDict)) + photos = [] + for f in self.m_Table.GetFields(): + if f.m_Type == bd_table.TableFieldType.ENUM: + for s in f.m_Enum: + msg = self.GetMessage(EnumMessageForView(s)) + if msg: + a_Msg.UpdateDesc(a_Msg.GetDesc().replace(str(s), str(msg.GetMessageForLang(a_Lang).StaticCopy()))) + elif f.m_Type == bd_table.TableFieldType.PHOTO: + if f.m_Name in a_ItemDict: + photos += [str(a_ItemDict[f.m_Name])] + if a_EnablePhoto: + a_Msg.UpdatePhotoID(','.join(photos)) + return a_Msg + def ShowMessageTemplate(self, a_Message, Inline_keyboard_template_func = None, a_EnablePhoto = False): - async def ShowMessage(a_CallbackQuery, a_Item): + async def ShowMessage(a_CallbackQuery, a_Item, a_ItemDict, table_name = self.m_Table.GetName()): msg = a_Message.StaticCopy() - # TODO: добавить поддержку языка в a_MessageName + # TODO: добавить поддержку языков в a_MessageName Inline_keyboard_func = None item_access = None - if a_Item: + if a_ItemDict: + lang = str(a_CallbackQuery.from_user.language_code) + msg = msg.GetMessageForLang(lang).StaticCopy() + msg = self.UpdateMessageByDict(msg, lang, a_ItemDict, a_EnablePhoto = a_EnablePhoto) + + if a_Item and self.m_Table.GetName() == table_name: if len(a_Item) < self.m_Table.GetFieldsCount() - 1: # Для проектов это нужно. Там на 1 меньше поле. TODO разделить отправку сообщений item_access и Inline_keyboard_func return simple_message.WorkFuncResult(self.GetMessage(Messages.ERROR_FIND)) elif len(a_Item) == self.m_Table.GetFieldsCount(): @@ -197,14 +234,14 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): msg = self.UpdateMessage(msg, lang, a_Item, a_EnablePhoto = a_EnablePhoto) item_access = a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)] if Inline_keyboard_template_func: - Inline_keyboard_func = Inline_keyboard_template_func(a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.KEY)]) + Inline_keyboard_func = Inline_keyboard_template_func(a_Item[self.GetKeyFieldID()]) return simple_message.WorkFuncResult(msg, item_access = item_access, Inline_keyboard_func = Inline_keyboard_func) return ShowMessage - async def PreDelete(self, a_CallbackQuery, a_Item): + async def PreDelete(self, a_CallbackQuery, a_Item, a_None): if len(a_Item) < self.m_Table.GetFieldsCount(): - return simple_message.WorkFuncResult(error_find_proj_message) + return simple_message.WorkFuncResult(self.GetMessage(Messages.ERROR_FIND)) access = a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)] return simple_message.WorkFuncResult(self.GetMessage(Messages.SUCCESS_DELETE), None, item_access = access) @@ -222,6 +259,18 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): item_id = a_ItemID await self.SendSubscribe(subscribe_type, item_id, user_id) + table_name = self.m_Table.GetName() + key_name = self.GetKeyFieldName() + + cur_item = GetCurItem(self.m_Bot, table_name, key_name, a_ItemID) + print(cur_item) + + parent_id_field_index = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + if parent_id_field_index and cur_item and cur_item[parent_id_field_index]: + subscribe_type = bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT + item_id = cur_item[parent_id_field_index] + await self.SendSubscribe(subscribe_type, item_id, user_id) + return simple_message.WorkFuncResult(self.GetMessage(Messages.SUCCESS_DELETE)) async def AddBDItemFunc(self, a_ItemData, a_UserID): @@ -265,10 +314,15 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): else: self.m_Log.Success(f'Пользователь {a_UserID}. Добавлена запись в таблицу {request} {param}.') - subscribe_type = bot_subscribes.SubscribeType.ADD + subscribe_type = bot_subscribes.SubscribeType.ANY_ITEM_ADD item_id = -1 await self.SendSubscribe(subscribe_type, item_id, a_UserID) + if parent_id_field and a_ItemData[parent_id_field]: + subscribe_type = bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT + item_id = a_ItemData[parent_id_field] + await self.SendSubscribe(subscribe_type, item_id, a_UserID) + return res, error async def SendSubscribe(self, a_Type, a_ItemID, a_OwnerUserID): @@ -286,7 +340,10 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): a_Message = None user_groups = None parse_mode = None - await simple_message.SendMessage(self.m_Bot, a_BotMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_UserID, a_Message, user_groups, parse_mode=parse_mode) + try: + await simple_message.SendMessage(self.m_Bot, a_BotMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_UserID, a_Message, user_groups, parse_mode=parse_mode) + except: + return def SelectSourceTemplate(self, a_PrevPrefix, a_ButtonName): parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) @@ -309,12 +366,12 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): return a_Prefix - def AdditionalKeyboardForEditTemplate(self, a_Field): + def AdditionalKeyboardForEditTemplate(self, a_Field, user_access = user_access.AccessMode.EDIT): if a_Field.m_Type == bd_table.TableFieldType.ENUM: def KeyboardButtons(a_Message, a_UserGroups): cur_buttons = [] for s in a_Field.m_Enum: - cur_buttons += [keyboard.ButtonWithAccess(self.GetButton(EnumButton(s)), user_access.AccessMode.EDIT, self.GetAccess()),] + cur_buttons += [keyboard.ButtonWithAccess(self.GetButton(EnumButton(s)), user_access, self.GetAccess()),] return keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) return KeyboardButtons return None @@ -339,6 +396,18 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): await self.SendSubscribe(subscribe_type, item_id, a_EditUserID) + table_name = self.m_Table.GetName() + key_name = self.GetKeyFieldName() + + cur_item = GetCurItem(self.m_Bot, table_name, key_name, a_ItemID) + print(cur_item) + + parent_id_field_index = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + if parent_id_field_index and cur_item and cur_item[parent_id_field_index]: + subscribe_type = bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT + item_id = cur_item[parent_id_field_index] + await self.SendSubscribe(subscribe_type, item_id, a_EditUserID) + def RegisterEdit(self, a_Field, a_AccessMode = user_access.AccessMode.EDIT): a_ButtonName = self.GetButton(EditButton(a_Field.m_Destiny)) a_EditMessage = self.GetMessage(EditMessage(a_Field.m_Destiny)) @@ -356,12 +425,12 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): return self.OnChange() table_name = self.m_Table.GetName() - key_name = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY) + key_name = self.GetKeyFieldName() edit_keyboard_func = self.m_GetEditKeyboardButtonsFunc GetButtonNameAndKeyValueAndAccess = self.m_GetButtonNameAndKeyValueAndAccessFunc GetAccess = self.m_GetAccessFunc - a_Prefix = self.RegisterSelect(a_ButtonName, a_AccessMode, only_parent = True) + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.VIEW, only_parent = True) bd_item_edit.EditBDItemRegisterHandlers(self.m_Bot, \ self.SelectSourceTemplate(a_Prefix, a_ButtonName), \ @@ -383,9 +452,23 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): ) def GetAddFields(self): + add_destiny = ( + bd_table.TableFieldDestiny.NAME, + bd_table.TableFieldDestiny.DESC, + bd_table.TableFieldDestiny.PHOTO, + bd_table.TableFieldDestiny.SUBSCRIBE_TYPE, + bd_table.TableFieldDestiny.ITEM_ID, + bd_table.TableFieldDestiny.USER_NAME, + bd_table.TableFieldDestiny.USER_FAMILY_NAME, + bd_table.TableFieldDestiny.USER_MIDDLE_NAME, + bd_table.TableFieldDestiny.USER_BIRTHDAY, + bd_table.TableFieldDestiny.USER_ADDRESS, + bd_table.TableFieldDestiny.USER_CONTACTS, + bd_table.TableFieldDestiny.USER_CONFIRM, + ) fields = [] for f in self.m_Table.GetFields(): - if f.m_Destiny in (bd_table.TableFieldDestiny.NAME, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldDestiny.PHOTO, bd_table.TableFieldDestiny.SUBSCRIBE_TYPE, bd_table.TableFieldDestiny.ITEM_ID, ): + if f.m_Destiny in add_destiny: fields += [f] return fields @@ -419,23 +502,32 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): f_id = 0 f = fields[f_id] - keyboard = bd_item.MixKeyboardFuncTemplate(self.AdditionalKeyboardForEditTemplate(f), GetKeyboard(f)) + keyboard = bd_item.MixKeyboardFuncTemplate(self.AdditionalKeyboardForEditTemplate(f, user_access.AccessMode.ADD), GetKeyboard(f)) reg_func(bd_item_add.StartAddBDItemTemplate(self.m_Bot, fsm, getattr(fsm, f'item{f_id}'), self.ShowMessageTemplate(self.GetMessage(CreateMessage(f.m_Destiny))), a_ParentTableName, a_ParentKeyFieldName, a_ParentPrefix, a_AccessFunc, keyboard, a_ButtonFunc, access_mode), a_StartCheckFunc) for i in range(len(fields) - 1): f = fields[i] next_f = fields[i + 1] - keyboard = bd_item.MixKeyboardFuncTemplate(self.AdditionalKeyboardForEditTemplate(next_f), GetKeyboard(next_f)) + keyboard = bd_item.MixKeyboardFuncTemplate(self.AdditionalKeyboardForEditTemplate(next_f, user_access.AccessMode.ADD), GetKeyboard(next_f)) self.m_Bot.RegisterMessageHandler(bd_item_add.NextAddBDItemTemplate(self.m_Bot, fsm, None, a_ParentTableName, a_ParentKeyFieldName, f.m_Name, self.ShowMessageTemplate(self.GetMessage(CreateMessage(next_f.m_Destiny))), None, a_AccessFunc, keyboard, a_ButtonFunc, access_mode, field_type = GetFieldType(f)), content_types = GetContentTypes(f), state = getattr(fsm, f'item{i}')) f_id = len(fields) - 1 f = fields[f_id] self.m_Bot.RegisterMessageHandler(bd_item_add.FinishAddBDItemTemplate(self.m_Bot, fsm, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, f.m_Name, self.ShowMessageTemplate(self.GetMessage(Messages.SUCCESS_CREATE)), None, a_AccessFunc, a_ButtonFunc, access_mode, field_type = GetFieldType(f)), content_types = GetContentTypes(f), state = getattr(fsm, f'item{f_id}')) + def GetKeyFieldDestiny(self): + return bd_table.TableFieldDestiny.KEY + + def GetKeyFieldName(self): + return self.m_Table.GetFieldNameByDestiny(self.GetKeyFieldDestiny()) + + def GetKeyFieldID(self): + return self.m_Table.GetFieldIDByDestiny(self.GetKeyFieldDestiny()) + def RegisterHandlers(self): super().RegisterHandlers() table_name = self.m_Table.GetName() - key_name = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY) + key_name = self.GetKeyFieldName() name_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.NAME) desc_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DESC) photo_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PHOTO) @@ -448,7 +540,7 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): if self.m_ParentModName: parent_mod = self.GetModule(self.m_ParentModName) parent_table_name = parent_mod.m_Table.GetName() - parent_key_name = parent_mod.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY) + parent_key_name = parent_mod.GetKeyFieldName() def GetViewItemInlineKeyboardTemplate(a_ItemID): return self.GetViewItemInlineKeyboardTemplate(a_ItemID) @@ -483,7 +575,7 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): # Удаление a_ButtonName = self.GetButton(ButtonNames.DEL) if a_ButtonName: - a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.DELETE) + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.VIEW) bd_item_delete.DeleteBDItemRegisterHandlers(self.m_Bot, \ a_Prefix, \ table_name, \ @@ -497,7 +589,7 @@ class TableOperateModule(mod_simple_message.SimpleMessageModule): # Добавление a_ButtonName = self.GetButton(ButtonNames.ADD) if a_ButtonName: - a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.ADD, only_parent = True) + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.VIEW, only_parent = True) check_func = bd_item.GetCheckForTextFunc(a_ButtonName) if a_Prefix: diff --git a/bot_modules/needs.py b/bot_modules/needs.py index 0f0bf2f..0bba8ba 100644 --- a/bot_modules/needs.py +++ b/bot_modules/needs.py @@ -120,18 +120,21 @@ messages = { } messages_subscribes = { - mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ADD):f'''Потребность создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Потребность создана''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Потребность отредактирована''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Потребность удалёна''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Потребность отредактирована #item_id''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Потребность удалёна #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Потребность создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Потребность отредактирована''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Потребность удалёна''', } messages.update(messages_subscribes) class ModuleNeeds(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/orders.py b/bot_modules/orders.py index 3559006..1f8ecdb 100644 --- a/bot_modules/orders.py +++ b/bot_modules/orders.py @@ -22,6 +22,7 @@ module_name = 'orders' table_name = module_name key_name = 'orderID' +user_id_field = 'userID' name_field = 'orderName' desc_field = 'orderDesc' photo_field = 'orderPhoto' @@ -30,10 +31,11 @@ status_field = 'orderStatus' address_field = 'orderAddress' access_field = 'orderAccess' create_datetime_field = 'orderCreateDateTime' -parent_id_field = 'userID' +parent_id_field = 'catID' table = bd_table.Table(table_name, [ bd_table.TableField(key_name, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.INT), + bd_table.TableField(user_id_field, bd_table.TableFieldDestiny.USER_ID, bd_table.TableFieldType.INT), bd_table.TableField(name_field, bd_table.TableFieldDestiny.NAME, bd_table.TableFieldType.STR), bd_table.TableField(desc_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), bd_table.TableField(photo_field, bd_table.TableFieldDestiny.PHOTO, bd_table.TableFieldType.PHOTO), @@ -45,7 +47,7 @@ table = bd_table.Table(table_name, [ bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT), ]) -init_access = f'{user_access.user_access_group_new}=vea' +init_access = f'{user_access.user_access_group_auth_users}=vea' # --------------------------------------------------------- # Сообщения и кнопки @@ -134,7 +136,7 @@ messages = { ''', mod_table_operate.EditMessage(bd_table.TableFieldDestiny.ADDRESS): f''' Текущий адрес заказа: -#{desc_field} +#{address_field} Введите новый адрес доставки заказа (укажите, кто, когда и где его сможет забрать): ''', @@ -164,26 +166,31 @@ messages_order_status = { messages.update(messages_order_status) messages_subscribes = { - mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ADD):f'''Заказ создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Заказ создан''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Заказ отредактирован''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Заказ удалён''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Заказ отредактирован #item_id''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Заказ удалён #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Заказ создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Заказ отредактирован''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Заказ удалён''', } messages.update(messages_subscribes) -def GetCurItemsTemplate(a_Bot, a_TableName, a_UserIDFieldName, a_StatusFieldName): +def GetCurItemsTemplate(a_Bot, a_TableName, a_UserIDFieldName, a_ParentIDFieldName, a_StatusFieldName): def GetBDItems(a_Message, a_UserGroups, a_ParentID): user_id = str(a_Message.from_user.id) - request = f'SELECT * FROM {a_TableName} WHERE {a_UserIDFieldName} = ? AND {a_StatusFieldName} != ?' - return a_Bot.SQLRequest(request, param = ([user_id, str(OrderStatus.FINISH)])) + request = f'SELECT * FROM {a_TableName} WHERE {a_ParentIDFieldName} = ? AND {a_UserIDFieldName} = ? AND {a_StatusFieldName} != ?' + return a_Bot.SQLRequest(request, param = ([a_ParentID, user_id, str(OrderStatus.FINISH)])) return GetBDItems -def GetBDItemsForUserTemplate(a_Bot, a_TableName, a_UserIDFieldName): +def GetBDItemsForUserTemplate(a_Bot, a_TableName, a_UserIDFieldName, a_ParentIDFieldName): def GetBDItems(a_Message, a_UserGroups, a_ParentID): user_id = str(a_Message.from_user.id) - return bd_item.GetBDItemsTemplate(a_Bot, a_TableName, a_UserIDFieldName)(user_id) + request = f'SELECT * FROM {a_TableName} WHERE {a_ParentIDFieldName} = ? AND {a_UserIDFieldName} = ?' + print('GetBDItemsForUserTemplate', user_id, request, a_ParentID) + return a_Bot.SQLRequest(request, param = ([a_ParentID, user_id])) return GetBDItems class DBItemForUserSelectSource(bd_item_select.DBItemSelectSource): @@ -193,15 +200,12 @@ class DBItemForUserSelectSource(bd_item_select.DBItemSelectSource): def GetItemsFunc(self): if self.m_OnlyCurrent: - return GetCurItemsTemplate(self.m_Bot, self.m_TableName, self.m_ParentIDFieldName, status_field) - return GetBDItemsForUserTemplate(self.m_Bot, self.m_TableName, self.m_ParentIDFieldName) - - def IsFirst(self): - return True + return GetCurItemsTemplate(self.m_Bot, self.m_TableName, user_id_field, self.m_ParentIDFieldName, status_field) + return GetBDItemsForUserTemplate(self.m_Bot, self.m_TableName, user_id_field, self.m_ParentIDFieldName) class ModuleOrders(mod_table_operate.TableOperateModule): - def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def SelectSourceTemplate(self, a_PrevPrefix, a_ButtonName): parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) @@ -213,7 +217,7 @@ class ModuleOrders(mod_table_operate.TableOperateModule): def AddBDItemFunc(self, a_ItemData, a_UserID): parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) - a_ItemData[parent_id_field] = a_UserID + a_ItemData[user_id_field] = a_UserID a_ItemData[status_field] = str(OrderStatus.NEW) a_ItemData[address_field] = '' a_ItemData[photo_pay_field] = '0' @@ -262,7 +266,7 @@ class ModuleOrders(mod_table_operate.TableOperateModule): class ModuleUserOrders(ModuleOrders): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/orders_cat.py b/bot_modules/orders_cat.py new file mode 100644 index 0000000..0288656 --- /dev/null +++ b/bot_modules/orders_cat.py @@ -0,0 +1,138 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Проекты + +from bot_sys import bot_bd, keyboard, user_access, bd_table, bot_subscribes +from bot_modules import mod_table_operate, mod_simple_message + +# --------------------------------------------------------- +# БД +module_name = 'orders_cat' + +table_name = module_name +key_name = 'catID' +name_field = 'catName' +desc_field = 'catDesc' +photo_field = 'catPhoto' +access_field = 'catAccess' +create_datetime_field = 'catCreateDateTime' + +table = bd_table.Table(table_name, [ + bd_table.TableField(key_name, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.INT), + bd_table.TableField(name_field, bd_table.TableFieldDestiny.NAME, bd_table.TableFieldType.STR), + bd_table.TableField(desc_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), + bd_table.TableField(photo_field, bd_table.TableFieldDestiny.PHOTO, bd_table.TableFieldType.PHOTO), + bd_table.TableField(access_field, bd_table.TableFieldDestiny.ACCESS, bd_table.TableFieldType.STR), + bd_table.TableField(create_datetime_field, bd_table.TableFieldDestiny.CREATE_DATE, bd_table.TableFieldType.STR), + ]) + +init_access = f'{user_access.user_access_group_new}=v' + +# --------------------------------------------------------- +# Сообщения и кнопки + +button_names = { + mod_simple_message.ButtonNames.START: "🟥 Категории", + mod_table_operate.ButtonNames.LIST: "📃 Список категорий", + mod_table_operate.ButtonNames.ADD: "✅ Добавить категорию", + mod_table_operate.ButtonNames.EDIT: "🛠 Редактировать категорию", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.PHOTO): "☐ Изменить изображение в категории", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.NAME): "≂ Изменить название в категории", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.DESC): "𝌴 Изменить описание в категории", + mod_table_operate.EditButton(bd_table.TableFieldDestiny.ACCESS): "✋ Изменить доступ к категории", + mod_table_operate.ButtonNames.DEL: "❌ Удалить категорию", +} + +messages = { + mod_simple_message.Messages.START: f''' +{button_names[mod_simple_message.ButtonNames.START]} + +''', + mod_table_operate.Messages.SELECT: ''' +Пожалуйста, выберите категорию: +''', + mod_table_operate.Messages.ERROR_FIND: ''' +❌ Ошибка, категория не найдена +''', + mod_table_operate.Messages.OPEN: f''' +Категория: #{name_field} + +#{desc_field} + +Время создания: #{create_datetime_field} +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.NAME): ''' +Создание категории. Шаг №1 + +Введите название категории: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.DESC): ''' +Создание категории. Шаг №2 + +Введите описание категории: +''', + mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.PHOTO): ''' +Создание категории. Шаг №3 + +Загрузите обложку для категории (Фото): +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Категория успешно добавлена!''', + mod_table_operate.Messages.START_EDIT: ''' +Пожалуйста, выберите действие: +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' +Выберите проект, который вы хотите отредактировать. +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.PHOTO): ''' +Загрузите новую обложку для категории (Фото): +Она будет отображаться в его описании. +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.NAME): f''' +Текущее название категории: +#{name_field} + +Введите новое название категории: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.DESC): f''' +Текущее описание категории: +#{desc_field} + +Введите новое описание категории: +''', + mod_table_operate.EditMessage(bd_table.TableFieldDestiny.ACCESS): f''' +Текущий доступ к категории: +#{access_field} + +{user_access.user_access_readme} + +Введите новую строку доступа: +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Категория успешно отредактирована!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' +Выберите категорию, которую вы хотите удалить. +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Категория успешно удалёна!''', +} + +messages_subscribes = { + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Категория создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Категория отредактирована''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Категория удалена''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Категория отредактирована #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Категория удалена #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Категория создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Категория отредактирована''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Категория удалена''', +} + +messages.update(messages_subscribes) + +class ModuleOrdersCat(mod_table_operate.TableOperateModule): + def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + + def GetName(self): + return module_name + diff --git a/bot_modules/profile.py b/bot_modules/profile.py index f0c2a67..c584a07 100644 --- a/bot_modules/profile.py +++ b/bot_modules/profile.py @@ -32,7 +32,7 @@ init_access = f'{user_access.user_access_group_new}=+' class ModuleProfile(mod_simple_message.SimpleMessageModule): def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(messages, button_names, init_access, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/projects.py b/bot_modules/projects.py index becbc93..3ed3438 100644 --- a/bot_modules/projects.py +++ b/bot_modules/projects.py @@ -118,18 +118,21 @@ messages = { } messages_subscribes = { - mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ADD):f'''Проект создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Проект создан''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Проект отредактирован''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Проект удалён''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Проект отредактирован #item_id''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Проект удалён #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT):f'''Проект создан''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT):f'''Проект отредактирован''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT):f'''Проект удалён''', } messages.update(messages_subscribes) class ModuleProjects(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/start.py b/bot_modules/start.py index dc55776..58d3c63 100644 --- a/bot_modules/start.py +++ b/bot_modules/start.py @@ -24,7 +24,7 @@ init_access = f'{user_access.user_access_group_all}=+' class ModuleStart(mod_simple_message.SimpleMessageModule): def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(messages, button_names, init_access, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/subscribes.py b/bot_modules/subscribes.py index ae26e3f..3731920 100644 --- a/bot_modules/subscribes.py +++ b/bot_modules/subscribes.py @@ -59,11 +59,14 @@ button_names = { mod_table_operate.EditButton(bd_table.TableFieldDestiny.SUBSCRIBE_TYPE): "𝌴 Изменить тип в моей подписке", mod_table_operate.EditButton(bd_table.TableFieldDestiny.ITEM_ID): "𝌴 Изменить элемент в моей подписке", mod_table_operate.EditButton(bd_table.TableFieldDestiny.ACCESS): "✋ Изменить доступ к моей подписке", - mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ADD): "Добавление элемента", + mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_ADD): "Добавление элемента", mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_DEL): "Удаление какого либо элемента", mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_EDIT): "Редактирование какого либо элемента", mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ITEM_DEL): "Удаление определённого элемента", mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ITEM_EDIT): "Редактирование определённого элемента", + mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT): "Добавление элемента с родителем", + mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT): "Удаление элемента с родителем", + mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT): "Редактирование элемента с родителем", mod_table_operate.ButtonNames.DEL: "❌ Удалить мою подписку", } @@ -102,7 +105,7 @@ messages = { mod_table_operate.CreateMessage(bd_table.TableFieldDestiny.ITEM_ID): ''' Создание подписки. Шаг №3 -Номер элемента, на который нужно подписаться (-1, если элемента нет): +Номер элемента или его родителя, на который нужно подписаться (-1, если элемента нет): ''', mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Подписка успешно добавлена!''', mod_table_operate.Messages.START_EDIT: ''' @@ -143,23 +146,20 @@ messages = { mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Подписка успешно удалёна!''', } +# TODO Возможно это не нужно есть же mod_table_operate.EnumButton(bot_subscribes.SubscribeType.ANY_ITEM_ADD) см. выше messages_subs_type_status = { - mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ADD): f'''Добавление элемента''', + mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_ADD): f'''Добавление элемента''', mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_DEL): f'''Удаление элемента''', mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_EDIT): f'''Редактирование элемента''', mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ITEM_DEL): f'''Удаление конкретного элемента''', mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ITEM_EDIT): f'''Редактирование конкретного элемента''', + mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_ADD_WITH_PARENT): f'''Добавление элемента''', + mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_DEL_WITH_PARENT): f'''Удаление элемента''', + mod_table_operate.EnumMessageForView(bot_subscribes.SubscribeType.ANY_ITEM_EDIT_WITH_PARENT): f'''Редактирование элемента''', } messages.update(messages_subs_type_status) -def GetCurItemsTemplate(a_Bot, a_TableName, a_UserIDFieldName, a_StatusFieldName): - def GetBDItems(a_Message, a_UserGroups, a_ParentID): - user_id = str(a_Message.from_user.id) - request = f'SELECT * FROM {a_TableName} WHERE {a_UserIDFieldName} = ? AND {a_StatusFieldName} != ?' - return a_Bot.SQLRequest(request, param = ([user_id, str(OrderStatus.FINISH)])) - return GetBDItems - def GetBDItemsForUserTemplate(a_Bot, a_TableName, a_UserIDFieldName): def GetBDItems(a_Message, a_UserGroups, a_ParentID): user_id = str(a_Message.from_user.id) @@ -177,8 +177,8 @@ class DBItemForUserSelectSource(bd_item_select.DBItemSelectSource): return True class ModuleSubscribe(mod_table_operate.TableOperateModule): - def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + def __init__(self, a_Table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): + super().__init__(table, a_Messages, a_Buttons, a_ParentModName, a_ChildModName, a_InitAccess, a_DefInitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def SelectSourceTemplate(self, a_PrevPrefix, a_ButtonName): parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) @@ -211,7 +211,7 @@ class ModuleSubscribe(mod_table_operate.TableOperateModule): class ModuleUserSubscribe(ModuleSubscribe): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) self.UpdateSubscribes() def GetName(self): @@ -234,8 +234,8 @@ class ModuleUserSubscribe(ModuleSubscribe): a_ItemID = s[item_id_id_field] a_UserID = s[user_id_id_field] for t in bot_subscribes.SubscribeType: - k = mod_table_operate.EnumMessageForView(t) - m = messages_subs_type_status.get(k, None) + k = mod_table_operate.EnumButton(t) + m = button_names.get(k, None) if m and m == a_Type: a_Type = t break diff --git a/bot_modules/tasks.py b/bot_modules/tasks.py index 8e148b7..23f52a7 100644 --- a/bot_modules/tasks.py +++ b/bot_modules/tasks.py @@ -120,18 +120,21 @@ messages = { } messages_subscribes = { - mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ADD):f'''Задача создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Задача создана''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Задача отредактирована''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Задача удалёна''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_EDIT):f'''Задача отредактирована #item_id''', mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ITEM_DEL):f'''Задача удалёна #item_id''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_ADD):f'''Задача создана''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_EDIT):f'''Задача отредактирована''', + mod_table_operate.SubscribeMessage(bot_subscribes.SubscribeType.ANY_ITEM_DEL):f'''Задача удалёна''', } messages.update(messages_subscribes) class ModuleTasks(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/user_in_groups.py b/bot_modules/user_in_groups.py index f2e7830..3509cad 100644 --- a/bot_modules/user_in_groups.py +++ b/bot_modules/user_in_groups.py @@ -106,7 +106,7 @@ messages = { class ModuleUserInGroups(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/users.py b/bot_modules/users.py index e4feaee..ba92907 100644 --- a/bot_modules/users.py +++ b/bot_modules/users.py @@ -128,7 +128,7 @@ messages = { class ModuleUsers(mod_table_operate.TableOperateModule): def __init__(self, a_ParentModName, a_ChildModName, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(table, messages, button_names, a_ParentModName, a_ChildModName, init_access, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) def GetName(self): return module_name diff --git a/bot_modules/users_groups_agregator.py b/bot_modules/users_groups_agregator.py index 4c4533a..e26b55d 100644 --- a/bot_modules/users_groups_agregator.py +++ b/bot_modules/users_groups_agregator.py @@ -57,7 +57,7 @@ init_access = f'{user_access.user_access_group_new}=-' class ModuleUsersGroupsAgregator(mod_simple_message.SimpleMessageModule): def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log): - super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) + super().__init__(messages, button_names, init_access, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_BotSubscribes, a_Log) self.m_SqlRequestButtonName = self.CreateButton('sql request', sql_request_button_name) self.m_RequestStartMessage = self.CreateMessage('equest start', request_start_message) @@ -99,3 +99,12 @@ class ModuleUsersGroupsAgregator(mod_simple_message.SimpleMessageModule): bd_item.GetCheckForTextFunc(self.m_HelpButtonName) ) +def AddUserInGroup(a_Bot, a_UserID, a_GroupName): + g_id = a_Bot.SQLRequest(f'SELECT {groups.key_name} FROM {groups.table_name} WHERE {groups.name_field} = "{a_GroupName}"'); + if not g_id or len(g_id) != 1 or len(g_id[0]) != 1: + return False + group_id = g_id[0][0] + r = f'INSERT OR IGNORE INTO {user_in_groups.table_name}({user_in_groups.name_field}, {user_in_groups.parent_id_field}) VALUES(?, ?)' + result = a_Bot.SQLRequest(r, commit=True, param = (a_UserID, group_id)) + + diff --git a/bot_sys/bd_table.py b/bot_sys/bd_table.py index 7820abf..25c2981 100644 --- a/bot_sys/bd_table.py +++ b/bot_sys/bd_table.py @@ -36,6 +36,17 @@ class TableFieldDestiny(Enum): ITEM_ID = auto() ADDRESS = auto() OTHER = auto() + VERSION_NUMBER = auto() + SUB_VERSION_NUMBER = auto() + USER_ID = auto() + USER_NAME = auto() # Имя + USER_FAMILY_NAME = auto() # Фамилия + USER_MIDDLE_NAME = auto() # Отчество + USER_BIRTHDAY = auto() # Дата рождения + USER_ADDRESS = auto() # Адресс + USER_CONTACTS = auto() # контакты + USER_CONFIRM = auto() # подтверждение + AUTH_PHOTO_DOCS = auto() class TableField: def __init__(self, a_Name, a_Destiny : TableFieldDestiny, a_Type : TableFieldType, a_Enum = None): @@ -101,6 +112,13 @@ class Table: result = result.replace(f'#{f.m_Name}', str(a_BDItem[i])) return result + def ReplaceAllFieldTagsByDict(self, a_String, a_BDItemDict): + result = a_String + for f in self.m_Fields: + if f.m_Name in a_BDItemDict: + result = result.replace(f'#{f.m_Name}', str(a_BDItemDict[f.m_Name])) + return result + class Status(Enum): NEW = auto() FINISH = auto() diff --git a/bot_sys/bot_bd.py b/bot_sys/bot_bd.py index ec81174..47583b2 100644 --- a/bot_sys/bot_bd.py +++ b/bot_sys/bot_bd.py @@ -9,6 +9,7 @@ from bot_sys import log def GetBDDateTimeNow(): return 'datetime(\'now\')' +# TODO: Удалить что-то из SelectBDTemplate RequestSelectTemplate def SelectBDTemplate(a_Bot, a_TableName): def SelectBD(): return a_Bot.SQLRequest(f'SELECT * FROM {a_TableName}') diff --git a/bot_sys/bot_subscribes.py b/bot_sys/bot_subscribes.py index b37f258..91a3001 100644 --- a/bot_sys/bot_subscribes.py +++ b/bot_sys/bot_subscribes.py @@ -8,11 +8,14 @@ from enum import auto # Тип поля в таблице class SubscribeType(Enum): - ADD = auto() + ANY_ITEM_ADD = auto() ANY_ITEM_DEL = auto() ANY_ITEM_EDIT = auto() ITEM_DEL = auto() ITEM_EDIT = auto() + ANY_ITEM_ADD_WITH_PARENT = auto() + ANY_ITEM_DEL_WITH_PARENT = auto() + ANY_ITEM_EDIT_WITH_PARENT = auto() class BotSubscribes: def __init__(self): @@ -30,8 +33,8 @@ class BotSubscribes: for user_id, su in s.items(): sub_um = su.get(a_ModuleName, None) if sub_um: - t = sub_um.get(str(a_ItemID), None) - if t == a_Type: + i = sub_um.get(str(a_Type), None) + if i == str(a_ItemID): ids.add(user_id) return ids @@ -41,7 +44,7 @@ class BotSubscribes: s[a_UserID] = {} if not s[a_UserID].get(a_ModuleName, None): s[a_UserID][a_ModuleName] = {} - s[a_UserID][a_ModuleName][str(a_ItemID)] = a_Type + s[a_UserID][a_ModuleName][str(a_Type)] = str(a_ItemID) def Test(): a = set() @@ -57,17 +60,17 @@ def Test(): mod_1 = 'proj' mod_2 = 'backup' s = BotSubscribes() - s.AddSubscribe(user_id_1, mod_1, SubscribeType.ADD) + s.AddSubscribe(user_id_1, mod_1, SubscribeType.ANY_ITEM_ADD) s.AddSubscribe(user_id_2, mod_2, SubscribeType.ITEM_DEL) - assert len(s.GetUserIDs(mod_1, SubscribeType.ADD)) == 1 + assert len(s.GetUserIDs(mod_1, SubscribeType.ANY_ITEM_ADD)) == 1 assert len(s.GetUserIDs(mod_1, SubscribeType.ANY_ITEM_DEL)) == 0 - assert user_id_1 in s.GetUserIDs(mod_1, SubscribeType.ADD) - assert not user_id_2 in s.GetUserIDs(mod_1, SubscribeType.ADD) - assert not user_id_3 in s.GetUserIDs(mod_1, SubscribeType.ADD) + assert user_id_1 in s.GetUserIDs(mod_1, SubscribeType.ANY_ITEM_ADD) + assert not user_id_2 in s.GetUserIDs(mod_1, SubscribeType.ANY_ITEM_ADD) + assert not user_id_3 in s.GetUserIDs(mod_1, SubscribeType.ANY_ITEM_ADD) assert len(s.GetUserIDs(mod_2, SubscribeType.ITEM_DEL)) == 1 - assert len(s.GetUserIDs(mod_2, SubscribeType.ADD)) == 0 + assert len(s.GetUserIDs(mod_2, SubscribeType.ANY_ITEM_ADD)) == 0 assert user_id_2 in s.GetUserIDs(mod_2, SubscribeType.ITEM_DEL) assert not user_id_1 in s.GetUserIDs(mod_2, SubscribeType.ITEM_DEL) assert not user_id_3 in s.GetUserIDs(mod_2, SubscribeType.ITEM_DEL) diff --git a/bot_sys/config.py b/bot_sys/config.py index d41e67f..933455c 100644 --- a/bot_sys/config.py +++ b/bot_sys/config.py @@ -24,7 +24,9 @@ root_ids_file_name = 'config_root_ids' # Дополнительные функции def ClearReadLine(a_Line): - return a_Line[:-1] + line = a_Line.strip() + return line + def GetFirstLineFromFile(a_FileName): f = open(a_FileName, 'r') diff --git a/bot_sys/user_access.py b/bot_sys/user_access.py index abe3127..39394cd 100644 --- a/bot_sys/user_access.py +++ b/bot_sys/user_access.py @@ -8,6 +8,7 @@ from bot_sys import config user_access_group_all = 'all' user_access_group_new = 'new' +user_access_group_auth_users = 'authorize_users' user_access_readme = f''' Доступ к пользователям задаётся в виде строки @@ -32,11 +33,13 @@ ACCEES_EDIT = 'r' - изменение прав доступа # Типы уровня доступа class AccessMode(Enum): + NONE = '-' VIEW = 'v' ADD = 'a' EDIT = 'e' DELETE = 'd' ACCEES_EDIT = 'r' + ALL = '+' class UserGroups: def __init__(self, a_UserID : str, a_GroupNamesList : [str]): @@ -55,6 +58,7 @@ def CheckAccessItem(a_AccessItem : str, a_AccessMode : AccessMode): # Возвращает возможность доступа пользователю a_UserGroups в элемент с правами a_AccessValue по режиму доступа a_AccessMode def CheckAccess(a_RootIDs, a_AccessValue : str, a_UserGroups : UserGroups, a_AccessMode : AccessMode): + #print(a_RootIDs, a_AccessValue, a_UserGroups, a_AccessMode) if a_UserGroups.user_id in a_RootIDs: return True for i in a_AccessValue.split(';'): diff --git a/config_auth_docs b/config_auth_docs new file mode 100644 index 0000000..1524400 --- /dev/null +++ b/config_auth_docs @@ -0,0 +1 @@ +auth_docs/test_doc.html diff --git a/main.py b/main.py index 9675156..4a0e35a 100644 --- a/main.py +++ b/main.py @@ -6,7 +6,8 @@ import os from bot_sys import config, log, aiogram_bot, bot_messages, bd_table, user_access from bot_modules import mod_agregator, start, profile, backup, users_groups_agregator, access, projects, tasks, needs, comments from bot_modules import languages, messages, buttons, users, groups, user_in_groups -from bot_modules import orders, all_orders +from bot_modules import orders_cat, orders, all_orders, authorize +from bot_modules import bd_version from bot_sys import bot_subscribes from bot_modules import subscribes @@ -39,6 +40,7 @@ mod_buttons_name = buttons.module_name mod_users_name = users.module_name mod_groups_name = groups.module_name mod_user_in_groups_name = user_in_groups.module_name +mod_orders_cat_name = orders_cat.module_name mod_orders_name = orders.module_name mod_all_orders_name = all_orders.module_name @@ -95,17 +97,28 @@ mod_buttons = buttons.ModuleButtons(mod_languages_name, None, child_mod_name_lis g_ModuleAgregator.AddModule(mod_buttons) child_mod_name_list = [mod_start_name] -mod_orders = orders.ModuleUserOrders(None, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) -g_ModuleAgregator.AddModule(mod_orders) +mod_orders_cat = orders_cat.ModuleOrdersCat(None, mod_orders_name, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) +g_ModuleAgregator.AddModule(mod_orders_cat) child_mod_name_list = [mod_start_name] -mod_all_orders = all_orders.ModuleAllOrders(None, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) +mod_orders = orders.ModuleUserOrders(mod_orders_cat_name, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) +g_ModuleAgregator.AddModule(mod_orders) + +child_mod_name_list = [mod_start_name, mod_orders_cat_name] +mod_all_orders = all_orders.ModuleAllOrders(mod_orders_cat_name, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) g_ModuleAgregator.AddModule(mod_all_orders) child_mod_name_list = [mod_start_name] mod_subscribe = subscribes.ModuleUserSubscribe(None, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) g_ModuleAgregator.AddModule(mod_subscribe) +mod_bd_version = bd_version.ModuleBDVersion(g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) +g_ModuleAgregator.AddModule(mod_bd_version) + +child_mod_name_list = [mod_start_name] +mod_authorize = authorize.ModuleAuthorize(None, None, child_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) +g_ModuleAgregator.AddModule(mod_authorize) + child_mod_name_list = [ mod_profile.GetName(), mod_backup.GetName(), @@ -116,6 +129,8 @@ child_mod_name_list = [ mod_orders.GetName(), mod_all_orders.GetName(), mod_subscribe.GetName(), + mod_bd_version.GetName(), + mod_authorize.GetName(), ] mod_start = start.ModuleStart(child_mod_name_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_BotSubscribes, g_Log) g_ModuleAgregator.AddModule(mod_start) diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..b64513a --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'adminpanel.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt index e99a1ef..c3219b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,7 @@ -aiogram==2.20 +aiogram==2.20 colorama==0.4.5 +weasyprint +Django==2.2.1 +python-dotenv==0.21.1 +requests==2.31.0 +urllib3==1.25.11 \ No newline at end of file diff --git a/template/bd_item.py b/template/bd_item.py index 5a08a84..edfbf83 100644 --- a/template/bd_item.py +++ b/template/bd_item.py @@ -100,7 +100,7 @@ def CheckAccessBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_KeyValue, a_WorkF a_Bot.GetLog().Error(msg) return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(msg)), None - result_work_func = await a_WorkFunc(a_CallbackQuery, item[0]) + result_work_func = await a_WorkFunc(a_CallbackQuery, item[0], None, table_name = a_TableName) if result_work_func is None or result_work_func.m_BotMessage is None: return result_work_func, result_work_func diff --git a/template/bd_item_add.py b/template/bd_item_add.py index 54c6960..d3c9964 100644 --- a/template/bd_item_add.py +++ b/template/bd_item_add.py @@ -30,7 +30,7 @@ def StartAddBDItemTemplate(a_Bot, a_FSM, a_FSMStart, a_MessageFunc, a_ParentTabl if parent_id: check, res_of_work_func = await bd_item.CheckAccessBDItemTemplate(a_Bot, a_ParentTableName, a_ParentKeyFieldName, parent_id, a_MessageFunc, access_mode)(a_CallbackQuery) else: - res_of_work_func = await a_MessageFunc(a_CallbackQuery, None) + res_of_work_func = await a_MessageFunc(a_CallbackQuery, None, item_data) if not check is None: await state.finish() @@ -68,7 +68,7 @@ def FinishOrNextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableNa if parent_id: check, res_of_work_func = await bd_item.CheckAccessBDItemTemplate(a_Bot, a_ParentTableName, a_ParentKeyFieldName, parent_id, a_MessageFunc, access_mode)(a_Message) else: - res_of_work_func = await a_MessageFunc(a_Message, None) + res_of_work_func = await a_MessageFunc(a_Message, None, item_data) if not check is None: await state_func() @@ -82,7 +82,7 @@ def FinishOrNextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableNa if a_Message.photo == None or len(a_Message.photo) == 0: await state.finish() return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(error_photo_type_message), keyboard_func = a_FinishButtonFunc) - field_value = a_Message.photo[0].file_id + field_value = a_Message.photo[-1].file_id else: result = a_Message.text if a_PostProcessFunc: diff --git a/template/docs_message.py b/template/docs_message.py new file mode 100644 index 0000000..9354644 --- /dev/null +++ b/template/docs_message.py @@ -0,0 +1,93 @@ +# -*- coding: utf8 -*- +# Общественное достояние 2023, Алексей Безбородов (Alexei Bezborodov) + +# Сообщения для работы с документами + +from bot_sys import log, config, user_access +from bot_modules import groups_utils +from template import simple_message +#import odf + +def DocFilesTemplate(a_Bot, a_FilesFunc, a_CaptionMessage, a_AccessFunc, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_ErrorMessage, access_mode = user_access.AccessMode.EDIT): + async def DocFiles(a_Message): + user_id = str(a_Message.from_user.id) + user_groups= groups_utils.GetUserGroupData(a_Bot, user_id) + if not user_access.CheckAccess(a_Bot.GetRootIDs(), a_AccessFunc(), user_groups, access_mode): + return await simple_message.AccessDeniedMessage(a_Bot, a_GetButtonsFunc, user_id, a_Message, user_groups) + + msg = a_CaptionMessage.GetDesc() + msg = msg.replace('@time', a_Bot.GetLog().GetTime()) + + files = a_FilesFunc(user_id) + if not files: + await simple_message.SendMessage(a_Bot, a_ErrorMessage, a_GetButtonsFunc, None, user_id, a_Message, user_groups) + return + + for file_path, dict_replace in files.items(): + if not dict_replace: + continue + new_file = await MakeDocFile(a_Bot, file_path, dict_replace, user_id) + document = await GetFile(a_Bot, new_file) + if document is None: + await simple_message.SendMessage(a_Bot, a_ErrorMessage, a_GetButtonsFunc, None, user_id, a_Message, user_groups) + else: + await a_Bot.SendDocument( + user_id, + document, + msg, + simple_message.ProxyGetButtonsTemplate(a_GetButtonsFunc)(a_Message, user_groups), + simple_message.ProxyGetButtonsTemplate(a_GetInlineButtonsFunc)(a_Message, user_groups) + ) + return DocFiles + +async def ReplaceInFile(a_Bot, a_InputFileName, a_OutFileName, a_DictReplace): + try: + filedata = '' + + with open(a_InputFileName, 'r') as in_f: + filedata = in_f.read() + s = filedata + + for rep_this, to_this in a_DictReplace.items(): + s = s.replace(rep_this, to_this) + + with open(a_OutFileName, 'w') as out_f: + out_f.write(s) + a_Bot.GetLog().Success(f'Создан файл {a_OutFileName}') + return a_OutFileName + except Exception as e: + a_Bot.GetLog().Error(f'Не удалось заменить текст в фале {a_InputFileName} и записать в {a_OutFileName}. Ошибка {str(e)}') + return None + +from weasyprint import HTML, CSS + +async def SaveAsPdf(a_Bot, a_InputFileName, a_OutFileName): + try: + HTML(filename = a_InputFileName).write_pdf(a_OutFileName) + a_Bot.GetLog().Success(f'Создан файл {a_OutFileName}') + return a_OutFileName + except Exception as e: + a_Bot.GetLog().Error(f'Не удалось создать пдф из фала {a_InputFileName} и записать в {a_OutFileName}. Ошибка {str(e)}') + return None + +async def MakeDocFile(a_Bot, a_FilePath, a_DictReplace, a_user_id): + user_file_path = a_FilePath[:-5] + pdf_file_path = user_file_path + user_file_path += f"_{a_user_id}.html" + pdf_file_path += f"_{a_user_id}.pdf" + user_file_path = await ReplaceInFile(a_Bot, a_FilePath, user_file_path, a_DictReplace) + if not user_file_path: + return None + + return await SaveAsPdf(a_Bot, user_file_path, pdf_file_path) + +async def GetFile(a_Bot, a_Path): + if not a_Path: + return None + try: + document = open(a_Path, 'rb') + a_Bot.GetLog().Success(f'Загружен файл {a_Path}') + return document + except Exception as e: + a_Bot.GetLog().Error(f'Не удалось загрузить файл {a_Path}. Ошибка {str(e)}') + return None diff --git a/template/file_message.py b/template/file_message.py index fe7e6a7..0159aa3 100644 --- a/template/file_message.py +++ b/template/file_message.py @@ -16,7 +16,7 @@ def BackupFileTemplate(a_Bot, a_Path, a_CaptionMessage, a_AccessFunc, a_GetButto document = await GetFile(a_Bot, a_Path) if document is None: - return simple_message.SendMessage(a_Bot, a_ErrorMessage, a_GetButtonsFunc, None, user_id, a_Message, user_groups) + return await simple_message.SendMessage(a_Bot, a_ErrorMessage, a_GetButtonsFunc, None, user_id, a_Message, user_groups) msg = a_CaptionMessage.GetDesc() msg = msg.replace('@time', a_Bot.GetLog().GetTime()) From 3b99d2a8dd73c561ebe4404c81a5d64e8757fb34 Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 24 Nov 2023 11:59:53 +0300 Subject: [PATCH 2/6] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=BE=D0=BA=D0=BD=D0=BE=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=B1=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D1=88=D0=B8=D1=85=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 +++------ adminpanelapp/templates/send_telegram_message.html | 8 ++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index f58b8f3..5478952 100644 --- a/.gitignore +++ b/.gitignore @@ -3,15 +3,12 @@ config_root_ids __pycache__ log.txt bot.db -<<<<<<< HEAD adminpanelapp/migrations __init__.py .env -<<<<<<< HEAD -======= tmp.py ->>>>>>> 46ad1a6aefd07c5f411d1921fa7145d938b56dd8 -======= .idea/ venv/ ->>>>>>> f39b738d22a536bddc60ea3016319ce06869a670 +tmp.py +.idea +venv/ diff --git a/adminpanelapp/templates/send_telegram_message.html b/adminpanelapp/templates/send_telegram_message.html index 4644d06..030b159 100644 --- a/adminpanelapp/templates/send_telegram_message.html +++ b/adminpanelapp/templates/send_telegram_message.html @@ -1,6 +1,6 @@
-{% csrf_token %} - - - + {% csrf_token %} + + +
\ No newline at end of file From c3c12833e2d658755bc55d116c2c46779a1f340d Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 24 Nov 2023 19:05:30 +0300 Subject: [PATCH 3/6] =?UTF-8?q?=D1=83=D0=BC=D0=B5=D0=BD=D1=8C=D1=88=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D0=BA=D0=BD=D0=BE=20=D0=B4=D0=BB=D1=8F=20=D0=BE?= =?UTF-8?q?=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D0=B9=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adminpanelapp/templates/send_telegram_message.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/adminpanelapp/templates/send_telegram_message.html b/adminpanelapp/templates/send_telegram_message.html index 030b159..71d99e8 100644 --- a/adminpanelapp/templates/send_telegram_message.html +++ b/adminpanelapp/templates/send_telegram_message.html @@ -1,6 +1,8 @@
{% csrf_token %} - - - +
+
+    
+  
+
\ No newline at end of file From 4666b1832021ecb81c940699c7c73cc10f3f696e Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 24 Nov 2023 19:11:27 +0300 Subject: [PATCH 4/6] =?UTF-8?q?=D0=BF=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20gitignore=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 5478952..1751762 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,4 @@ __init__.py tmp.py .idea/ venv/ -tmp.py -.idea -venv/ + From b7781b40bef02d19768ab7820583ee57f028f7a5 Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 24 Nov 2023 19:26:56 +0300 Subject: [PATCH 5/6] =?UTF-8?q?=D0=BF=D0=BE=D0=BC=D0=B5=D0=BD=D1=8F=D0=BB?= =?UTF-8?q?=20=D0=B2=20settings.py=20Debug=20=3D=20False,=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=86=D0=B8=D1=8E=20=D0=B2=20=D0=B8=D0=BD=D1=81?= =?UTF-8?q?=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8=D1=8E=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + adminpanel/settings.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2cc30e0..a5cd134 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ http://t.me/Test_TPlatform_bot get_random_secret_key() 3. Вставьте полученный ключ в файл .env PLATFORM_ADMINPANEL_SECRET_KEY='ваш секретный ключ' +4. Для отладки проекта в adminpanel/settings.py установите DEBUG = False ### diff --git a/adminpanel/settings.py b/adminpanel/settings.py index 82495b0..5a2fd0c 100644 --- a/adminpanel/settings.py +++ b/adminpanel/settings.py @@ -24,7 +24,7 @@ load_dotenv() SECRET_KEY = os.getenv('PLATFORM_ADMINPANEL_SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False ALLOWED_HOSTS = ['*'] From 7e76dae60a55367abcd93ea8782617431fddf62a Mon Sep 17 00:00:00 2001 From: Anton Date: Fri, 24 Nov 2023 19:41:04 +0300 Subject: [PATCH 6/6] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20README=20#5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5cd134..9839291 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ http://t.me/Test_TPlatform_bot get_random_secret_key() 3. Вставьте полученный ключ в файл .env PLATFORM_ADMINPANEL_SECRET_KEY='ваш секретный ключ' -4. Для отладки проекта в adminpanel/settings.py установите DEBUG = False +4. Для отладки проекта в adminpanel/settings.py установите DEBUG = True ###