diff --git a/bot_modules/access.py b/bot_modules/access.py index a03c512..b5b2529 100644 --- a/bot_modules/access.py +++ b/bot_modules/access.py @@ -3,49 +3,39 @@ # Права пользователей -from bot_sys import bot_bd, log, config, keyboard, user_access -from bot_modules import start, groups -from template import simple_message, sql_request, bd_item_edit, bd_item +from bot_sys import keyboard, user_access, bot_bd, bd_table +from bot_modules import mod_simple_message, access_utils, mod_table_operate +from template import simple_message, sql_request, bd_item from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -from aiogram import types class FSMRequestToBDAccess(StatesGroup): sqlRequest = State() - class FSMEditAccessItem(StatesGroup): item_field = State() - class FSMEditDefaultAccessItem(StatesGroup): item_field = State() # --------------------------------------------------------- # БД module_name = 'access' -table_name = 'module_access' -mod_name_field = 'modName' -moduleaccess_field = 'modAccess' -mod_default_access_field = 'itemDefaultAccess' - -#TODO: Автоматическое создание init_bd_cmds, необходимо table_name, mod_name_field ... объединить в объект - -init_bd_cmds = [f"""CREATE TABLE IF NOT EXISTS {table_name}( - {mod_name_field} TEXT, - {moduleaccess_field} TEXT, - {mod_default_access_field} TEXT, - UNIQUE({mod_name_field}) -);""", -f"INSERT OR IGNORE INTO {table_name} ({mod_name_field}, {moduleaccess_field}, {mod_default_access_field}) VALUES ('{module_name}', '{user_access.user_access_group_new}=-', '{user_access.user_access_group_new}=-');" -] +table_name = access_utils.table_name +mod_name_field = access_utils.mod_name_field +moduleaccess_field = access_utils.moduleaccess_field +mod_default_access_field = access_utils.mod_default_access_field +table = bd_table.Table(table_name, [ + bd_table.TableField(mod_name_field, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.STR), + bd_table.TableField(moduleaccess_field, bd_table.TableFieldDestiny.ACCESS, bd_table.TableFieldType.STR), + bd_table.TableField(mod_default_access_field, bd_table.TableFieldDestiny.DEFAULT_ACCESS, bd_table.TableFieldType.STR), + ]) # --------------------------------------------------------- # Сообщения -access_start_message = ''' +start_message = ''' Права пользователей находятся в стадии разработки Пока можете воспользоваться хардкорным способом через запросы к БД @@ -68,11 +58,7 @@ help_message = ''' modAccess - строка ''' + user_access.user_access_readme -access_denied_message = ''' -❌ Доступ запрещён! -''' - -access_button_name = "⛀ Доступ пользователей" +start_button_name = "⛀ Доступ пользователей" sql_request_button_name = "⛁ Запрос к БД для редактирования доступа" help_button_name = "📄 Информация по редактированию доступа" @@ -92,7 +78,7 @@ moduleaccess_edit_access_message = f''' Введите новую строку доступа: ''' -edit_moduleaccess_default_access_button_name = "◈ Изменить доступ по умолчанию к модулю " +edit_moduleaccess_default_access_button_name = "◈ Изменить доступ по умолчанию" moduleaccess_edit_default_access_message = f''' Текущий доступ по умолчанию к модулю #{mod_name_field}: #{mod_default_access_field} @@ -101,106 +87,80 @@ moduleaccess_edit_default_access_message = f''' Введите новую строку доступа: ''' +moduleaccess_success_edit_message = '''✅ Доступ к модулю успешно отредактирован!''' + +button_names = { + mod_simple_message.ButtonNames.START: start_button_name, + mod_table_operate.ButtonNames.EDIT: "🛠 Редактировать доступ", + mod_table_operate.ButtonNames.EDIT_ACCESS: edit_moduleaccess_access_button_name, + mod_table_operate.ButtonNames.EDIT_DEFAULT_ACCESS: edit_moduleaccess_default_access_button_name, + } + +messages = { + mod_simple_message.Messages.START: start_message, + mod_table_operate.Messages.START_EDIT: ''' +Пожалуйста, выберите действие: +''', + mod_table_operate.Messages.SELECT_TO_EDIT: moduleaccess_select_to_edit_message, + mod_table_operate.Messages.EDIT_ACCESS: moduleaccess_edit_access_message, + mod_table_operate.Messages.EDIT_DEFAULT_ACCESS: moduleaccess_edit_default_access_message, + mod_table_operate.Messages.SUCCESS_EDIT: moduleaccess_success_edit_message, +} + +fsm = { + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditAccessItem, + mod_table_operate.FSMs.EDIT_DEFAULT_ACCESS: FSMEditDefaultAccessItem, + } + +init_access = f'{user_access.user_access_group_new}=-' + +class ModuleAccess(mod_table_operate.TableOperateModule): + def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log): + super().__init__(table, messages, button_names, fsm, None, None, init_access, a_ChildModuleNameList, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + self.m_SqlRequestButtonName = self.CreateButton('sql request', sql_request_button_name) + self.m_RequestStartMessage = self.CreateMessage('equest start', request_start_message) + + self.m_HelpButtonName = self.CreateButton('help', help_button_name) + self.m_HelpMessage = self.CreateMessage('help', help_message) + + self.m_HelpMessageHandler = simple_message.InfoMessageTemplate( + self.m_Bot, + self.m_HelpMessage, + self.m_GetStartKeyboardButtonsFunc, + None, + self.m_GetAccessFunc + ) -moduleaccess_success_edit_message = '''✅ Проект успешно отредактирован!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditAccessKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(sql_request_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_moduleaccess_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_moduleaccess_default_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - keyboard.ButtonWithAccess(help_button_name, user_access.AccessMode.VIEW, GetAccess()) - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -# --------------------------------------------------------- -# Обработка сообщений - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # ButtonName KeyValue Access - return a_Item[0], a_Item[0], a_Item[1] - -def ShowMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 3): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = a_StringMessage.\ - replace(f'#{mod_name_field}', a_Item[0]).\ - replace(f'#{moduleaccess_field}', a_Item[1]).\ - replace(f'#{mod_default_access_field}', a_Item[2]) - return simple_message.WorkFuncResult(msg, item_access = a_Item[1]) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# --------------------------------------------------------- -# Работа с базой данных - -def GetModuleAccessList(): - return bot_bd.SelectBDTemplate(table_name)() - -# --------------------------------------------------------- -# API - -def GetAccessForModule(a_ModuleName): - alist = GetModuleAccessList() - for i in alist: - if i[0] == a_ModuleName: - return i[1] - return '' - -def GetItemDefaultAccessForModule(a_ModuleName): - alist = GetModuleAccessList() - for i in alist: - if i[0] == a_ModuleName: - return i[2] - return '' - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(access_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetEditAccessKeyboardButtons - dp.register_message_handler(simple_message.InfoMessageTemplate(access_start_message, defaul_keyboard_func, GetAccess), text = access_button_name) - dp.register_message_handler(simple_message.InfoMessageTemplate(help_message, defaul_keyboard_func, GetAccess), text = help_button_name) - - sql_request.RequestToBDRegisterHandlers(dp, sql_request_button_name, request_start_message, FSMRequestToBDAccess, defaul_keyboard_func, user_access.AccessMode.ACCEES_EDIT, GetAccess) - - edit_keyboard_func = defaul_keyboard_func - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.ACCEES_EDIT): - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - None, \ - a_FSM, \ - bd_item.GetCheckForTextFunc(a_ButtonName), \ - moduleaccess_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(moduleaccess_success_edit_message), \ - table_name, \ - mod_name_field, \ - None, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ + def GetButtonNameAndKeyValueAndAccess(self, a_Item): + return \ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.KEY)],\ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.KEY)],\ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)] + + def GetName(self): + return module_name + + def GetStartKeyboardButtons(self, a_Message, a_UserGroups): + mod_buttons = super().GetStartKeyboardButtons(a_Message, a_UserGroups) + cur_buttons = [ + keyboard.ButtonWithAccess(self.m_SqlRequestButtonName, user_access.AccessMode.EDIT, self.GetAccess()), + keyboard.ButtonWithAccess(self.m_HelpButtonName , user_access.AccessMode.VIEW, self.GetAccess()) + ] + return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) + + def RegisterHandlers(self): + super().RegisterHandlers() + sql_request.RequestToBDRegisterHandlers( + self.m_Bot, + self.m_SqlRequestButtonName, + self.m_RequestStartMessage, + FSMRequestToBDAccess, + self.m_GetStartKeyboardButtonsFunc, + user_access.AccessMode.EDIT, + self.m_GetAccessFunc ) - RegisterEdit(edit_moduleaccess_access_button_name, FSMEditAccessItem, moduleaccess_edit_access_message, moduleaccess_field, bd_item.FieldType.text, user_access.AccessMode.ACCEES_EDIT) - RegisterEdit(edit_moduleaccess_default_access_button_name, FSMEditDefaultAccessItem, moduleaccess_edit_default_access_message, mod_default_access_field, bd_item.FieldType.text, user_access.AccessMode.EDIT) + self.m_Bot.RegisterMessageHandler( + self.m_HelpMessageHandler, + bd_item.GetCheckForTextFunc(self.m_HelpButtonName) + ) + diff --git a/bot_modules/access_utils.py b/bot_modules/access_utils.py new file mode 100644 index 0000000..18c6e99 --- /dev/null +++ b/bot_modules/access_utils.py @@ -0,0 +1,37 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Права пользователей + +from bot_sys import bot_bd + +# --------------------------------------------------------- +# БД +table_name = 'module_access' +mod_name_field = 'modName' +moduleaccess_field = 'modAccess' +mod_default_access_field = 'itemDefaultAccess' + +access_denied_message = ''' +❌ Доступ запрещён! +''' + +def GetAccessForModuleRequest(module_name, access, default_access): + return f"INSERT OR IGNORE INTO {table_name} ({mod_name_field}, {moduleaccess_field}, {mod_default_access_field}) VALUES ('{module_name}', '{access}', '{default_access}');" + +def GetModulesAccessList(a_Bot): + return bot_bd.RequestSelectTemplate(a_Bot, table_name)() + +def GetAccessForModule(a_Bot, a_ModuleName): + alist = GetModulesAccessList(a_Bot) + for i in alist: + if i[0] == a_ModuleName: + return i[1] + return '' + +def GetItemDefaultAccessForModule(a_Bot, a_ModuleName): + alist = GetModulesAccessList(a_Bot) + for i in alist: + if i[0] == a_ModuleName: + return i[2] + return '' diff --git a/bot_modules/backup.py b/bot_modules/backup.py index 0fe5e61..bd4ca67 100644 --- a/bot_modules/backup.py +++ b/bot_modules/backup.py @@ -3,33 +3,22 @@ # Бэкапы пользователя -from bot_sys import bot_bd, log, config, keyboard, user_access -from bot_modules import start, access, groups -from template import file_message, simple_message - -from aiogram import Bot, types - -import sqlite3 - -from aiogram.dispatcher import Dispatcher - -bot = Bot(token=config.GetTelegramBotApiToken(), parse_mode=types.ParseMode.HTML) +from bot_sys import user_access, keyboard +from bot_modules import mod_simple_message, profile +from template import bd_item, file_message # --------------------------------------------------------- # БД module_name = 'backup' -init_bd_cmds = [ -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=-', '{user_access.user_access_group_new}=-');" -] - # --------------------------------------------------------- # Сообщения - -backup_message = ''' +start_message = ''' Здесь вы можете выполнить специальные операции по сервисному обслуживанию ''' +start_button_name = "📦 Резервные копии и логи" + backup_bd_message = ''' 📀 Резервная копия базы данных 🕰 @time @@ -44,44 +33,69 @@ error_backup_message = ''' ❌ Ошибка резервного копирования ''' -backup_button_name = "📦 Резервные копии и логи" backup_bd_button_name = "📀 Резервные копия базы" backup_log_button_name = "📃 Логи" -# --------------------------------------------------------- -# Работа с кнопками - -def GetBackupKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(backup_bd_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(backup_log_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -# --------------------------------------------------------- -# Обработка сообщений - -# --------------------------------------------------------- -# Работа с базой данных пользователей - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(backup_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - dp.register_message_handler(simple_message.InfoMessageTemplate(backup_message, GetBackupKeyboardButtons, GetAccess), text = backup_button_name) - - dp.register_message_handler(file_message.BackupFileTemplate(bot_bd.GetBDFileName(), backup_bd_message, GetAccess, GetBackupKeyboardButtons, error_backup_message), text = backup_bd_button_name) - dp.register_message_handler(file_message.BackupFileTemplate(log.g_log_file_name, backup_log_message, GetAccess, GetBackupKeyboardButtons, error_backup_message), text = backup_log_button_name) +button_names = { + mod_simple_message.ButtonNames.START: start_button_name, +} + +messages = { + mod_simple_message.Messages.START: start_message, +} + +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_Log): + super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + self.m_BackupBDButtonName = self.CreateButton('backup bd', backup_bd_button_name) + self.m_BackupBDMessage = self.CreateMessage('backup bd', backup_bd_message) + + self.m_BackupLogButtonName = self.CreateButton('backup log', backup_log_button_name) + self.m_BackupLogMessage = self.CreateMessage('backup log', backup_log_message) + + self.m_BackupErrorMessage = self.CreateMessage('backup error', error_backup_message) + + self.m_BackupBDMessageHandler = file_message.BackupFileTemplate( + self.m_Bot, + self.m_Bot.m_BDFileName, + self.m_BackupBDMessage, + self.m_GetAccessFunc, + self.m_GetStartKeyboardButtonsFunc, + None, + self.m_BackupErrorMessage, + access_mode = user_access.AccessMode.EDIT + ) + self.m_BackupLogMessageHandler = file_message.BackupFileTemplate( + self.m_Bot, + self.m_Bot.GetLog().GetFileName(), + self.m_BackupLogMessage, + self.m_GetAccessFunc, + self.m_GetStartKeyboardButtonsFunc, + None, + self.m_BackupErrorMessage, + access_mode = user_access.AccessMode.EDIT + ) + + def GetName(self): + return module_name + + def GetStartKeyboardButtons(self, a_Message, a_UserGroups): + mod_buttons = super().GetStartKeyboardButtons(a_Message, a_UserGroups) + cur_buttons = [ + keyboard.ButtonWithAccess(self.m_BackupBDButtonName, user_access.AccessMode.EDIT, self.GetAccess()), + keyboard.ButtonWithAccess(self.m_BackupLogButtonName , user_access.AccessMode.EDIT, self.GetAccess()) + ] + return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) + + def RegisterHandlers(self): + super().RegisterHandlers() + self.m_Bot.RegisterMessageHandler( + self.m_BackupBDMessageHandler, + bd_item.GetCheckForTextFunc(self.m_BackupBDButtonName) + ) + self.m_Bot.RegisterMessageHandler( + self.m_BackupLogMessageHandler, + bd_item.GetCheckForTextFunc(self.m_BackupLogButtonName) + ) diff --git a/bot_modules/buttons.py b/bot_modules/buttons.py new file mode 100644 index 0000000..e2cef12 --- /dev/null +++ b/bot_modules/buttons.py @@ -0,0 +1,200 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Сообщения + +from bot_sys import bot_bd, keyboard, user_access, bd_table, bot_messages +from bot_modules import mod_table_operate, mod_simple_message, access_utils +from template import bd_item + +from aiogram.dispatcher import FSMContext +from aiogram.dispatcher.filters.state import State, StatesGroup + +class FSMCreateButton(StatesGroup): + name = State() + desc = State() + photo = State() + +class FSMEditButtonPhotoItem(StatesGroup): + item_id = State() + item_field = State() + +class FSMEditButtonNameItem(StatesGroup): + item_id = State() + item_field = State() + +class FSMEditButtonDescItem(StatesGroup): + item_id = State() + item_field = State() + +class FSMEditButtonAccessItem(StatesGroup): + item_id = State() + item_field = State() +# --------------------------------------------------------- +# БД +module_name = 'buttons' + +table_name = module_name +key_name = 'buttonID' +name_field = 'buttonName' +desc_field = 'buttonDesc' +photo_field = 'buttonPhoto' +access_field = 'buttonAccess' +create_datetime_field = 'buttonCreateDateTime' +parent_id_field = 'languageID' + +table_name_field = bd_table.TableField(name_field, bd_table.TableFieldDestiny.NAME, bd_table.TableFieldType.STR) +table_parent_id_field = bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT) + +table = bd_table.Table(table_name, [ + bd_table.TableField(key_name, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.INT), + table_name_field, + 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.STR), + 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), + table_parent_id_field, + ], + [ + [table_name_field, table_parent_id_field], + ] +) + +init_access = f'{user_access.user_access_group_all}=-' + +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateButton, + mod_table_operate.FSMs.EDIT_NAME: FSMEditButtonNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditButtonDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditButtonPhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditButtonAccessItem, + } + +# --------------------------------------------------------- +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение у названия кнопок", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название у названия кнопок", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание у названия кнопок", + mod_table_operate.ButtonNames.EDIT_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.Messages.CREATE_NAME: ''' +Создание названия кнопки Шаг №1 + +Введите название название кнопки: +''', + mod_table_operate.Messages.CREATE_DESC: ''' +Создание названия кнопки. Шаг №2 + +Введите описание название кнопки: +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' +Создание названия кнопки +Загрузите обложку для названия кнопок (Фото): +На данный момент не поддерживается! +Нажмите пропустить +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Название кнопки успешно добавлено!''', + mod_table_operate.Messages.START_EDIT: ''' +Пожалуйста, выберите действие: +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' +Выберите название кнопки, который вы хотите отредактировать. +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' +Загрузите новую обложку для названия кнопок (Фото): +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.EDIT_NAME: f''' +Текущее название названия кнопок: +#{name_field} + +Введите новое название названия кнопки: +''', + mod_table_operate.Messages.EDIT_DESC: f''' +Текущее описание названия кнопок: +#{desc_field} + +Введите новое описание названия кнопки: +''', + mod_table_operate.Messages.EDIT_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: '''✅ Название кнопки успешно удалено!''', +} + +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + + def GetName(self): + return module_name + + def AddOrIgnoreMessage(self, a_Message): + table_name = self.m_Table.GetName() + name_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.NAME) + photo_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PHOTO) + desc_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DESC) + access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.ACCESS) + create_datetime_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.CREATE_DATE) + parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + + lang_id = self.GetModule(self.m_ParentModName).GetLangID(a_Message.m_Language) + return self.m_Bot.SQLRequest(f'INSERT OR IGNORE INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', + commit = True, return_error = True, param = (a_Message.m_PhotoID, a_Message.m_MessageName, a_Message.m_MessageDesc, access_utils.GetItemDefaultAccessForModule(self.m_Bot, module_name), lang_id)) + + def FlushMessages(self): + msg = self.m_BotButtons.GetMessages() + for lang, msg_dict in msg.items(): + for msg_name, message in msg_dict.items(): + self.AddOrIgnoreMessage(message) + + table_name = self.m_Table.GetName() + msgs_bd = bd_item.GetAllItemsTemplate(self.m_Bot, table_name)() + if msgs_bd: + for m in msgs_bd: + name = m[1] + desc = m[2] + photo_id = m[3] + lang_id = m[6] + lang_name = self.GetModule(self.m_ParentModName).GetLangName(lang_id) + self.m_BotButtons.CreateMessage(name, desc, self.m_Log.GetTimeNow(), a_MessagePhotoID = photo_id, a_MessageLang = lang_name) + + self.m_BotButtons.UpdateSignal(self.m_Log.GetTimeNow()) + + def OnChange(self): + self.FlushMessages() diff --git a/bot_modules/comments.py b/bot_modules/comments.py index 14c14cc..8217dc8 100644 --- a/bot_modules/comments.py +++ b/bot_modules/comments.py @@ -3,26 +3,27 @@ # Комментарии -from bot_sys import bot_bd, log, keyboard, user_access -from bot_modules import start, access, groups, projects, tasks, needs -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add, bd_item_select - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table +from bot_modules import mod_table_operate, mod_simple_message from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateComment(StatesGroup): - bd_item = State() + name = State() + desc = State() + photo = State() + +class FSMEditCommentPhotoItem(StatesGroup): + item_field = State() + +class FSMEditCommentNameItem(StatesGroup): + item_field = State() class FSMEditCommentDescItem(StatesGroup): - item_id = State() item_field = State() class FSMEditCommentAccessItem(StatesGroup): - item_id = State() item_field = State() # --------------------------------------------------------- # БД @@ -30,302 +31,123 @@ module_name = 'comments' table_name = module_name key_name = 'commentID' +name_field = 'commentName' desc_field = 'commentDesc' +photo_field = 'commentPhoto' access_field = 'commentAccess' create_datetime_field = 'commentCreateDateTime' parent_id_field = 'needID' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {desc_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - {parent_id_field} INTEGER - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=va', '{user_access.user_access_group_new}=va');" -] - -select_comments_prefix = '' +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.STR), + 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), + bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT), + ]) + +init_access = f'{user_access.user_access_group_new}=va' + +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateComment, + mod_table_operate.FSMs.EDIT_NAME: FSMEditCommentNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditCommentDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditCommentPhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditCommentAccessItem, + } # --------------------------------------------------------- -# Сообщения - -comments_button_name = "⚏ Комментарии" -base_comment_message = f''' -{comments_button_name} - -''' - -list_comment_button_name = "📃 Список комментариев" -select_comment_message = ''' +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение у комментария", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название у комментария", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание у комментария", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите комментарий: -''' - -error_find_proj_message = ''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' ❌ Ошибка, комментарий не найден -''' - -comment_open_message = f''' -Комментарий +''', + mod_table_operate.Messages.OPEN: f''' +Комментарий: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''' - -# Создание комментариев - -add_comment_button_name = "☑ Добавить комментарий" -comment_create_desc_message = ''' -Введите свой комментарий: -''' - -comment_success_create_message = '''✅ Комментарий успешно добавлен!''' - -# Редактирование комментариев. - -edit_comment_button_name = "🛠 Редактировать комментарий" -comment_start_edit_message= ''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' +Создание комментария. Шаг №1 + +Введите название комментария: +''', + mod_table_operate.Messages.CREATE_DESC: ''' +Создание комментария. Шаг №2 + +Введите описание комментария: +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' +Создание комментария. Шаг №3 + +Загрузите обложку для комментария (Фото): +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Комментарий успешно добавлен!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''' - -comment_select_to_edit_message = ''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' Выберите комментарий, который вы хотите отредактировать. -''' - -edit_comment_desc_button_name = "𝌴 Изменить комментарий" -comment_edit_desc_message = f''' -Текущий комментарий: +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' +Загрузите новую обложку для комментария (Фото): +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.EDIT_NAME: f''' +Текущее название комментария: +#{name_field} + +Введите новое название комментария: +''', + mod_table_operate.Messages.EDIT_DESC: f''' +Текущее описание комментария: #{desc_field} -Введите отредактированный комментарий: -''' - -edit_comment_access_button_name = "✋ Изменить доступ к комментарию" -comment_edit_access_message = f''' -Текущий доступ к комментарию: +Введите новое описание комментария: +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' +Текущий доступ к комментарийу: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''' - -comment_success_edit_message = '''✅ Комментарий успешно отредактирован!''' - -# Удаление комментариев - -del_comment_button_name = "❌ Удалить комментарий" -comment_select_to_delete_message = ''' -Выберите комментарий, которую вы хотите удалить. -''' - -comment_success_delete_message = '''✅ Комментарий успешно удалён!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditCommentKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_comment_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_comment_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetStartCommentKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_comment_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_comment_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_comment_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_comment_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, projects, tasks, needs] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -# --------------------------------------------------------- -# Обработка сообщений - -# стартовое сообщение -async def CommentsOpen(a_Message : types.message, state = None): - return simple_message.WorkFuncResult(base_comment_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # commentDesc commentID commentAccess - return a_Item[1], a_Item[0], a_Item[2] - -def ShowMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 4): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = a_StringMessage.\ - replace(f'#{desc_field}', a_Item[1]).\ - replace(f'#{create_datetime_field}', a_Item[3]).\ - replace(f'#{access_field}', a_Item[2]) - return simple_message.WorkFuncResult(msg, item_access = a_Item[2]) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# Удаление комментариев - -async def CommentPreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 4): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[2] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def CommentPostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Комментарий №{a_ItemID} был удалён пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - return simple_message.WorkFuncResult(comment_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных комментариев - -def AddBDItemFunc(a_ItemData, a_UserID): - print(a_ItemData) - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+", a_ItemData[parent_id_field])) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - return res, error - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(comments_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartCommentKeyboardButtons - def RegisterSelectParent(a_ButtonName, access_mode): - a_PrefixBase = a_ButtonName - a_Prefix = bd_item_select.FirstSelectBDItemRegisterHandlers(dp, \ - a_PrefixBase, \ - a_ButtonName, \ - projects.table_name, \ - projects.key_name, \ - projects.GetButtonNameAndKeyValueAndAccess, \ - projects.select_project_message, \ - projects.GetAccess, \ - access_mode = access_mode\ - ) - a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(dp, \ - a_Prefix, \ - tasks.parent_id_field, \ - tasks.table_name, \ - tasks.key_name, \ - tasks.GetButtonNameAndKeyValueAndAccess, \ - tasks.select_task_message, \ - tasks.GetAccess, \ - access_mode = access_mode\ - ) - a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(dp, \ - a_Prefix, \ - needs.parent_id_field, \ - needs.table_name, \ - needs.key_name, \ - needs.GetButtonNameAndKeyValueAndAccess, \ - needs.select_need_message, \ - needs.GetAccess, \ - access_mode = access_mode\ - ) - return a_Prefix - - - # Стартовое сообщение - dp.register_message_handler(simple_message.SimpleMessageTemplate(CommentsOpen, defaul_keyboard_func, GetAccess), text = comments_button_name) - - # Список комментариев - a_Prefix = RegisterSelectParent(list_comment_button_name, user_access.AccessMode.VIEW) - bd_item_view.LastSelectAndShowBDItemRegisterHandlers(dp, \ - a_Prefix, parent_id_field, \ - table_name, key_name, \ - ShowMessageTemplate(comment_open_message), \ - GetButtonNameAndKeyValueAndAccess, \ - select_comment_message, \ - GetAccess, \ - defaul_keyboard_func, \ - access_mode = user_access.AccessMode.VIEW\ - ) - global select_comments_prefix - select_comments_prefix = a_Prefix - - # Удаление комментариев - a_Prefix = RegisterSelectParent(del_comment_button_name, user_access.AccessMode.DELETE) - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - a_Prefix, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - table_name, \ - key_name, \ - parent_id_field, \ - CommentPreDelete, \ - CommentPostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_comment_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление комментариев - a_Prefix = RegisterSelectParent(add_comment_button_name, user_access.AccessMode.ADD) - bd_item_add.AddBDItem1RegisterHandlers(dp, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - FSMCreateComment, \ - AddBDItemFunc, \ - SimpleMessageTemplate(comment_create_desc_message), \ - SimpleMessageTemplate(comment_success_create_message), \ - a_Prefix,\ - needs.table_name, \ - needs.key_name, \ - desc_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartCommentKeyboardButtons,\ - bd_item.FieldType.text - ) - - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - a_Prefix = RegisterSelectParent(a_ButtonName, a_AccessMode) - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - a_Prefix, \ - a_FSM, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - comment_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(comment_success_edit_message), \ - table_name, \ - key_name, \ - parent_id_field, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) - - # Редактирование комментариев - edit_keyboard_func = GetEditCommentKeyboardButtons - dp.register_message_handler(simple_message.InfoMessageTemplate(comment_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_comment_button_name) - - RegisterEdit(edit_comment_desc_button_name, FSMEditCommentDescItem, comment_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_comment_access_button_name, FSMEditCommentAccessItem, comment_edit_access_message, access_field, bd_item.FieldType.text) +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Комментарий успешно отредактирован!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' +Выберите комментарий, который вы хотите удалить. +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Комментарий успешно удалён!''', +} + +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + + def GetName(self): + return module_name diff --git a/bot_modules/groups.py b/bot_modules/groups.py index 68e386e..7d02fa6 100644 --- a/bot_modules/groups.py +++ b/bot_modules/groups.py @@ -3,13 +3,12 @@ # Группы пользователей -from bot_sys import bot_bd, log, config, keyboard, user_access -from bot_modules import start, access -from template import simple_message, sql_request +from bot_sys import keyboard, user_access, bot_bd +from bot_modules import mod_simple_message +from template import simple_message, sql_request, bd_item from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher class FSMRequestToBD(StatesGroup): sqlRequest = State() @@ -27,34 +26,9 @@ user_id_field = 'user_id' access_field = 'access' create_datetime_field = 'createDateTime' -init_bd_cmds = [f"""CREATE TABLE IF NOT EXISTS {table_groups_name}( - {key_table_groups_name} INTEGER PRIMARY KEY NOT NULL, - {name_table_groups_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - UNIQUE({key_table_groups_name}), - UNIQUE({name_table_groups_field}) -);""", -f"""CREATE TABLE IF NOT EXISTS {table_user_in_groups_name}( - {user_id_field} INTEGER, - {key_table_groups_name} INTEGER, - {access_field} TEXT, - {create_datetime_field} TEXT, - UNIQUE({user_id_field}, {key_table_groups_name}) -);""", -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=-', '{user_access.user_access_group_new}=-');", -f"INSERT OR IGNORE INTO {table_groups_name} ({name_table_groups_field}, {access_field}, {create_datetime_field}) VALUES ('{user_access.user_access_group_new}', '{user_access.user_access_group_new}=-', {bot_bd.GetBDDateTimeNow()});" -] - # --------------------------------------------------------- # Сообщения -group_start_message = ''' -Группы пользователей находятся в стадии разработки - -Пока можете воспользоваться хардкорным способом через запросы к БД -''' - request_start_message = ''' **Задайте запрос к БД** @@ -73,58 +47,84 @@ help_message = ''' `user_in_groups(user_id, group_id)` - содержит соответсвия ID пользователей и групп ''' -user_group_button_name = "‍️️▦ Группы пользователей" sql_request_button_name = "⛃ Запрос к БД для редактирования групп" help_button_name = "📄 Информация по группам" -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditGroupKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(sql_request_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(help_button_name, user_access.AccessMode.VIEW, GetAccess()) - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) +button_names = { + mod_simple_message.ButtonNames.START: "‍️️▦ Группы пользователей", +} -# --------------------------------------------------------- -# Обработка сообщений - -# --------------------------------------------------------- -# Работа с базой данных групп - -def GetGroupIDForUser(a_UserID): - return bot_bd.SQLRequestToBD('SELECT group_id FROM user_in_groups WHERE user_id = ?', param = [a_UserID]) - -def GetGroupNamesForUser(a_UserID): - return bot_bd.SQLRequestToBD('SELECT groupName FROM user_groups WHERE group_id=(SELECT group_id FROM user_in_groups WHERE user_id = ?)', param = [a_UserID]) - -# --------------------------------------------------------- -# API - -def GetUserGroupData(a_UserID): - r = GetGroupNamesForUser(a_UserID) - groups = [] - for i in r: - if len(i) > 0: - groups += [i[0]] - return user_access.UserGroups(a_UserID, groups) - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(user_group_button_name, user_access.AccessMode.VIEW, GetAccess())] +messages = { + mod_simple_message.Messages.START: ''' +Группы пользователей находятся в стадии разработки -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - dp.register_message_handler(simple_message.InfoMessageTemplate(group_start_message, GetEditGroupKeyboardButtons, GetAccess), text = user_group_button_name) - dp.register_message_handler(simple_message.InfoMessageTemplate(help_message, GetEditGroupKeyboardButtons, GetAccess), text = help_button_name) +Пока можете воспользоваться хардкорным способом через запросы к БД +''', +} + +init_access = f'{user_access.user_access_group_new}=-' + +class ModuleGroups(mod_simple_message.SimpleMessageModule): + def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log): + super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + self.m_SqlRequestButtonName = self.CreateButton('sql request', sql_request_button_name) + self.m_RequestStartMessage = self.CreateMessage('equest start', request_start_message) + + self.m_HelpButtonName = self.CreateButton('help', help_button_name) + self.m_HelpMessage = self.CreateMessage('help', help_message) + + self.m_HelpMessageHandler = simple_message.InfoMessageTemplate( + self.m_Bot, + self.m_HelpMessage, + self.m_GetStartKeyboardButtonsFunc, + None, + self.m_GetAccessFunc + ) + + def GetInitBDCommands(self): + return super(). GetInitBDCommands() + [ + f"""CREATE TABLE IF NOT EXISTS {table_groups_name}( + {key_table_groups_name} INTEGER PRIMARY KEY NOT NULL, + {name_table_groups_field} TEXT, + {access_field} TEXT, + {create_datetime_field} TEXT, + UNIQUE({key_table_groups_name}), + UNIQUE({name_table_groups_field}) + );""", + f"""CREATE TABLE IF NOT EXISTS {table_user_in_groups_name}( + {user_id_field} INTEGER, + {key_table_groups_name} INTEGER, + {access_field} TEXT, + {create_datetime_field} TEXT, + UNIQUE({user_id_field}, {key_table_groups_name}) + );""", + f"INSERT OR IGNORE INTO {table_groups_name} ({name_table_groups_field}, {access_field}, {create_datetime_field}) VALUES ('{user_access.user_access_group_new}', '{user_access.user_access_group_new}=-', {bot_bd.GetBDDateTimeNow()});" + ] + + def GetName(self): + return module_name + + def GetStartKeyboardButtons(self, a_Message, a_UserGroups): + mod_buttons = super().GetStartKeyboardButtons(a_Message, a_UserGroups) + cur_buttons = [ + keyboard.ButtonWithAccess(self.m_SqlRequestButtonName, user_access.AccessMode.EDIT, self.GetAccess()), + keyboard.ButtonWithAccess(self.m_HelpButtonName , user_access.AccessMode.VIEW, self.GetAccess()) + ] + return mod_buttons + keyboard.MakeButtons(cur_buttons, a_UserGroups) + + def RegisterHandlers(self): + super().RegisterHandlers() + sql_request.RequestToBDRegisterHandlers( + self.m_Bot, + self.m_SqlRequestButtonName, + self.m_RequestStartMessage, + FSMRequestToBD, + self.m_GetStartKeyboardButtonsFunc, + user_access.AccessMode.EDIT, + self.m_GetAccessFunc + ) + self.m_Bot.RegisterMessageHandler( + self.m_HelpMessageHandler, + bd_item.GetCheckForTextFunc(self.m_HelpButtonName) + ) - sql_request.RequestToBDRegisterHandlers(dp, sql_request_button_name, request_start_message, FSMRequestToBD, GetEditGroupKeyboardButtons, user_access.AccessMode.EDIT, GetAccess) diff --git a/bot_modules/groups_utils.py b/bot_modules/groups_utils.py new file mode 100644 index 0000000..e80e53e --- /dev/null +++ b/bot_modules/groups_utils.py @@ -0,0 +1,16 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Группы пользователей + +from bot_sys import user_access + +def GetUserGroupData(a_Bot, a_UserID): + def GetGroupNamesForUser(a_UserID): + return a_Bot.SQLRequest('SELECT groupName FROM user_groups WHERE group_id=(SELECT group_id FROM user_in_groups WHERE user_id = ?)', param = [a_UserID]) + r = GetGroupNamesForUser(a_UserID) + groups = [] + for i in r: + if len(i) > 0: + groups += [i[0]] + return user_access.UserGroups(a_UserID, groups) diff --git a/bot_modules/languages.py b/bot_modules/languages.py index 250111f..259bb59 100644 --- a/bot_modules/languages.py +++ b/bot_modules/languages.py @@ -3,16 +3,12 @@ # Языки -from bot_sys import bot_bd, log, keyboard, user_access, user_messages -from bot_modules import start, access, groups, messages -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table +from bot_modules import mod_table_operate, mod_simple_message, access_utils +from template import bd_item from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateLanguage(StatesGroup): name = State() @@ -25,7 +21,7 @@ class FSMEditLanguagePhotoItem(StatesGroup): class FSMEditLanguageNameItem(StatesGroup): item_field = State() -class FSMEditLanguageDeskItem(StatesGroup): +class FSMEditLanguageDescItem(StatesGroup): item_field = State() class FSMEditLanguageAccessItem(StatesGroup): @@ -42,336 +38,157 @@ photo_field = 'languagePhoto' access_field = 'languageAccess' create_datetime_field = 'languageCreateDateTime' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {name_field} TEXT, - {desc_field} TEXT, - {photo_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - UNIQUE({key_name}), - UNIQUE({name_field}) - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_all}=-', '{user_access.user_access_group_all}=-');" -] - -# --------------------------------------------------------- -# Сообщения +table_name_field = bd_table.TableField(name_field, bd_table.TableFieldDestiny.NAME, bd_table.TableFieldType.STR) + +table = bd_table.Table(table_name, [ + bd_table.TableField(key_name, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.INT), + table_name_field, + 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.STR), + 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), + ], + [ + [table_name_field], + ] +) -languages_button_name = "⚑ Языки" -base_language_message = f''' -{languages_button_name} +init_access = f'{user_access.user_access_group_all}=-' -''' +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateLanguage, + mod_table_operate.FSMs.EDIT_NAME: FSMEditLanguageNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditLanguageDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditLanguagePhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditLanguageAccessItem, + } -list_language_button_name = "📃 Список языков" -select_language_message = ''' +# --------------------------------------------------------- +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение в языке", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название в языке", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание в языке", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите язык: -''' - -error_find_proj_message = ''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' ❌ Ошибка, язык не найден -''' - -language_open_message = f''' +''', + mod_table_operate.Messages.OPEN: f''' Язык: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''' - -# Создание языка - -add_language_button_name = "✅ Добавить язык" -language_create_name_message = ''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' Создание языка. Шаг №1 Введите название языка: -''' - -language_create_desc_message = ''' +''', + mod_table_operate.Messages.CREATE_DESC: ''' Создание языка. Шаг №2 Введите описание языка: -''' - -language_create_photo_message = ''' +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' Создание языка. Шаг №3 Загрузите обложку для языка (Фото): Она будет отображаться в его описании. -''' - -language_success_create_message = '''✅ Язык успешно добавлен!''' - -# Редактирование языка. - -edit_language_button_name = "🛠 Редактировать язык" -language_start_edit_message= ''' +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Язык успешно добавлен!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''' - -language_select_to_edit_message = ''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' Выберите язык, который вы хотите отредактировать. -''' - -edit_language_photo_button_name = "☐ Изменить изображение в языке" -language_edit_photo_message = ''' +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' Загрузите новую обложку для языка (Фото): Она будет отображаться в его описании. -''' - -edit_language_name_button_name = "≂ Изменить название в языке" -language_edit_name_message = f''' +''', + mod_table_operate.Messages.EDIT_NAME: f''' Текущее название языка: #{name_field} Введите новое название языка: -''' - -edit_language_desc_button_name = "𝌴 Изменить описание в языке" -language_edit_desc_message = f''' +''', + mod_table_operate.Messages.EDIT_DESC: f''' Текущее описание языка: #{desc_field} Введите новое описание языка: -''' - -edit_language_access_button_name = "✋ Изменить доступ к языку" -language_edit_access_message = f''' +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' Текущий доступ к языку: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''' - -language_success_edit_message = '''✅ Язык успешно отредактирован!''' - -# Удаление языка - -del_language_button_name = "❌ Удалить язык" -language_select_to_delete_message = ''' -Выберите язык, которое вы хотите удалить. -''' +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Язык успешно отредактирован!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' +Выберите язык, который вы хотите удалить. +Все задачи и потребности в этом языке так же будут удалены! +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Язык успешно удалён!''', +} + +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + self.m_LanguageIDs = {} + + def GetName(self): + return module_name + + def GetLangID(self, a_Lang): + return self.m_LanguageIDs.get(a_Lang, None) + + def GetLangName(self, a_LangID): + for lang_name, lang_id in self.m_LanguageIDs: + if a_LangID == lang_id: + return lang_name + return self.m_BotMessages.m_DefaultLanguage + + def FlushLanguages(self): + msg = self.m_BotMessages.GetMessages() + for lang, msg_dict in msg.items(): + self.AddOrIgnoreLang(lang) + langs = bd_item.GetAllItemsTemplate(self.m_Bot, table_name)() + if langs: + for l in langs: + self.m_LanguageIDs[l[1]] = str(l[0]) + print('FlushLanguages', self.m_LanguageIDs) + + def AddOrIgnoreLang(self, a_Lang : str): + table_name = self.m_Table.GetName() + name_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.NAME) + photo_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PHOTO) + desc_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DESC) + access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.ACCESS) + create_datetime_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.CREATE_DATE) + + res, error = self.m_Bot.SQLRequest(f'INSERT OR IGNORE INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', + commit = True, return_error = True, param = (0, a_Lang, '', access_utils.GetItemDefaultAccessForModule(self.m_Bot, module_name))) + + def OnChange(self): + self.FlushLanguages() -language_success_delete_message = '''✅ Язык успешно удален!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditLanguageKeyboardButtons(a_Language, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_language_photo_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_language_name_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_language_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_language_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetStartLanguageKeyboardButtons(a_Language, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_language_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_language_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_language_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_language_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, messages] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetViewItemInlineKeyboardTemplate(a_ItemID): - def GetViewItemInlineKeyboard(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.InlineButton(messages.list_message_button_name, messages.select_messages_prefix, a_ItemID, GetAccess(), user_access.AccessMode.VIEW), - ] - return keyboard.MakeInlineKeyboard(cur_buttons, a_UserGroups) - return GetViewItemInlineKeyboard -# --------------------------------------------------------- -# Обработка языков - -# стартовое язык -async def LanguagesOpen(a_Language : types.message, state = None): - return simple_message.WorkFuncResult(base_language_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # languageName languageID languageAccess - return a_Item[1], a_Item[0], a_Item[4] - -def ShowMessageTemplate(a_StringLanguage, keyboard_template_func = None): - async def ShowLanguage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = a_StringLanguage.\ - replace(f'#{name_field}', a_Item[1]).\ - replace(f'#{desc_field}', a_Item[2]).\ - replace(f'#{create_datetime_field}', a_Item[5]).\ - replace(f'#{access_field}', a_Item[4]) - keyboard_func = None - if keyboard_template_func: - keyboard_func = keyboard_template_func(a_Item[0]) - return simple_message.WorkFuncResult(msg, photo_id = a_Item[3], item_access = a_Item[4], keyboard_func = keyboard_func) - return ShowLanguage - -def SimpleMessageTemplate(a_StringLanguage): - async def ShowLanguage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringLanguage) - return ShowLanguage - -# Удаление языка - -async def LanguagePreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[4] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def LanguagePostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Язык №{a_ItemID} был удалён пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - FlushLanguages() - return simple_message.WorkFuncResult(language_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных языков - -def AddBDItemFunc(a_ItemData, a_UserID): - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+")) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - FlushLanguages() - return res, error - -# --------------------------------------------------------- -# API - -def AddOrIgnoreLang(a_Lang : str): - res, error = bot_bd.SQLRequestToBD(f'INSERT OR IGNORE INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (0, a_Lang, '', access.GetItemDefaultAccessForModule(module_name))) - -g_languages = {} -def GetLangID(a_Lang): - global g_languages - return g_languages.get(a_Lang, None) - -def GetLangName(a_LangID): - global g_languages - for lang_name, lang_id in g_languages: - if a_LangID == lang_id: - return lang_name - return user_messages.default_language - -def FlushLanguages(): - global g_languages - msg = user_messages.GetMessages() - for lang, msg_dict in msg.items(): - AddOrIgnoreLang(lang) - langs = bd_item.GetAllItemsTemplate(table_name)() - if langs: - for l in langs: - g_languages[l[1]] = str(l[0]) - print('FlushLanguages', g_languages) - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [ - keyboard.ButtonWithAccess(languages_button_name, user_access.AccessMode.VIEW, GetAccess()), - ] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartLanguageKeyboardButtons - - # Список языков - dp.register_message_handler(simple_message.SimpleMessageTemplate(LanguagesOpen, defaul_keyboard_func, GetAccess), text = languages_button_name) - bd_item_view.FirstSelectAndShowBDItemRegisterHandlers(dp, \ - list_language_button_name, \ - table_name, \ - key_name, \ - ShowMessageTemplate(language_open_message, GetViewItemInlineKeyboardTemplate), \ - GetButtonNameAndKeyValueAndAccess, \ - select_language_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Удаление языка - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - None, \ - bd_item.GetCheckForTextFunc(del_language_button_name), \ - table_name, \ - key_name, \ - None, \ - LanguagePreDelete, \ - LanguagePostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_language_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление языка - bd_item_add.AddBDItem3RegisterHandlers(dp, \ - bd_item.GetCheckForTextFunc(add_language_button_name), \ - FSMCreateLanguage,\ - FSMCreateLanguage.name,\ - FSMCreateLanguage.desc, \ - FSMCreateLanguage.photo,\ - AddBDItemFunc, \ - SimpleMessageTemplate(language_create_name_message), \ - SimpleMessageTemplate(language_create_desc_message), \ - SimpleMessageTemplate(language_create_photo_message), \ - SimpleMessageTemplate(language_success_create_message), \ - None,\ - None, \ - None, \ - name_field, \ - desc_field, \ - photo_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartLanguageKeyboardButtons\ - ) - - # Редактирование языка - edit_keyboard_func = GetEditLanguageKeyboardButtons - - def RegisterEdit(a_ButtonName, a_FSM, a_EditLanguage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - None, \ - a_FSM, \ - bd_item.GetCheckForTextFunc(a_ButtonName), \ - language_select_to_edit_message, \ - ShowMessageTemplate(a_EditLanguage), \ - ShowMessageTemplate(language_success_edit_message), \ - table_name, \ - key_name, \ - None, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) - - dp.register_message_handler(simple_message.InfoMessageTemplate(language_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_language_button_name) - RegisterEdit(edit_language_photo_button_name, FSMEditLanguagePhotoItem, language_edit_photo_message, photo_field, bd_item.FieldType.photo) - RegisterEdit(edit_language_name_button_name, FSMEditLanguageNameItem, language_edit_name_message, name_field, bd_item.FieldType.text) - RegisterEdit(edit_language_desc_button_name, FSMEditLanguageDeskItem, language_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_language_access_button_name, FSMEditLanguageAccessItem, language_edit_access_message, access_field, bd_item.FieldType.text) diff --git a/bot_modules/messages.py b/bot_modules/messages.py index ccf9fad..2585c8b 100644 --- a/bot_modules/messages.py +++ b/bot_modules/messages.py @@ -3,16 +3,12 @@ # Сообщения -from bot_sys import bot_bd, log, keyboard, user_access, user_messages -from bot_modules import start, access, groups, languages -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add, bd_item_select - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table, bot_messages +from bot_modules import mod_table_operate, mod_simple_message, access_utils +from template import bd_item from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateMessage(StatesGroup): name = State() @@ -47,355 +43,158 @@ access_field = 'messageAccess' create_datetime_field = 'messageCreateDateTime' parent_id_field = 'languageID' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {name_field} TEXT, - {desc_field} TEXT, - {photo_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - {parent_id_field} INTEGER, - UNIQUE({key_name}), - UNIQUE({name_field}, {parent_id_field}) - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_all}=-', '{user_access.user_access_group_all}=-');" -] - -select_messages_prefix = '' - -# --------------------------------------------------------- -# Сообщения +table_name_field = bd_table.TableField(name_field, bd_table.TableFieldDestiny.NAME, bd_table.TableFieldType.STR) +table_parent_id_field = bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT) + +table = bd_table.Table(table_name, [ + bd_table.TableField(key_name, bd_table.TableFieldDestiny.KEY, bd_table.TableFieldType.INT), + table_name_field, + 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.STR), + 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), + table_parent_id_field, + ], + [ + [table_name_field, table_parent_id_field], + ] +) -messages_button_name = "✉ Сообщения" -base_message_message = ''' -✎ Сообщения +init_access = f'{user_access.user_access_group_all}=-' -''' +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateMessage, + mod_table_operate.FSMs.EDIT_NAME: FSMEditMessageNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditMessageDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditMessagePhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditMessageAccessItem, + } -list_message_button_name = "📃 Список сообщений" -select_message_message = ''' +# --------------------------------------------------------- +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение у сообщения", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название у сообщения", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание у сообщения", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите сообщение: -''' - -error_find_proj_message = ''' -❌ Ошибка, сообщенийа не найдена -''' - -message_open_message = f''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' +❌ Ошибка, сообщение не найден +''', + mod_table_operate.Messages.OPEN: f''' Сообщение: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''' - -# Создание сообщения - -add_message_button_name = "☑ Добавить сообщение" -message_create_name_message = ''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' Создание сообщения. Шаг №1 Введите название сообщения: -''' - -message_create_desc_message = ''' +''', + mod_table_operate.Messages.CREATE_DESC: ''' Создание сообщения. Шаг №2 Введите описание сообщения: -''' - -message_create_photo_message = ''' +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' Создание сообщения. Шаг №3 Загрузите обложку для сообщения (Фото): -Она будет отображаться в её описании. -''' - -message_success_create_message = '''✅ Сообщение успешно добавлено!''' - -# Редактирование сообщения. - -edit_message_button_name = "🛠 Редактировать сообщение" -message_start_edit_message= ''' +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Сообщение успешно добавлено!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''' - -message_select_to_edit_message = ''' -Выберите сообщение, которую вы хотите отредактировать. -''' - -edit_message_photo_button_name = "☐ Изменить изображение у сообщения" -message_edit_photo_message = ''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' +Выберите сообщение, который вы хотите отредактировать. +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' Загрузите новую обложку для сообщения (Фото): -Она будет отображаться в её описании. -''' - -edit_message_name_button_name = "≂ Изменить название у сообщения" -message_edit_name_message = f''' +Она будет отображаться в его описании. +''', + mod_table_operate.Messages.EDIT_NAME: f''' Текущее название сообщения: #{name_field} Введите новое название сообщения: -''' - -edit_message_desc_button_name = "𝌴 Изменить описание у сообщения" -message_edit_desc_message = f''' +''', + mod_table_operate.Messages.EDIT_DESC: f''' Текущее описание сообщения: #{desc_field} Введите новое описание сообщения: -''' - -edit_message_access_button_name = "✋ Изменить доступ к сообщению" -message_edit_access_message = f''' -Текущий доступ к сообщению: +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' +Текущий доступ к сообщениеу: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''' - -message_success_edit_message = '''✅ Сообщение успешно отредактировано!''' - -# Удаление сообщения - -del_message_button_name = "❌ Удалить сообщение" -message_select_to_delete_message = ''' -Выберите сообщение, которую вы хотите удалить. -''' - -message_success_delete_message = '''✅ Сообщение успешно удалено!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditMessageKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_message_photo_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_message_name_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_message_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_message_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetStartMessageKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_message_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_message_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_message_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_message_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, languages] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetViewItemInlineKeyboardTemplate(a_ItemID): - def GetViewItemInlineKeyboard(a_Message, a_UserGroups): - cur_buttons = [ - #keyboard.InlineButton(needs.list_need_button_name, needs.select_needs_prefix, a_ItemID, GetAccess(), user_access.AccessMode.VIEW), - ] - return keyboard.MakeInlineKeyboard(cur_buttons, a_UserGroups) - return GetViewItemInlineKeyboard - -# --------------------------------------------------------- -# Обработка сообщений - -# стартовое сообщение -async def MessagesOpen(a_Message : types.message, state = None): - return simple_message.WorkFuncResult(base_message_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # messageName messageID messageAccess - return a_Item[1], a_Item[0], a_Item[4] - -def ShowMessageTemplate(a_StringMessage, keyboard_template_func = None): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - - if message_success_edit_message == a_StringMessage: - FlushMessages() - # TODO FlushMessages происходит рано. Нужно после изменений - msg = a_StringMessage.\ - replace(f'#{name_field}', a_Item[1]).\ - replace(f'#{desc_field}', a_Item[2]).\ - replace(f'#{create_datetime_field}', a_Item[5]).\ - replace(f'#{access_field}', a_Item[4]) - keyboard_func = None - if keyboard_template_func: - keyboard_func = keyboard_template_func(a_Item[0]) - return simple_message.WorkFuncResult(msg, photo_id = a_Item[3], item_access = a_Item[4], keyboard_func = keyboard_func) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# Удаление сообщения - -async def MessagePreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[4] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def MessagePostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Сообщение №{a_ItemID} была удалена пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - FlushMessages() - return simple_message.WorkFuncResult(message_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных сообщений - -def AddBDItemFunc(a_ItemData, a_UserID): - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+", a_ItemData[parent_id_field])) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - FlushMessages() - return res, error - -# --------------------------------------------------------- -# API - -def AddOrIgnoreMessage(a_Message : user_messages.Message): - return bot_bd.SQLRequestToBD(f'INSERT OR IGNORE INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_Message.m_PhotoID, a_Message.m_MessageName, a_Message.m_MessageDesc, access.GetItemDefaultAccessForModule(module_name), languages.GetLangID(a_Message.m_Language))) - -def FlushMessages(): - msg = user_messages.GetMessages() - for lang, msg_dict in msg.items(): - for msg_name, message in msg_dict.items(): - AddOrIgnoreMessage(message) - - msgs_bd = bd_item.GetAllItemsTemplate(table_name)() - if msgs_bd: - for m in msgs_bd: - name = m[1] - lang_id = m[6] - lang_name = languages.GetLangName(lang_id) - new_msg = user_messages.Message(name, m[2], lang_name, m[3], log.GetTimeNow()) - if not msg.get(lang_name, None): - msg[lang_name] = {} - msg[lang_name][name] = new_msg - user_messages.UpdateSignal(log.GetTimeNow()) - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(messages_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartMessageKeyboardButtons - def RegisterSelectParent(a_ButtonName, access_mode): - a_PrefixBase = a_ButtonName - return bd_item_select.FirstSelectBDItemRegisterHandlers(dp, \ - a_PrefixBase, \ - a_ButtonName, \ - languages.table_name, \ - languages.key_name, \ - languages.GetButtonNameAndKeyValueAndAccess, \ - languages.select_language_message, \ - languages.GetAccess, access_mode = access_mode\ - ) - - # Стартовое сообщение - dp.register_message_handler(simple_message.SimpleMessageTemplate(MessagesOpen, defaul_keyboard_func, GetAccess), text = messages_button_name) - - # Список сообщений - a_Prefix = RegisterSelectParent(list_message_button_name, user_access.AccessMode.VIEW) - bd_item_view.LastSelectAndShowBDItemRegisterHandlers(dp, \ - a_Prefix, parent_id_field, \ - table_name, key_name, \ - ShowMessageTemplate(message_open_message), \ - GetButtonNameAndKeyValueAndAccess, \ - select_message_message, \ - GetAccess, \ - defaul_keyboard_func, \ - access_mode = user_access.AccessMode.VIEW\ - ) - global select_messages_prefix - select_messages_prefix = a_Prefix - - # Удаление сообщения - a_Prefix = RegisterSelectParent(del_message_button_name, user_access.AccessMode.DELETE) - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - a_Prefix, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - table_name, \ - key_name, \ - parent_id_field, \ - MessagePreDelete, \ - MessagePostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_message_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление сообщения - a_Prefix = RegisterSelectParent(add_message_button_name, user_access.AccessMode.ADD) - bd_item_add.AddBDItem3RegisterHandlers(dp, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - FSMCreateMessage, \ - FSMCreateMessage.name,\ - FSMCreateMessage.desc, \ - FSMCreateMessage.photo,\ - AddBDItemFunc, \ - SimpleMessageTemplate(message_create_name_message), \ - SimpleMessageTemplate(message_create_desc_message), \ - SimpleMessageTemplate(message_create_photo_message), \ - SimpleMessageTemplate(message_success_create_message), \ - a_Prefix,\ - languages.table_name, \ - languages.key_name, \ - name_field, \ - desc_field, \ - photo_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartMessageKeyboardButtons\ - ) - - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - a_Prefix = RegisterSelectParent(a_ButtonName, a_AccessMode) - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - a_Prefix, \ - a_FSM, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - message_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(message_success_edit_message), \ - table_name, \ - key_name, \ - parent_id_field, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) - - # Редактирование сообщения - edit_keyboard_func = GetEditMessageKeyboardButtons - dp.register_message_handler(simple_message.InfoMessageTemplate(message_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_message_button_name) - - RegisterEdit(edit_message_photo_button_name, FSMEditMessagePhotoItem, message_edit_photo_message, photo_field, bd_item.FieldType.photo) - RegisterEdit(edit_message_name_button_name, FSMEditMessageNameItem, message_edit_name_message, name_field, bd_item.FieldType.text) - RegisterEdit(edit_message_desc_button_name, FSMEditMessageDescItem, message_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_message_access_button_name, FSMEditMessageAccessItem, message_edit_access_message, access_field, bd_item.FieldType.text) +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Сообщение успешно отредактировано!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' +Выберите сообщение, который вы хотите удалить. +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Сообщение успешно удалено!''', +} + +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + + def GetName(self): + return module_name + + def AddOrIgnoreMessage(self, a_Message): + table_name = self.m_Table.GetName() + name_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.NAME) + photo_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PHOTO) + desc_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DESC) + access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.ACCESS) + create_datetime_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.CREATE_DATE) + parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + + lang_id = self.GetModule(self.m_ParentModName).GetLangID(a_Message.m_Language) + return self.m_Bot.SQLRequest(f'INSERT OR IGNORE INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', + commit = True, return_error = True, param = (a_Message.m_PhotoID, a_Message.m_MessageName, a_Message.m_MessageDesc, access_utils.GetItemDefaultAccessForModule(self.m_Bot, module_name), lang_id)) + + def FlushMessages(self): + msg = self.m_BotMessages.GetMessages() + for lang, msg_dict in msg.items(): + for msg_name, message in msg_dict.items(): + self.AddOrIgnoreMessage(message) + + table_name = self.m_Table.GetName() + msgs_bd = bd_item.GetAllItemsTemplate(self.m_Bot, table_name)() + if msgs_bd: + for m in msgs_bd: + name = m[1] + desc = m[2] + photo_id = m[3] + lang_id = m[6] + lang_name = self.GetModule(self.m_ParentModName).GetLangName(lang_id) + self.m_BotMessages.CreateMessage(name, desc, self.m_Log.GetTimeNow(), a_MessagePhotoID = photo_id, a_MessageLang = lang_name) + + self.m_BotMessages.UpdateSignal(self.m_Log.GetTimeNow()) + + def OnChange(self): + self.FlushMessages() diff --git a/bot_modules/mod_agregator.py b/bot_modules/mod_agregator.py new file mode 100644 index 0000000..f2e3306 --- /dev/null +++ b/bot_modules/mod_agregator.py @@ -0,0 +1,15 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +class ModuleAgregator: + def __init__(self): + self.m_Modules = {} + + def GetModule(self, a_ModName): + return self.m_Modules[a_ModName] + + def AddModule(self, a_Module): + self.m_Modules[a_Module.GetName()] = a_Module + + def GetModList(self): + return self.m_Modules.values() diff --git a/bot_modules/mod_interface.py b/bot_modules/mod_interface.py new file mode 100644 index 0000000..3423c78 --- /dev/null +++ b/bot_modules/mod_interface.py @@ -0,0 +1,25 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +from abc import ABC, abstractmethod + +class IModule(ABC): + @abstractmethod + def GetName(self): + pass + + @abstractmethod + def GetInitBDCommands(self): + pass + + @abstractmethod + def GetAccess(self): + pass + + @abstractmethod + def GetModuleButtons(self): + pass + + @abstractmethod + def RegisterHandlers(self): + pass diff --git a/bot_modules/mod_simple_message.py b/bot_modules/mod_simple_message.py new file mode 100644 index 0000000..19d5ff4 --- /dev/null +++ b/bot_modules/mod_simple_message.py @@ -0,0 +1,112 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Простой модуль с одним сообщением + +from bot_sys import keyboard, user_access +from bot_modules import access_utils, mod_interface +from template import simple_message, bd_item + +from enum import Enum +from enum import auto + +class ButtonNames(Enum): + START = auto() + +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_Log): + self.m_ChildModuleNameList = a_ChildModuleNameList + self.m_InitAccess = a_InitAccess + self.m_Bot = a_Bot + self.m_ModuleAgregator = a_ModuleAgregator + self.m_BotMessages = a_BotMessages + self.m_BotButtons = a_BotButtons + self.m_Log = a_Log + + self.m_Buttons = {} + for name, button_name in a_Buttons.items(): + self.m_Buttons[name] = self.CreateButton(name, button_name) + + self.m_Messages = {} + for name, message in a_Messages.items(): + self.m_Messages[name] = self.CreateMessage(name, message) + + async def StartMessageHandler(a_Message, state = None): + return await self.StartMessageHandler(a_Message, state) + self.m_StartMessageHandlerFunc = StartMessageHandler + + def GetAccess(): + return self.GetAccess() + self.m_GetAccessFunc = GetAccess + + def GetStartKeyboardButtons(a_Message, a_UserGroups): + return self.GetStartKeyboardButtons(a_Message, a_UserGroups) + self.m_GetStartKeyboardButtonsFunc = GetStartKeyboardButtons + + self.m_StartMessageHandler = simple_message.SimpleMessageTemplate( + self.m_Bot, + self.m_StartMessageHandlerFunc, + self.m_GetStartKeyboardButtonsFunc, + None, + self.m_GetAccessFunc + ) + + # Основной обработчик главного сообщения + async def StartMessageHandler(self, a_Message, state = None): + return simple_message.WorkFuncResult(self.GetMessage(Messages.START)) + + def GetButton(self, a_ButtonName): + return self.m_Buttons.get(a_ButtonName, None) + + def GetMessage(self, a_MessageNames): + return self.m_Messages.get(a_MessageNames, None) + + def CreateMessage(self, a_MessageName, a_MessageDesc): + msg = self.m_BotMessages.CreateMessage(f'{self.GetName()} {a_MessageName}', a_MessageDesc, self.m_Log.GetTimeNow()) + return msg + + def CreateButton(self, a_ButtonName, a_ButtonDesc): + assert len(a_ButtonDesc) < 41 # Телеграм не поддерживает больше + assert a_ButtonDesc[0] != ' ' # Телеграм не поддерживает пробелы в начале + assert a_ButtonDesc[-1:] != ' ' # Телеграм не поддерживает пробелы в конце + btn = self.m_BotButtons.CreateMessage(f'{self.GetName()} {a_ButtonName}', a_ButtonDesc, self.m_Log.GetTimeNow()) + return btn + + def GetModule(self, a_ModName): + return self.m_ModuleAgregator.GetModule(a_ModName) + + def GetButtons(self, a_ModNameList): + buttons = [] + for n in a_ModNameList: + m = self.m_ModuleAgregator.GetModule(n) + b = m.GetModuleButtons() + if not b is None or len(b) != 0: + buttons += b + return buttons + + def GetStartKeyboardButtons(self, a_Message, a_UserGroups): + buttons = self.GetButtons(self.m_ChildModuleNameList) + return keyboard.MakeButtons(self.m_Bot, buttons, a_UserGroups) + + def GetInitBDCommands(self): + return [ + access_utils.GetAccessForModuleRequest(self.GetName(), self.m_InitAccess, self.m_InitAccess), + ] + + def GetAccess(self): + return access_utils.GetAccessForModule(self.m_Bot, self.GetName()) + + def GetModuleButtons(self): + return [ + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.START), user_access.AccessMode.VIEW, self.GetAccess()), + ] + + def RegisterHandlers(self): + self.m_Bot.RegisterMessageHandler( + self.m_StartMessageHandler, + bd_item.GetCheckForTextFunc(self.GetButton(ButtonNames.START)) + ) + diff --git a/bot_modules/mod_table_operate.py b/bot_modules/mod_table_operate.py new file mode 100644 index 0000000..0c62eaa --- /dev/null +++ b/bot_modules/mod_table_operate.py @@ -0,0 +1,386 @@ +# -*- coding: utf8 -*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Модуль для редактирования и просмотра таблицы в БД + +from bot_sys import keyboard, user_access, bd_table, bot_bd +from bot_modules import access_utils, mod_simple_message +from template import simple_message, bd_item, bd_item_select, bd_item_view, bd_item_delete, bd_item_add, bd_item_edit + +from enum import Enum +from enum import auto + +class ButtonNames(Enum): + LIST = auto() + ADD = auto() + EDIT = auto() + EDIT_PHOTO = auto() + EDIT_NAME = auto() + EDIT_DESC = auto() + EDIT_ACCESS = auto() + EDIT_DEFAULT_ACCESS = auto() + DEL = auto() + +class Messages(Enum): + SELECT = auto() + ERROR_FIND = auto() + OPEN = auto() + CREATE_NAME = auto() + CREATE_DESC = auto() + CREATE_PHOTO = auto() + SUCCESS_CREATE = auto() + START_EDIT = auto() + SELECT_TO_EDIT = auto() + EDIT_PHOTO = auto() + EDIT_NAME = auto() + EDIT_DESC = auto() + EDIT_ACCESS = auto() + EDIT_DEFAULT_ACCESS = auto() + SUCCESS_EDIT = auto() + SELECT_TO_DELETE = auto() + SUCCESS_DELETE = auto() + +class FSMs(Enum): + CREATE = auto() + EDIT_PHOTO = auto() + EDIT_NAME = auto() + EDIT_DESC = auto() + EDIT_ACCESS = auto() + EDIT_DEFAULT_ACCESS = auto() + +class TableOperateModule(mod_simple_message.SimpleMessageModule): + def __init__(self, a_Table, a_Messages, a_Buttons, a_FSMs, a_ParentModName, a_ChildModName, a_InitAccess, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log): + super().__init__(a_Messages, a_Buttons, a_InitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + self.m_Table = a_Table + self.m_FSMs = a_FSMs + self.m_EditModuleNameList = a_EditModuleNameList + self.m_ChildModName = a_ChildModName + self.m_ParentModName = a_ParentModName + self.m_SelectPrefix = '' + + def GetEditKeyboardButtons(a_Message, a_UserGroups): + return self.GetEditKeyboardButtons(a_Message, a_UserGroups) + self.m_GetEditKeyboardButtonsFunc = GetEditKeyboardButtons + + def GetButtonNameAndKeyValueAndAccess(a_Item): + return self.GetButtonNameAndKeyValueAndAccess(a_Item) + self.m_GetButtonNameAndKeyValueAndAccessFunc = GetButtonNameAndKeyValueAndAccess + + async def PreDelete(a_CallbackQuery, a_Item): + return await self.PreDelete(a_CallbackQuery, a_Item) + self.m_PreDeleteFunc = PreDelete + + async def PostDelete(a_CallbackQuery, a_ItemID): + return await self.PostDelete(a_CallbackQuery, a_ItemID) + self.m_PostDeleteFunc = PostDelete + + def AddBDItemFunc(a_ItemData, a_UserID): + return self.AddBDItemFunc(a_ItemData, a_UserID) + self.m_AddBDItemFunc = AddBDItemFunc + + def GetFSM(self, a_FSMName): + return self.m_FSMs.get(a_FSMName, None) + + def GetInitBDCommands(self): + return super(). GetInitBDCommands() + [ + self.m_Table.GetInitTableRequest(), + ] + + 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()), + ] + return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) + + def GetEditKeyboardButtons(self, a_Message, a_UserGroups): + mod_buttons = keyboard.MakeButtons(self.m_Bot, self.GetButtons(self.m_EditModuleNameList), a_UserGroups) + cur_buttons = [ + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT_PHOTO), user_access.AccessMode.VIEW, self.GetAccess()), + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT_NAME), user_access.AccessMode.ADD, self.GetAccess()), + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT_DESC), user_access.AccessMode.DELETE, self.GetAccess()), + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT_ACCESS), user_access.AccessMode.DELETE, self.GetAccess()), + keyboard.ButtonWithAccess(self.GetButton(ButtonNames.EDIT_DEFAULT_ACCESS), user_access.AccessMode.EDIT, self.GetAccess()), + ] + return mod_buttons + keyboard.MakeButtons(self.m_Bot, cur_buttons, a_UserGroups) + + def GetViewItemInlineKeyboardTemplate(self, a_ItemID): + def GetViewItemInlineKeyboard(a_Message, a_UserGroups): + return self.GetViewItemInlineKeyboard(a_Message, a_UserGroups, a_ItemID) + return GetViewItemInlineKeyboard + + def GetSelectPrefix(self): + return self.m_SelectPrefix + + def GetViewItemInlineKeyboard(self, a_Message, a_UserGroups, a_ItemID): + if not self.m_ChildModName: + return None + child_mod = self.GetModule(self.m_ChildModName) + cur_buttons = [ + keyboard.InlineButtonWithAccess(child_mod.GetButton(ButtonNames.LIST), child_mod.GetSelectPrefix(), a_ItemID, self.GetAccess(), user_access.AccessMode.VIEW), + ] + return keyboard.MakeInlineKeyboardButtons(self.m_Bot, cur_buttons, a_UserGroups) + + def GetButtonNameAndKeyValueAndAccess(self, a_Item): + return \ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.NAME)],\ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.KEY)],\ + a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)] + + def ShowMessageTemplate(self, a_Message, Inline_keyboard_template_func = None): + async def ShowMessage(a_CallbackQuery, a_Item): + msg = a_Message.StaticCopy() + # TODO: добавить поддержку языка в a_MessageName + Inline_keyboard_func = None + item_access = None + if a_Item: + 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(): + lang = str(a_CallbackQuery.from_user.language_code) + msg = msg.GetMessageForLang(lang).StaticCopy() + msg.UpdateDesc(self.m_Table.ReplaceAllFieldTags(msg.GetDesc(), a_Item)) + photo_field = self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.PHOTO) + if photo_field: + msg.UpdatePhotoID(a_Item[photo_field]) + 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)]) + + return simple_message.WorkFuncResult(msg, item_access = item_access, Inline_keyboard_func = Inline_keyboard_func) + return ShowMessage + + # TODO: delete? + def SimpleMessageTemplate(self, a_MessageName : Messages): + async def ShowMessage(a_CallbackQuery, a_Item): + return simple_message.WorkFuncResult(self.GetMessage(a_MessageName)) + return ShowMessage + + async def PreDelete(self, a_CallbackQuery, a_Item): + if len(a_Item) < self.m_Table.GetFieldsCount(): + return simple_message.WorkFuncResult(error_find_proj_message) + access = a_Item[self.m_Table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)] + return simple_message.WorkFuncResult(self.GetMessage(Messages.SUCCESS_DELETE), None, item_access = access) + + async def PostDelete(self, a_CallbackQuery, a_ItemID): + self.m_Log.Success(f'Задача №{a_ItemID} была удалена пользователем {a_CallbackQuery.from_user.id}.') + #TODO: удалить вложенные + self.OnChange() + return simple_message.WorkFuncResult(self.GetMessage(Messages.SUCCESS_DELETE)) + + def AddBDItemFunc(self, a_ItemData, a_UserID): + table_name = self.m_Table.GetName() + name_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.NAME) + photo_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PHOTO) + desc_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DESC) + access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.ACCESS) + create_datetime_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.CREATE_DATE) + parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + + res, error = None, None + def_access = access_utils.GetItemDefaultAccessForModule(self.m_Bot, self.GetName()) + #TODO сделать список полей, чтобы запрос генерировался автоматически. + if parent_id_field: + res, error = self.m_Bot.SQLRequest(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', + commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], def_access + f";{a_UserID}=+", a_ItemData[parent_id_field])) + else: + res, error = self.m_Bot.SQLRequest(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', + commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], def_access + f";{a_UserID}=+")) + + self.OnChange() + if error: + self.m_Log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {def_access}).') + else: + self.m_Log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {def_access}).') + + return res, error + + def RegisterSelect(self, a_ButtonName, access_mode, only_parent = False): + a_Prefix = None + if self.m_ParentModName: + parent_mod = self.GetModule(self.m_ParentModName) + a_Prefix = parent_mod.RegisterSelect(a_ButtonName, access_mode, only_parent = False) + if not only_parent: + a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(self.m_Bot, \ + a_Prefix, \ + self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID), \ + self.m_Table.GetName(), \ + self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY), \ + self.m_GetButtonNameAndKeyValueAndAccessFunc, \ + self.GetMessage(Messages.SELECT), \ + self.m_GetAccessFunc,\ + access_mode = access_mode\ + ) + else: + if not only_parent: + a_PrefixBase = a_ButtonName.GetDesc() + a_Prefix = bd_item_select.FirstSelectBDItemRegisterHandlers(self.m_Bot, \ + a_PrefixBase, \ + a_ButtonName, \ + self.m_Table.GetName(), \ + self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY), \ + self.m_GetButtonNameAndKeyValueAndAccessFunc, \ + self.GetMessage(Messages.SELECT), \ + self.m_GetAccessFunc,\ + access_mode = access_mode\ + ) + return a_Prefix + + def RegisterHandlers(self): + super().RegisterHandlers() + table_name = self.m_Table.GetName() + key_name = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.KEY) + 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) + access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.ACCESS) + def_access_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.DEFAULT_ACCESS) + parent_id_field = self.m_Table.GetFieldNameByDestiny(bd_table.TableFieldDestiny.PARENT_ID) + + parent_table_name = None + parent_key_name = None + 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) + + def GetViewItemInlineKeyboardTemplate(a_ItemID): + return self.GetViewItemInlineKeyboardTemplate(a_ItemID) + + GetButtonNameAndKeyValueAndAccess = self.m_GetButtonNameAndKeyValueAndAccessFunc + GetAccess = self.m_GetAccessFunc + + defaul_keyboard_func = self.m_GetStartKeyboardButtonsFunc + + # Список + a_ButtonName = self.GetButton(ButtonNames.LIST) + if a_ButtonName: + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.VIEW, only_parent = True) + if a_Prefix: + bd_item_view.LastSelectAndShowBDItemRegisterHandlers(self.m_Bot, \ + a_Prefix,\ + parent_id_field, \ + table_name,\ + key_name, \ + self.ShowMessageTemplate(self.GetMessage(Messages.OPEN), GetViewItemInlineKeyboardTemplate), \ + GetButtonNameAndKeyValueAndAccess, \ + self.GetMessage(Messages.SELECT), \ + GetAccess, \ + defaul_keyboard_func, \ + access_mode = user_access.AccessMode.VIEW\ + ) + else: + bd_item_view.FirstSelectAndShowBDItemRegisterHandlers(self.m_Bot, \ + a_ButtonName, \ + table_name, \ + key_name, \ + self.ShowMessageTemplate(self.GetMessage(Messages.OPEN), GetViewItemInlineKeyboardTemplate), \ + GetButtonNameAndKeyValueAndAccess, \ + self.GetMessage(Messages.SELECT), \ + GetAccess, \ + defaul_keyboard_func\ + ) + self.m_SelectPrefix = a_Prefix + + # Удаление + a_ButtonName = self.GetButton(ButtonNames.DEL) + if a_ButtonName: + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.DELETE) + bd_item_delete.DeleteBDItemRegisterHandlers(self.m_Bot, \ + a_Prefix, \ + table_name, \ + key_name, \ + self.m_PreDeleteFunc, \ + self.m_PostDeleteFunc, \ + GetAccess, \ + defaul_keyboard_func\ + ) + + # Добавление + a_ButtonName = self.GetButton(ButtonNames.ADD) + if a_ButtonName: + a_Prefix = self.RegisterSelect(a_ButtonName, user_access.AccessMode.ADD, only_parent = True) + + check_func = bd_item.GetCheckForTextFunc(a_ButtonName) + if a_Prefix: + check_func = bd_item.GetCheckForPrefixFunc(a_Prefix) + + bd_item_add.AddBDItem3RegisterHandlers(self.m_Bot, \ + check_func, \ + self.GetFSM(FSMs.CREATE), \ + self.GetFSM(FSMs.CREATE).name,\ + self.GetFSM(FSMs.CREATE).desc, \ + self.GetFSM(FSMs.CREATE).photo,\ + self.m_AddBDItemFunc, \ + self.ShowMessageTemplate(self.GetMessage(Messages.CREATE_NAME)), \ + self.ShowMessageTemplate(self.GetMessage(Messages.CREATE_DESC)), \ + self.ShowMessageTemplate(self.GetMessage(Messages.CREATE_PHOTO)), \ + self.ShowMessageTemplate(self.GetMessage(Messages.SUCCESS_CREATE)), \ + a_Prefix,\ + parent_table_name, \ + parent_key_name, \ + name_field, \ + desc_field, \ + photo_field, \ + GetButtonNameAndKeyValueAndAccess, \ + GetAccess, \ + self.m_GetStartKeyboardButtonsFunc\ + ) + + # Редактирование + edit_keyboard_func = self.m_GetEditKeyboardButtonsFunc + def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): + if not a_ButtonName: + return + + def OnChange(): + return self.OnChange() + + a_Prefix = self.RegisterSelect(a_ButtonName, a_AccessMode, only_parent = True) + check_func = bd_item.GetCheckForTextFunc(a_ButtonName) + if a_Prefix: + check_func = bd_item.GetCheckForPrefixFunc(a_Prefix) + #print(a_ButtonName, a_Prefix, check_func) + bd_item_edit.EditBDItemRegisterHandlers(self.m_Bot, \ + a_Prefix, \ + a_FSM, \ + check_func, \ + self.GetMessage(Messages.SELECT_TO_EDIT), \ + self.ShowMessageTemplate(a_EditMessage), \ + self.ShowMessageTemplate(self.GetMessage(Messages.SUCCESS_EDIT)), \ + table_name, \ + key_name, \ + parent_id_field, \ + a_FieldName, \ + GetButtonNameAndKeyValueAndAccess, \ + GetAccess, \ + edit_keyboard_func, \ + OnChange,\ + access_mode = a_AccessMode, \ + field_type = a_FieldType\ + ) + + a_ButtonName = self.GetButton(ButtonNames.EDIT) + if a_ButtonName: + self.m_Bot.RegisterMessageHandler(\ + simple_message.InfoMessageTemplate(\ + self.m_Bot,\ + self.GetMessage(Messages.START_EDIT),\ + edit_keyboard_func,\ + None,\ + GetAccess,\ + access_mode = user_access.AccessMode.EDIT),\ + bd_item.GetCheckForTextFunc(a_ButtonName)\ + ) + + RegisterEdit(self.GetButton(ButtonNames.EDIT_NAME), self.GetFSM(FSMs.EDIT_NAME), self.GetMessage(Messages.EDIT_NAME), name_field, bd_item.FieldType.text) + RegisterEdit(self.GetButton(ButtonNames.EDIT_DESC), self.GetFSM(FSMs.EDIT_DESC), self.GetMessage(Messages.EDIT_DESC), desc_field, bd_item.FieldType.text) + RegisterEdit(self.GetButton(ButtonNames.EDIT_PHOTO), self.GetFSM(FSMs.EDIT_PHOTO), self.GetMessage(Messages.EDIT_PHOTO), photo_field, bd_item.FieldType.photo) + RegisterEdit(self.GetButton(ButtonNames.EDIT_ACCESS), self.GetFSM(FSMs.EDIT_ACCESS), self.GetMessage(Messages.EDIT_ACCESS), access_field, bd_item.FieldType.text) + RegisterEdit(self.GetButton(ButtonNames.EDIT_DEFAULT_ACCESS), self.GetFSM(FSMs.EDIT_DEFAULT_ACCESS), self.GetMessage(Messages.EDIT_DEFAULT_ACCESS), def_access_field, bd_item.FieldType.text) + + def OnChange(self): + pass diff --git a/bot_modules/needs.py b/bot_modules/needs.py index e1245e9..15625a3 100644 --- a/bot_modules/needs.py +++ b/bot_modules/needs.py @@ -3,16 +3,11 @@ # Потребности -from bot_sys import bot_bd, log, keyboard, user_access -from bot_modules import start, access, groups, projects, tasks, comments -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add, bd_item_select - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table +from bot_modules import mod_table_operate, mod_simple_message from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateNeed(StatesGroup): name = State() @@ -20,19 +15,15 @@ class FSMCreateNeed(StatesGroup): photo = State() class FSMEditNeedPhotoItem(StatesGroup): - item_id = State() item_field = State() class FSMEditNeedNameItem(StatesGroup): - item_id = State() item_field = State() class FSMEditNeedDescItem(StatesGroup): - item_id = State() item_field = State() class FSMEditNeedAccessItem(StatesGroup): - item_id = State() item_field = State() # --------------------------------------------------------- # БД @@ -47,340 +38,117 @@ access_field = 'needAccess' create_datetime_field = 'needCreateDateTime' parent_id_field = 'taskID' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {name_field} TEXT, - {desc_field} TEXT, - {photo_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - {parent_id_field} INTEGER - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=va', '{user_access.user_access_group_new}=va');" -] - -select_needs_prefix = '' +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.STR), + 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), + bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT), + ]) + +init_access = f'{user_access.user_access_group_new}=va' + +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateNeed, + mod_table_operate.FSMs.EDIT_NAME: FSMEditNeedNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditNeedDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditNeedPhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditNeedAccessItem, + } # --------------------------------------------------------- -# Сообщения - -needs_button_name = "👉 Потребности" -base_need_message = f''' -{needs_button_name} - -''' - -list_need_button_name = "📃 Список потребностей" -select_need_message = ''' +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение у потребности", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название у потребности", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание у потребности", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите потребность: -''' - -error_find_proj_message = ''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' ❌ Ошибка, потребность не найдена -''' - -need_open_message = f''' +''', + mod_table_operate.Messages.OPEN: f''' Потребность: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''' - -# Создание потребностей - -add_need_button_name = "☑ Добавить потребность" -need_create_name_message = ''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' Создание потребности. Шаг №1 Введите название потребности: -''' - -need_create_desc_message = ''' +''', + mod_table_operate.Messages.CREATE_DESC: ''' Создание потребности. Шаг №2 Введите описание потребности: -''' - -need_create_photo_message = ''' +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' Создание потребности. Шаг №3 Загрузите обложку для потребности (Фото): Она будет отображаться в её описании. -''' - -need_success_create_message = '''✅ Потребность успешно добавлена!''' - -# Редактирование потребностей. - -edit_need_button_name = "🛠 Редактировать потребность" -need_start_edit_message= ''' +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Потребность успешно добавлена!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''' - -need_select_to_edit_message = ''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' Выберите потребность, которую вы хотите отредактировать. -''' - -edit_need_photo_button_name = "☐ Изменить изображение у потребности" -need_edit_photo_message = ''' +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' Загрузите новую обложку для потребности (Фото): Она будет отображаться в её описании. -''' - -edit_need_name_button_name = "≂ Изменить название у потребности" -need_edit_name_message = f''' +''', + mod_table_operate.Messages.EDIT_NAME: f''' Текущее название потребности: #{name_field} Введите новое название потребности: -''' - -edit_need_desc_button_name = "𝌴 Изменить описание у потребности" -need_edit_desc_message = f''' +''', + mod_table_operate.Messages.EDIT_DESC: f''' Текущее описание потребности: #{desc_field} Введите новое описание потребности: -''' - -edit_need_access_button_name = "✋ Изменить доступ к потребности" -need_edit_access_message = f''' +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' Текущий доступ к потребности: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''' - -need_success_edit_message = '''✅ Потребность успешно отредактирована!''' - -# Удаление потребностей - -del_need_button_name = "❌ Удалить потребность" -need_select_to_delete_message = ''' +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Потребность успешно отредактирован!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' Выберите потребность, которую вы хотите удалить. -Все сообщения в этой потребности так же будут удалены! -''' - -need_success_delete_message = '''✅ Потребность успешно удалена!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditNeedKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_need_photo_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_need_name_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_need_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_need_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetStartNeedKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_need_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_need_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_need_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_need_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, projects, tasks, comments] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetViewItemInlineKeyboardTemplate(a_ItemID): - def GetViewItemInlineKeyboard(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.InlineButton(comments.list_comment_button_name, comments.select_comments_prefix, a_ItemID, GetAccess(), user_access.AccessMode.VIEW), - ] - return keyboard.MakeInlineKeyboard(cur_buttons, a_UserGroups) - return GetViewItemInlineKeyboard -# --------------------------------------------------------- -# Обработка сообщений - -# стартовое сообщение -async def NeedsOpen(a_Message : types.message, state = None): - return simple_message.WorkFuncResult(base_need_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # needName needID needAccess - return a_Item[1], a_Item[0], a_Item[4] - -def ShowMessageTemplate(a_StringMessage, keyboard_template_func = None): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = a_StringMessage.\ - replace(f'#{name_field}', a_Item[1]).\ - replace(f'#{desc_field}', a_Item[2]).\ - replace(f'#{create_datetime_field}', a_Item[5]).\ - replace(f'#{access_field}', a_Item[4]) - keyboard_func = None - if keyboard_template_func: - keyboard_func = keyboard_template_func(a_Item[0]) - return simple_message.WorkFuncResult(msg, photo_id = a_Item[3], item_access = a_Item[4], keyboard_func = keyboard_func) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# Удаление потребностей - -async def NeedPreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[4] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def NeedPostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Потребность №{a_ItemID} была удалена пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - return simple_message.WorkFuncResult(need_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных потребностей - -def AddBDItemFunc(a_ItemData, a_UserID): - print(a_ItemData) - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+", a_ItemData[parent_id_field])) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - return res, error - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(needs_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartNeedKeyboardButtons - def RegisterSelectParent(a_ButtonName, access_mode): - a_PrefixBase = a_ButtonName - a_Prefix = bd_item_select.FirstSelectBDItemRegisterHandlers(dp, \ - a_PrefixBase, \ - a_ButtonName, \ - projects.table_name, \ - projects.key_name, \ - projects.GetButtonNameAndKeyValueAndAccess, \ - projects.select_project_message, \ - projects.GetAccess, \ - access_mode = access_mode\ - ) - a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(dp, \ - a_Prefix, \ - tasks.parent_id_field, \ - tasks.table_name, \ - tasks.key_name, \ - tasks.GetButtonNameAndKeyValueAndAccess, \ - tasks.select_task_message, \ - tasks.GetAccess, \ - access_mode = access_mode\ - ) - return a_Prefix - - - # Стартовое сообщение - dp.register_message_handler(simple_message.SimpleMessageTemplate(NeedsOpen, defaul_keyboard_func, GetAccess), text = needs_button_name) - - # Список потребностей - a_Prefix = RegisterSelectParent(list_need_button_name, user_access.AccessMode.VIEW) - bd_item_view.LastSelectAndShowBDItemRegisterHandlers(dp, \ - a_Prefix, parent_id_field, \ - table_name, key_name, \ - ShowMessageTemplate(need_open_message, GetViewItemInlineKeyboardTemplate), \ - GetButtonNameAndKeyValueAndAccess, \ - select_need_message, \ - GetAccess, \ - defaul_keyboard_func, \ - access_mode = user_access.AccessMode.VIEW\ - ) - global select_needs_prefix - select_needs_prefix = a_Prefix - - # Удаление потребностей - a_Prefix = RegisterSelectParent(del_need_button_name, user_access.AccessMode.DELETE) - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - a_Prefix, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - table_name, \ - key_name, \ - parent_id_field, \ - NeedPreDelete, \ - NeedPostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_need_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление потребностей - a_Prefix = RegisterSelectParent(add_need_button_name, user_access.AccessMode.ADD) - bd_item_add.AddBDItem3RegisterHandlers(dp, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - FSMCreateNeed, \ - FSMCreateNeed.name,\ - FSMCreateNeed.desc, \ - FSMCreateNeed.photo,\ - AddBDItemFunc, \ - SimpleMessageTemplate(need_create_name_message), \ - SimpleMessageTemplate(need_create_desc_message), \ - SimpleMessageTemplate(need_create_photo_message), \ - SimpleMessageTemplate(need_success_create_message), \ - a_Prefix,\ - tasks.table_name, \ - tasks.key_name, \ - name_field, \ - desc_field, \ - photo_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartNeedKeyboardButtons\ - ) - - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - a_Prefix = RegisterSelectParent(a_ButtonName, a_AccessMode) - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - a_Prefix, \ - a_FSM, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - need_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(need_success_edit_message), \ - table_name, \ - key_name, \ - parent_id_field, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) +Все комментарии в этой потребности так же будут удалены! +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Потребность успешно удалёна!''', +} - # Редактирование потребностей - edit_keyboard_func = GetEditNeedKeyboardButtons - dp.register_message_handler(simple_message.InfoMessageTemplate(need_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_need_button_name) +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) - RegisterEdit(edit_need_photo_button_name, FSMEditNeedPhotoItem, need_edit_photo_message, photo_field, bd_item.FieldType.photo) - RegisterEdit(edit_need_name_button_name, FSMEditNeedNameItem, need_edit_name_message, name_field, bd_item.FieldType.text) - RegisterEdit(edit_need_desc_button_name, FSMEditNeedDescItem, need_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_need_access_button_name, FSMEditNeedAccessItem, need_edit_access_message, access_field, bd_item.FieldType.text) + def GetName(self): + return module_name diff --git a/bot_modules/profile.py b/bot_modules/profile.py index 0b027f2..4062b38 100644 --- a/bot_modules/profile.py +++ b/bot_modules/profile.py @@ -3,12 +3,9 @@ # Профиль пользователя -from bot_sys import bot_bd, log, config, keyboard, user_access, user_messages -from bot_modules import start, access, groups -from template import simple_message - -from aiogram import types -from aiogram.dispatcher import Dispatcher +from bot_sys import user_access, bot_bd, bd_table +from bot_modules import mod_simple_message, groups, access, access_utils, groups_utils +from template import bd_item, simple_message # --------------------------------------------------------- # БД @@ -24,30 +21,23 @@ language_code_field = 'userLanguageCode' access_field = 'userAccess' create_datetime_field = 'createDateTime' -init_bd_cmds = [f"""CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER, - {name_field} TEXT, - {name1_field} TEXT, - {name2_field} TEXT, - {is_bot_field} TEXT, - {language_code_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - UNIQUE({key_name}) -);""", -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=+', '{user_access.user_access_group_new}=+');" -] - -def MSG(a_MessageName, a_MessageDesc): - def UpdateMSG(a_Message : user_messages.Message): - print(a_Message.m_MessageName, a_Message.m_MessageDesc) - globals()[a_Message.m_MessageName] = a_Message - user_messages.MSG(a_MessageName, a_MessageDesc, UpdateMSG, log.GetTimeNow()) - -# --------------------------------------------------------- -# Сообщения - -MSG('profile_message', f''' +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(name1_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), + bd_table.TableField(name2_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), + bd_table.TableField(is_bot_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), + bd_table.TableField(language_code_field, bd_table.TableFieldDestiny.DESC, bd_table.TableFieldType.STR), + 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), + ]) + +button_names = { + mod_simple_message.ButtonNames.START: "📰 Профиль", +} + +messages = { + mod_simple_message.Messages.START: f''' 📰 Профиль: ID: #{key_name} @@ -56,73 +46,53 @@ MSG('profile_message', f''' Имя2: #{name2_field} Код языка: #{language_code_field} Дата добавления: #{create_datetime_field} -''') +''', +} -user_profile_button_name = "📰 Профиль" +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_Log): + super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) -def GetStartKeyboardButtons(a_Message, a_UserGroups): - mods = [start] - return keyboard.MakeKeyboardForMods(mods, a_UserGroups) + def GetInitBDCommands(self): + return super(). GetInitBDCommands() + [ + table.GetInitTableRequest(), + ] + + def GetName(self): + return module_name + + # Основной обработчик главного сообщения + async def StartMessageHandler(self, a_Message, state = None): + user_info = GetUserInfo(self.m_Bot, a_Message.from_user.id) + lang = str(a_Message.from_user.language_code) + if not user_info is None: + msg = self.GetMessage(mod_simple_message.Messages.START) + msg = msg.GetMessageForLang(lang).StaticCopy() + msg.UpdateDesc(table.ReplaceAllFieldTags(msg.GetDesc(), user_info)) + return simple_message.WorkFuncResult(msg, item_access = str(user_info[table.GetFieldIDByDestiny(bd_table.TableFieldDestiny.ACCESS)])) + return await super().StartMessageHandler(a_Message, state) -# --------------------------------------------------------- -# Обработка сообщений - -async def ProfileOpen(a_Message, state = None): - user_info = GetUserInfo(a_Message.from_user.id) - msg = profile_message - if not user_info is None: - msg = str(msg).\ - replace(f'#{key_name}', str(user_info[0])).\ - replace(f'#{name_field}', str(user_info[1])).\ - replace(f'#{name1_field}', str(user_info[2])).\ - replace(f'#{name2_field}', str(user_info[3])).\ - replace(f'#{is_bot_field}', str(user_info[4])).\ - replace(f'#{language_code_field}', str(user_info[5])).\ - replace(f'#{access_field}', str(user_info[6])).\ - replace(f'#{create_datetime_field}', str(user_info[7])) - return simple_message.WorkFuncResult(msg, item_access = str(user_info[6])) - return simple_message.WorkFuncResult(msg) -# --------------------------------------------------------- # Работа с базой данных пользователей # Добавление пользователя, если он уже есть, то игнорируем -def AddUser(a_UserID, a_UserName, a_UserName1, a_UserName2, a_UserIsBot, a_LanguageCode): - bot_bd.SQLRequestToBD(f"INSERT OR IGNORE INTO users ({key_name}, {name_field}, {name1_field}, {name2_field}, {is_bot_field}, {language_code_field}, {access_field}, {create_datetime_field}) VALUES (?, ?, ?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()});", - commit=True, param = (a_UserID, a_UserName, a_UserName1, a_UserName2, a_UserIsBot, a_LanguageCode, access.GetItemDefaultAccessForModule(module_name))) +def AddUser(a_Bot, a_UserID, a_UserName, a_UserName1, a_UserName2, a_UserIsBot, a_LanguageCode): + a_Bot.SQLRequest(f"INSERT OR IGNORE INTO users ({key_name}, {name_field}, {name1_field}, {name2_field}, {is_bot_field}, {language_code_field}, {access_field}, {create_datetime_field}) VALUES (?, ?, ?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()});", + commit=True, param = (a_UserID, a_UserName, a_UserName1, a_UserName2, a_UserIsBot, a_LanguageCode, access_utils.GetItemDefaultAccessForModule(a_Bot, module_name))) - user_groups = groups.GetUserGroupData(a_UserID) + user_groups = groups_utils.GetUserGroupData(a_Bot, a_UserID) # Если пользователь не состоит ни в одной группе, то добавляем его в группу user_access.user_access_group_new if len(user_groups.group_names_list) == 0: - new_group_id = bot_bd.SQLRequestToBD(f'SELECT {groups.key_table_groups_name} FROM {groups.table_groups_name} WHERE {groups.name_table_groups_field} = ?', + new_group_id = a_Bot.SQLRequest(f'SELECT {groups.key_table_groups_name} FROM {groups.table_groups_name} WHERE {groups.name_table_groups_field} = ?', param = [user_access.user_access_group_new]) if new_group_id and new_group_id[0]: - bot_bd.SQLRequestToBD(f"INSERT OR IGNORE INTO {groups.table_user_in_groups_name} ({groups.user_id_field}, {groups.key_table_groups_name}, {groups.access_field}, {groups.create_datetime_field}) VALUES (?, ?, ?, {bot_bd.GetBDDateTimeNow()});", - commit=True, param = (a_UserID, new_group_id[0][0], access.GetItemDefaultAccessForModule(module_name))) + a_Bot.SQLRequest(f"INSERT OR IGNORE INTO {groups.table_user_in_groups_name} ({groups.user_id_field}, {groups.key_table_groups_name}, {groups.access_field}, {groups.create_datetime_field}) VALUES (?, ?, ?, {bot_bd.GetBDDateTimeNow()});", + commit=True, param = (a_UserID, new_group_id[0][0], access_utils.GetItemDefaultAccessForModule(a_Bot, module_name))) -def GetUserInfo(a_UserID): - user_info = bot_bd.SQLRequestToBD('SELECT * FROM users WHERE user_id = ?', param = [a_UserID]) +def GetUserInfo(a_Bot, a_UserID): + user_info = a_Bot.SQLRequest('SELECT * FROM users WHERE user_id = ?', param = [a_UserID]) if len(user_info) != 0: return user_info[0] return None - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(user_profile_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - dp.register_message_handler(simple_message.SimpleMessageTemplate(ProfileOpen, GetStartKeyboardButtons, GetAccess), text = user_profile_button_name) diff --git a/bot_modules/projects.py b/bot_modules/projects.py index 74c5135..6b82cfa 100644 --- a/bot_modules/projects.py +++ b/bot_modules/projects.py @@ -3,16 +3,11 @@ # Проекты -from bot_sys import bot_bd, log, keyboard, user_access, user_messages -from bot_modules import start, access, groups, tasks, needs, comments -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table +from bot_modules import mod_table_operate, mod_simple_message from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateProject(StatesGroup): name = State() @@ -25,7 +20,7 @@ class FSMEditProjectPhotoItem(StatesGroup): class FSMEditProjectNameItem(StatesGroup): item_field = State() -class FSMEditProjectDeskItem(StatesGroup): +class FSMEditProjectDescItem(StatesGroup): item_field = State() class FSMEditProjectAccessItem(StatesGroup): @@ -42,314 +37,123 @@ photo_field = 'projectPhoto' access_field = 'projectAccess' create_datetime_field = 'projectCreateDateTime' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {name_field} TEXT, - {desc_field} TEXT, - {photo_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=va', '{user_access.user_access_group_new}=va');" -] - -def MSG(a_MessageName, a_MessageDesc): - def UpdateMSG(a_Message : user_messages.Message): - print(a_Message.m_MessageName, a_Message.m_MessageDesc) - globals()[a_Message.m_MessageName] = a_Message - user_messages.MSG(a_MessageName, a_MessageDesc, UpdateMSG, log.GetTimeNow()) +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.STR), + 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}=va' + +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateProject, + mod_table_operate.FSMs.EDIT_NAME: FSMEditProjectNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditProjectDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditProjectPhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditProjectAccessItem, + } # --------------------------------------------------------- -# Сообщения - -projects_button_name = "🟥 Проекты" -MSG('base_project_message',''' -🟥 Проекты - -''') - -list_project_button_name = "📃 Список проектов" -MSG('select_project_message',''' +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение в проекте", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название в проекте", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание в проекте", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите проект: -''') - -MSG('error_find_proj_message',''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' ❌ Ошибка, проект не найден -''') - -MSG('project_open_message',f''' +''', + mod_table_operate.Messages.OPEN: f''' Проект: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''') - -# Создание проекта - -add_project_button_name = "✅ Добавить проект" -MSG('project_create_name_message',''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' Создание проекта. Шаг №1 Введите название проекта: -''') - -MSG('project_create_desc_message',''' +''', + mod_table_operate.Messages.CREATE_DESC: ''' Создание проекта. Шаг №2 Введите описание проекта: -''') - -MSG('project_create_photo_message',''' +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' Создание проекта. Шаг №3 Загрузите обложку для проекта (Фото): Она будет отображаться в его описании. -''') - -MSG('project_success_create_message','''✅ Проект успешно добавлен!''') - -# Редактирование проекта. - -edit_project_button_name = "🛠 Редактировать проект" -MSG('project_start_edit_message', ''' +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Проект успешно добавлен!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''') - -MSG('project_select_to_edit_message',''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' Выберите проект, который вы хотите отредактировать. -''') - -edit_project_photo_button_name = "☐ Изменить изображение в проекте" -MSG('project_edit_photo_message',''' +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' Загрузите новую обложку для проекта (Фото): Она будет отображаться в его описании. -''') - -edit_project_name_button_name = "≂ Изменить название в проекте" -MSG('project_edit_name_message',f''' +''', + mod_table_operate.Messages.EDIT_NAME: f''' Текущее название проекта: #{name_field} Введите новое название проекта: -''') - -edit_project_desc_button_name = "𝌴 Изменить описание в проекте" -MSG('project_edit_desc_message',f''' +''', + mod_table_operate.Messages.EDIT_DESC: f''' Текущее описание проекта: #{desc_field} Введите новое описание проекта: -''') - -edit_project_access_button_name = "✋ Изменить доступ к проекту" -MSG('project_edit_access_message',f''' +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' Текущий доступ к проекту: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''') - -MSG('project_success_edit_message','''✅ Проект успешно отредактирован!''') - -# Удаление проекта - -del_project_button_name = "❌ Удалить проект" -MSG('project_select_to_delete_message',''' +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Проект успешно отредактирован!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' Выберите проект, который вы хотите удалить. Все задачи и потребности в этом проекте так же будут удалены! -''') - -MSG('project_success_delete_message','''✅ Проект успешно удалён!''') - -# --------------------------------------------------------- -# Работа с кнопками +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Проект успешно удалён!''', +} -def GetEditProjectKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_project_photo_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_project_name_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_project_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_project_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) -def GetStartProjectKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_project_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_project_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_project_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_project_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, tasks, needs, comments] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) + def GetName(self): + return module_name -def GetViewItemInlineKeyboardTemplate(a_ItemID): - def GetViewItemInlineKeyboard(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.InlineButton(tasks.list_task_button_name, tasks.select_tasks_prefix, a_ItemID, GetAccess(), user_access.AccessMode.VIEW), + def GetModuleButtons(self): + return super().GetModuleButtons() + [ + keyboard.ButtonWithAccess(self.GetButton(mod_table_operate.ButtonNames.LIST), user_access.AccessMode.VIEW, self.GetAccess()), ] - return keyboard.MakeInlineKeyboard(cur_buttons, a_UserGroups) - return GetViewItemInlineKeyboard - -# --------------------------------------------------------- -# Обработка сообщений - -# стартовое сообщение -async def ProjectsOpen(a_Message : types.message, state = None): - return simple_message.WorkFuncResult(base_project_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # projectName projectID projectAccess - return a_Item[1], a_Item[0], a_Item[4] - -def ShowMessageTemplate(a_StringMessage, keyboard_template_func = None): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = str(a_StringMessage).\ - replace(f'#{name_field}', a_Item[1]).\ - replace(f'#{desc_field}', a_Item[2]).\ - replace(f'#{create_datetime_field}', a_Item[5]).\ - replace(f'#{access_field}', a_Item[4]) - keyboard_func = None - if keyboard_template_func: - keyboard_func = keyboard_template_func(a_Item[0]) - return simple_message.WorkFuncResult(msg, photo_id = a_Item[3], item_access = a_Item[4], keyboard_func = keyboard_func) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# Удаление проекта - -async def ProjectPreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[4] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def ProjectPostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Проект №{a_ItemID} был удалён пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - return simple_message.WorkFuncResult(project_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных проектов - -def AddBDItemFunc(a_ItemData, a_UserID): - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+")) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - return res, error - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [ - keyboard.ButtonWithAccess(projects_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(list_project_button_name, user_access.AccessMode.VIEW, GetAccess()), - ] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartProjectKeyboardButtons - - # Список проектов - dp.register_message_handler(simple_message.SimpleMessageTemplate(ProjectsOpen, defaul_keyboard_func, GetAccess), text = projects_button_name) - bd_item_view.FirstSelectAndShowBDItemRegisterHandlers(dp, \ - list_project_button_name, \ - table_name, \ - key_name, \ - ShowMessageTemplate(project_open_message, GetViewItemInlineKeyboardTemplate), \ - GetButtonNameAndKeyValueAndAccess, \ - select_project_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Удаление проекта - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - None, \ - bd_item.GetCheckForTextFunc(del_project_button_name), \ - table_name, \ - key_name, \ - None, \ - ProjectPreDelete, \ - ProjectPostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_project_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление проекта - bd_item_add.AddBDItem3RegisterHandlers(dp, \ - bd_item.GetCheckForTextFunc(add_project_button_name), \ - FSMCreateProject,\ - FSMCreateProject.name,\ - FSMCreateProject.desc, \ - FSMCreateProject.photo,\ - AddBDItemFunc, \ - SimpleMessageTemplate(project_create_name_message), \ - SimpleMessageTemplate(project_create_desc_message), \ - SimpleMessageTemplate(project_create_photo_message), \ - SimpleMessageTemplate(project_success_create_message), \ - None,\ - None, \ - None, \ - name_field, \ - desc_field, \ - photo_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartProjectKeyboardButtons\ - ) - - # Редактирование проекта - edit_keyboard_func = GetEditProjectKeyboardButtons - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - None, \ - a_FSM, \ - bd_item.GetCheckForTextFunc(a_ButtonName), \ - project_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(project_success_edit_message), \ - table_name, \ - key_name, \ - None, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) - dp.register_message_handler(simple_message.InfoMessageTemplate(project_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_project_button_name) - RegisterEdit(edit_project_photo_button_name, FSMEditProjectPhotoItem, project_edit_photo_message, photo_field, bd_item.FieldType.photo) - RegisterEdit(edit_project_name_button_name, FSMEditProjectNameItem, project_edit_name_message, name_field, bd_item.FieldType.text) - RegisterEdit(edit_project_desc_button_name, FSMEditProjectDeskItem, project_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_project_access_button_name, FSMEditProjectAccessItem, project_edit_access_message, access_field, bd_item.FieldType.text) diff --git a/bot_modules/start.py b/bot_modules/start.py index 52e77fe..d4012c3 100644 --- a/bot_modules/start.py +++ b/bot_modules/start.py @@ -3,76 +3,50 @@ # Стартовое меню -from bot_sys import log, config, keyboard, user_access, user_messages -from bot_modules import profile, projects, groups, access, backup, languages -from template import simple_message +from bot_sys import user_access +from bot_modules import mod_simple_message, profile +from template import bd_item -from aiogram.dispatcher import Dispatcher - -def MSG(a_MessageName, a_MessageDesc): - def UpdateMSG(a_Message : user_messages.Message): - print(a_Message.m_MessageName, a_Message.m_MessageDesc) - globals()[a_Message.m_MessageName] = a_Message - user_messages.MSG(a_MessageName, a_MessageDesc, UpdateMSG, log.GetTimeNow()) - -# --------------------------------------------------------- -# БД module_name = 'start' -init_bd_cmds = [ -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_all}=+', '{user_access.user_access_group_all}=+');" -] +button_names = { + mod_simple_message.ButtonNames.START: "☰ Главное меню", +} -# --------------------------------------------------------- -# Сообщения - -MSG('start_message', ''' +messages = { + mod_simple_message.Messages.START: f''' Добро пожаловать! -Выберите возможные действия на кнопках ниже ⌨''' -) - -start_menu_button_name = "☰ Главное меню" - -# --------------------------------------------------------- -# Работа с кнопками - -def GetStartKeyboardButtons(a_Message, a_UserGroups): - mods = [profile, projects, groups, access, backup, languages] - return keyboard.MakeKeyboardForMods(mods, a_UserGroups) - -# --------------------------------------------------------- -# Обработка сообщений - -# Первичное привестивие -async def StartMenu(a_Message, state = None): - user_id = str(a_Message.from_user.id) - user_name = str(a_Message.from_user.username) - first_name = str(a_Message.from_user.first_name) - last_name = str(a_Message.from_user.last_name) - is_bot = str(a_Message.from_user.is_bot) - language_code = str(a_Message.from_user.language_code) - profile.AddUser(user_id, user_name, first_name, last_name, is_bot, language_code) - log.Info(f'Пользователь {user_id} {user_name} авторизовался в боте. Полные данные {a_Message.from_user}.') - return simple_message.WorkFuncResult(start_message) - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Имена доступных кнопок -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(start_menu_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - dp.register_message_handler(simple_message.SimpleMessageTemplate(StartMenu, GetStartKeyboardButtons, GetAccess), commands = ['start']) - dp.register_message_handler(simple_message.SimpleMessageTemplate(StartMenu, GetStartKeyboardButtons, GetAccess), text = start_menu_button_name) +Выберите возможные действия на кнопках ниже ⌨''', +} + +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_Log): + super().__init__(messages, button_names, init_access, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) + + def GetName(self): + return module_name + + # Основной обработчик главного сообщения + async def StartMessageHandler(self, a_Message, state = None): + user_id = str(a_Message.from_user.id) + user_name = str(a_Message.from_user.username) + first_name = str(a_Message.from_user.first_name) + last_name = str(a_Message.from_user.last_name) + is_bot = str(a_Message.from_user.is_bot) + language_code = str(a_Message.from_user.language_code) + profile.AddUser(self.m_Bot, user_id, user_name, first_name, last_name, is_bot, language_code) + self.m_Log.Info(f'Пользователь {user_id} {user_name} авторизовался в боте. Полные данные {a_Message.from_user}.') + return await super().StartMessageHandler(a_Message, state) + + def RegisterHandlers(self): + super().RegisterHandlers() + self.m_Bot.RegisterMessageHandler( + self.m_StartMessageHandler, + None, + commands = ['start'] + ) diff --git a/bot_modules/tasks.py b/bot_modules/tasks.py index 505aca4..b591ce3 100644 --- a/bot_modules/tasks.py +++ b/bot_modules/tasks.py @@ -3,16 +3,11 @@ # Задачи -from bot_sys import bot_bd, log, keyboard, user_access -from bot_modules import start, access, groups, projects, needs, comments -from template import bd_item_view, simple_message, bd_item_delete, bd_item_edit, bd_item, bd_item_add, bd_item_select - -from aiogram import types +from bot_sys import bot_bd, keyboard, user_access, bd_table +from bot_modules import mod_table_operate, mod_simple_message from aiogram.dispatcher import FSMContext from aiogram.dispatcher.filters.state import State, StatesGroup -from aiogram.dispatcher import Dispatcher -import sqlite3 class FSMCreateTask(StatesGroup): name = State() @@ -20,19 +15,15 @@ class FSMCreateTask(StatesGroup): photo = State() class FSMEditTaskPhotoItem(StatesGroup): - item_id = State() item_field = State() class FSMEditTaskNameItem(StatesGroup): - item_id = State() item_field = State() class FSMEditTaskDescItem(StatesGroup): - item_id = State() item_field = State() class FSMEditTaskAccessItem(StatesGroup): - item_id = State() item_field = State() # --------------------------------------------------------- # БД @@ -47,327 +38,117 @@ access_field = 'taskAccess' create_datetime_field = 'taskCreateDateTime' parent_id_field = 'projectID' -init_bd_cmds = [f'''CREATE TABLE IF NOT EXISTS {table_name}( - {key_name} INTEGER PRIMARY KEY, - {name_field} TEXT, - {desc_field} TEXT, - {photo_field} TEXT, - {access_field} TEXT, - {create_datetime_field} TEXT, - {parent_id_field} INTEGER - )''', -f"INSERT OR IGNORE INTO module_access (modName, modAccess, itemDefaultAccess) VALUES ('{module_name}', '{user_access.user_access_group_new}=va', '{user_access.user_access_group_new}=va');" -] - -select_tasks_prefix = '' +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.STR), + 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), + bd_table.TableField(parent_id_field, bd_table.TableFieldDestiny.PARENT_ID, bd_table.TableFieldType.INT), + ]) + +init_access = f'{user_access.user_access_group_new}=va' + +fsm = { + mod_table_operate.FSMs.CREATE: FSMCreateTask, + mod_table_operate.FSMs.EDIT_NAME: FSMEditTaskNameItem, + mod_table_operate.FSMs.EDIT_DESC: FSMEditTaskDescItem, + mod_table_operate.FSMs.EDIT_PHOTO: FSMEditTaskPhotoItem, + mod_table_operate.FSMs.EDIT_ACCESS: FSMEditTaskAccessItem, + } # --------------------------------------------------------- -# Сообщения - -tasks_button_name = "✎ Задачи" -base_task_message = ''' -✎ Задачи - -''' - -list_task_button_name = "📃 Список задач" -select_task_message = ''' +# Сообщения и кнопки + +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.ButtonNames.EDIT_PHOTO: "☐ Изменить изображение у задачи", + mod_table_operate.ButtonNames.EDIT_NAME: "≂ Изменить название у задачи", + mod_table_operate.ButtonNames.EDIT_DESC: "𝌴 Изменить описание у задачи", + mod_table_operate.ButtonNames.EDIT_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: ''' Пожалуйста, выберите задачу: -''' - -error_find_proj_message = ''' +''', + mod_table_operate.Messages.ERROR_FIND: ''' ❌ Ошибка, задача не найдена -''' - -task_open_message = f''' +''', + mod_table_operate.Messages.OPEN: f''' Задача: #{name_field} #{desc_field} Время создания: #{create_datetime_field} -''' - -# Создание задачи - -add_task_button_name = "☑ Добавить задачу" -task_create_name_message = ''' +''', + mod_table_operate.Messages.CREATE_NAME: ''' Создание задачи. Шаг №1 Введите название задачи: -''' - -task_create_desc_message = ''' +''', + mod_table_operate.Messages.CREATE_DESC: ''' Создание задачи. Шаг №2 Введите описание задачи: -''' - -task_create_photo_message = ''' +''', + mod_table_operate.Messages.CREATE_PHOTO: ''' Создание задачи. Шаг №3 Загрузите обложку для задачи (Фото): Она будет отображаться в её описании. -''' - -task_success_create_message = '''✅ Задача успешно добавлена!''' - -# Редактирование задачи. - -edit_task_button_name = "🛠 Редактировать задачу" -task_start_edit_message= ''' +''', + mod_table_operate.Messages.SUCCESS_CREATE: '''✅ Задача успешно добавлена!''', + mod_table_operate.Messages.START_EDIT: ''' Пожалуйста, выберите действие: -''' - -task_select_to_edit_message = ''' +''', + mod_table_operate.Messages.SELECT_TO_EDIT: ''' Выберите задачу, которую вы хотите отредактировать. -''' - -edit_task_photo_button_name = "☐ Изменить изображение у задачи" -task_edit_photo_message = ''' +''', + mod_table_operate.Messages.EDIT_PHOTO: ''' Загрузите новую обложку для задачи (Фото): Она будет отображаться в её описании. -''' - -edit_task_name_button_name = "≂ Изменить название у задачи" -task_edit_name_message = f''' +''', + mod_table_operate.Messages.EDIT_NAME: f''' Текущее название задачи: #{name_field} Введите новое название задачи: -''' - -edit_task_desc_button_name = "𝌴 Изменить описание у задачи" -task_edit_desc_message = f''' +''', + mod_table_operate.Messages.EDIT_DESC: f''' Текущее описание задачи: #{desc_field} Введите новое описание задачи: -''' - -edit_task_access_button_name = "✋ Изменить доступ к задаче" -task_edit_access_message = f''' +''', + mod_table_operate.Messages.EDIT_ACCESS: f''' Текущий доступ к задаче: #{access_field} {user_access.user_access_readme} Введите новую строку доступа: -''' - -task_success_edit_message = '''✅ Задача успешно отредактирована!''' - -# Удаление задачи - -del_task_button_name = "❌ Удалить задачу" -task_select_to_delete_message = ''' +''', + mod_table_operate.Messages.SUCCESS_EDIT: '''✅ Задача успешно отредактирован!''', + mod_table_operate.Messages.SELECT_TO_DELETE: ''' Выберите задачу, которую вы хотите удалить. -Все потребности в этой задачае так же будут удалены! -''' - -task_success_delete_message = '''✅ Задача успешно удалена!''' - -# --------------------------------------------------------- -# Работа с кнопками - -def GetEditTaskKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = GetModuleButtons() + [ - keyboard.ButtonWithAccess(edit_task_photo_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_task_name_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_task_desc_button_name, user_access.AccessMode.EDIT, GetAccess()), - keyboard.ButtonWithAccess(edit_task_access_button_name, user_access.AccessMode.ACCEES_EDIT, GetAccess()), - ] - mods = [start] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetStartTaskKeyboardButtons(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.ButtonWithAccess(list_task_button_name, user_access.AccessMode.VIEW, GetAccess()), - keyboard.ButtonWithAccess(add_task_button_name, user_access.AccessMode.ADD, GetAccess()), - keyboard.ButtonWithAccess(del_task_button_name, user_access.AccessMode.DELETE, GetAccess()), - keyboard.ButtonWithAccess(edit_task_button_name, user_access.AccessMode.EDIT, GetAccess()) - ] - mods = [start, projects, needs, comments] - return keyboard.MakeKeyboard(keyboard.GetButtons(mods) + cur_buttons, a_UserGroups) - -def GetViewItemInlineKeyboardTemplate(a_ItemID): - def GetViewItemInlineKeyboard(a_Message, a_UserGroups): - cur_buttons = [ - keyboard.InlineButton(needs.list_need_button_name, needs.select_needs_prefix, a_ItemID, GetAccess(), user_access.AccessMode.VIEW), - ] - return keyboard.MakeInlineKeyboard(cur_buttons, a_UserGroups) - return GetViewItemInlineKeyboard - -# --------------------------------------------------------- -# Обработка сообщений - -# стартовое сообщение -async def TasksOpen(a_Message : types.message, state = None): - return simple_message.WorkFuncResult(base_task_message) - -def GetButtonNameAndKeyValueAndAccess(a_Item): - # taskName taskID taskAccess - return a_Item[1], a_Item[0], a_Item[4] - -def ShowMessageTemplate(a_StringMessage, keyboard_template_func = None): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - - msg = a_StringMessage.\ - replace(f'#{name_field}', a_Item[1]).\ - replace(f'#{desc_field}', a_Item[2]).\ - replace(f'#{create_datetime_field}', a_Item[5]).\ - replace(f'#{access_field}', a_Item[4]) - keyboard_func = None - if keyboard_template_func: - keyboard_func = keyboard_template_func(a_Item[0]) - return simple_message.WorkFuncResult(msg, photo_id = a_Item[3], item_access = a_Item[4], keyboard_func = keyboard_func) - return ShowMessage - -def SimpleMessageTemplate(a_StringMessage): - async def ShowMessage(a_CallbackQuery : types.CallbackQuery, a_Item): - return simple_message.WorkFuncResult(a_StringMessage) - return ShowMessage - -# Удаление задачи - -async def TaskPreDelete(a_CallbackQuery : types.CallbackQuery, a_Item): - if (len(a_Item) < 6): - return simple_message.WorkFuncResult(error_find_proj_message) - access = a_Item[4] - return simple_message.WorkFuncResult('', None, item_access = access) - -async def TaskPostDelete(a_CallbackQuery : types.CallbackQuery, a_ItemID): - log.Success(f'Задача №{a_ItemID} была удалена пользователем {a_CallbackQuery.from_user.id}.') - #TODO: удалить вложенные - return simple_message.WorkFuncResult(task_success_delete_message) - -# --------------------------------------------------------- -# Работа с базой данных задач - -def AddBDItemFunc(a_ItemData, a_UserID): - res, error = bot_bd.SQLRequestToBD(f'INSERT INTO {table_name}({photo_field}, {name_field}, {desc_field}, {access_field}, {parent_id_field}, {create_datetime_field}) VALUES(?, ?, ?, ?, ?, {bot_bd.GetBDDateTimeNow()})', - commit = True, return_error = True, param = (a_ItemData[photo_field], a_ItemData[name_field], a_ItemData[desc_field], access.GetItemDefaultAccessForModule(module_name) + f";{a_UserID}=+", a_ItemData[parent_id_field])) - - if error: - log.Error(f'Пользоватлель {a_UserID}. Ошибка добавления записи в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - else: - log.Success(f'Пользоватлель {a_UserID}. Добавлена запись в таблицу {table_name} ({a_ItemData[photo_field]}, {a_ItemData[name_field]}, {a_ItemData[desc_field]}, {access.GetItemDefaultAccessForModule(module_name)}).') - - return res, error - -# --------------------------------------------------------- -# API - -# Инициализация БД -def GetInitBDCommands(): - return init_bd_cmds - -def GetAccess(): - return access.GetAccessForModule(module_name) - -# Доступные кнопки -def GetModuleButtons(): - return [keyboard.ButtonWithAccess(tasks_button_name, user_access.AccessMode.VIEW, GetAccess())] - -# Обработка кнопок -def RegisterHandlers(dp : Dispatcher): - defaul_keyboard_func = GetStartTaskKeyboardButtons - def RegisterSelectParent(a_ButtonName, access_mode): - a_PrefixBase = a_ButtonName - return bd_item_select.FirstSelectBDItemRegisterHandlers(dp, \ - a_PrefixBase, \ - a_ButtonName, \ - projects.table_name, \ - projects.key_name, \ - projects.GetButtonNameAndKeyValueAndAccess, \ - projects.select_project_message, \ - projects.GetAccess, access_mode = access_mode\ - ) - - # Стартовое сообщение - dp.register_message_handler(simple_message.SimpleMessageTemplate(TasksOpen, defaul_keyboard_func, GetAccess), text = tasks_button_name) - - # Список задач - a_Prefix = RegisterSelectParent(list_task_button_name, user_access.AccessMode.VIEW) - bd_item_view.LastSelectAndShowBDItemRegisterHandlers(dp, \ - a_Prefix, parent_id_field, \ - table_name, key_name, \ - ShowMessageTemplate(task_open_message, GetViewItemInlineKeyboardTemplate), \ - GetButtonNameAndKeyValueAndAccess, \ - select_task_message, \ - GetAccess, \ - defaul_keyboard_func, \ - access_mode = user_access.AccessMode.VIEW\ - ) - global select_tasks_prefix - select_tasks_prefix = a_Prefix - - # Удаление задачи - a_Prefix = RegisterSelectParent(del_task_button_name, user_access.AccessMode.DELETE) - bd_item_delete.DeleteBDItemRegisterHandlers(dp, \ - a_Prefix, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - table_name, \ - key_name, \ - parent_id_field, \ - TaskPreDelete, \ - TaskPostDelete, \ - GetButtonNameAndKeyValueAndAccess, \ - select_task_message, \ - GetAccess, \ - defaul_keyboard_func\ - ) - - # Добавление задачи - a_Prefix = RegisterSelectParent(add_task_button_name, user_access.AccessMode.ADD) - bd_item_add.AddBDItem3RegisterHandlers(dp, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - FSMCreateTask, \ - FSMCreateTask.name,\ - FSMCreateTask.desc, \ - FSMCreateTask.photo,\ - AddBDItemFunc, \ - SimpleMessageTemplate(task_create_name_message), \ - SimpleMessageTemplate(task_create_desc_message), \ - SimpleMessageTemplate(task_create_photo_message), \ - SimpleMessageTemplate(task_success_create_message), \ - a_Prefix,\ - projects.table_name, \ - projects.key_name, \ - name_field, \ - desc_field, \ - photo_field, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - GetStartTaskKeyboardButtons\ - ) - - def RegisterEdit(a_ButtonName, a_FSM, a_EditMessage, a_FieldName, a_FieldType, a_AccessMode = user_access.AccessMode.EDIT): - a_Prefix = RegisterSelectParent(a_ButtonName, a_AccessMode) - bd_item_edit.EditBDItemRegisterHandlers(dp, \ - a_Prefix, \ - a_FSM, \ - bd_item.GetCheckForPrefixFunc(a_Prefix), \ - task_select_to_edit_message, \ - ShowMessageTemplate(a_EditMessage), \ - ShowMessageTemplate(task_success_edit_message), \ - table_name, \ - key_name, \ - parent_id_field, \ - a_FieldName, \ - GetButtonNameAndKeyValueAndAccess, \ - GetAccess, \ - edit_keyboard_func, \ - access_mode = a_AccessMode, \ - field_type = a_FieldType\ - ) +Все потребности в этой задаче так же будут удалены! +''', + mod_table_operate.Messages.SUCCESS_DELETE: '''✅ Задача успешно удалёна!''', +} - # Редактирование задачи - edit_keyboard_func = GetEditTaskKeyboardButtons - dp.register_message_handler(simple_message.InfoMessageTemplate(task_start_edit_message, edit_keyboard_func, GetAccess, access_mode = user_access.AccessMode.EDIT), text = edit_task_button_name) +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_Log): + super().__init__(table, messages, button_names, fsm, a_ParentModName, a_ChildModName, init_access, a_ChildModuleNameList, a_EditModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log) - RegisterEdit(edit_task_photo_button_name, FSMEditTaskPhotoItem, task_edit_photo_message, photo_field, bd_item.FieldType.photo) - RegisterEdit(edit_task_name_button_name, FSMEditTaskNameItem, task_edit_name_message, name_field, bd_item.FieldType.text) - RegisterEdit(edit_task_desc_button_name, FSMEditTaskDescItem, task_edit_desc_message, desc_field, bd_item.FieldType.text) - RegisterEdit(edit_task_access_button_name, FSMEditTaskAccessItem, task_edit_access_message, access_field, bd_item.FieldType.text) + def GetName(self): + return module_name diff --git a/bot_sys/aiogram_bot.py b/bot_sys/aiogram_bot.py new file mode 100644 index 0000000..6b4ccca --- /dev/null +++ b/bot_sys/aiogram_bot.py @@ -0,0 +1,104 @@ +#-*-coding utf-8-*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +from bot_sys import interfaces, bot_bd, keyboard, user_access + +from aiogram import types +from aiogram import Bot +from aiogram.dispatcher import Dispatcher +from aiogram.contrib.fsm_storage.memory import MemoryStorage +from aiogram.utils import executor + +class AiogramBot(interfaces.IBot): + def __init__(self, a_TelegramBotApiToken, a_BDFileName, a_RootIDs, a_Log): + self.m_TelegramBotApiToken = a_TelegramBotApiToken + self.m_BDFileName = a_BDFileName + self.m_RootIDs = a_RootIDs + self.m_Log = a_Log + self.m_TBot = Bot(token=self.m_TelegramBotApiToken, parse_mode = types.ParseMode.HTML) + self.m_Storage = MemoryStorage() + self.m_Dispatcher = Dispatcher(self.m_TBot, storage = self.m_Storage) + + def GetRootIDs(self): + return self.m_RootIDs + + def GetLog(self): + return self.m_Log + + def SQLRequest(self, a_Request : str, commit = False, return_error = False, param = None): + return bot_bd.SQLRequest(self.m_Log, self.m_BDFileName, a_Request, commit = commit, return_error = return_error, param = param) + + async def SendMessage(self, a_UserID, a_Message, a_PhotoIDs, a_KeyboardButtons, a_InlineKeyboardButtons, parse_mode = None): + if not parse_mode: + parse_mode = types.ParseMode.HTML + inline_keyboards = None + if a_InlineKeyboardButtons: + inline_keyboards = keyboard.MakeAiogramInlineKeyboards(a_InlineKeyboardButtons) + base_keyboards = None + if a_KeyboardButtons: + base_keyboards = [keyboard.MakeAiogramKeyboard(a_KeyboardButtons)] + if inline_keyboards: + base_keyboards = inline_keyboards + if a_PhotoIDs and a_PhotoIDs != 0 and a_PhotoIDs != '0': + if base_keyboards: + for k in base_keyboards: + await self.m_TBot.send_photo( + a_UserID, + a_PhotoIDs, + a_Message, + reply_markup = k + ) + else: + await self.m_TBot.send_photo( + a_UserID, + a_PhotoIDs, + a_Message + ) + else: + #print('SendMessage', a_UserID, a_Message, a_PhotoIDs, a_InlineKeyboardButtons, a_KeyboardButtons, base_keyboard) + if base_keyboards: + for k in base_keyboards: + await self.m_TBot.send_message( + a_UserID, + a_Message, + reply_markup = k, + parse_mode = parse_mode + ) + else: + await self.m_TBot.send_message( + a_UserID, + a_Message, + parse_mode = parse_mode + ) + + async def SendDocument(self, a_UserID, a_Document, a_Caption, a_KeyboardButtons, a_InlineKeyboardButtons): + inline_keyboard = None + if a_InlineKeyboardButtons: + inline_keyboard = keyboard.MakeAiogramInlineKeyboard(a_InlineKeyboardButtons) + base_keyboard = None + if a_KeyboardButtons: + base_keyboard = keyboard.MakeAiogramKeyboard(a_KeyboardButtons) + if inline_keyboard: + base_keyboard = inline_keyboard + await self.m_TBot.send_document( + a_UserID, + a_Document, + caption = a_Caption, + reply_markup = base_keyboard + ) + + def RegisterMessageHandler(self, a_MessageHandler, a_CheckFunc=None, commands=None, regexp=None, content_types=None, state=None): + if a_CheckFunc: + self.m_Dispatcher.register_message_handler(a_MessageHandler, a_CheckFunc, commands=commands, regexp=regexp, content_types=content_types, state=state) + else: + self.m_Dispatcher.register_message_handler(a_MessageHandler, commands=commands, regexp=regexp, content_types=content_types, state=state) + + def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc=None, commands=None, regexp=None, content_types=None, state=None): + if a_CheckFunc: + self.m_Dispatcher.register_callback_query_handler(a_CallbackHandler, a_CheckFunc, commands=commands, regexp=regexp, content_types=content_types, state=state) + else: + self.m_Dispatcher.register_callback_query_handler(a_CallbackHandler, commands=commands, regexp=regexp, content_types=content_types, state=state) + + def StartPolling(self): + executor.start_polling(self.m_Dispatcher) + diff --git a/bot_sys/bd_table.py b/bot_sys/bd_table.py new file mode 100644 index 0000000..aaacb4f --- /dev/null +++ b/bot_sys/bd_table.py @@ -0,0 +1,125 @@ +#-*-coding utf-8-*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +from enum import Enum +from enum import auto + +# Тип поля в таблице +class TableFieldType(Enum): + INT = 'INTEGER' + STR = 'TEXT' + +# Предназначение поля в таблице +class TableFieldDestiny(Enum): + KEY = auto() + NAME = auto() + DESC = auto() + PHOTO = auto() + ACCESS = auto() + DEFAULT_ACCESS = auto() + CREATE_DATE = auto() + PARENT_ID = auto() + OTHER = auto() + +class TableField: + def __init__(self, a_Name, a_Destiny : TableFieldDestiny, a_Type : TableFieldType): + self.m_Name = a_Name + self.m_Destiny = a_Destiny + self.m_Type = a_Type + +class Table: + def __init__(self, a_TableName, a_Fields : [TableField], a_UniqueFields = None): + self.m_TableName = a_TableName + self.m_Fields = a_Fields + self.m_UniqueFields = a_UniqueFields + + def GetName(self): + return self.m_TableName + + def GetFields(self): + return self.TableFieldType + + def GetFieldsCount(self): + return len(self.m_Fields) + + def GetFieldByDestiny(self, a_Destiny): + for f in self.m_Fields: + if f.m_Destiny == a_Destiny: + return f + return None + + def GetFieldNameByDestiny(self, a_Destiny): + f = self.GetFieldByDestiny(a_Destiny) + if f: + return f.m_Name + return None + + def GetFieldIDByDestiny(self, a_Destiny): + for i in range(len(self.m_Fields)): + f = self.m_Fields[i] + if f.m_Destiny == a_Destiny: + return i + return None + + def GetInitTableRequest(self): + request = f'CREATE TABLE IF NOT EXISTS {self.GetName()}(' + items = [] + for f in self.m_Fields: + item = f.m_Name + ' ' + str(f.m_Type.value) + if f.m_Destiny == TableFieldDestiny.KEY: + item += ' PRIMARY KEY' + items += [item] + if self.m_UniqueFields: + for u in self.m_UniqueFields: + fields = [] + for f in u: + fields += [f.m_Name] + items += ['UNIQUE(' + ', '.join(fields) +')'] + return request + ', '.join(items) + ');' + + def ReplaceAllFieldTags(self, a_String, a_BDItem): + result = a_String + for i in range(len(self.m_Fields)): + f = self.m_Fields[i] + result = result.replace(f'#{f.m_Name}', str(a_BDItem[i])) + return result + +def Test(): + f1 = TableField('f1', TableFieldDestiny.KEY, TableFieldType.INT) + f2 = TableField('f2', TableFieldDestiny.NAME, TableFieldType.STR) + f3 = TableField('f3', TableFieldDestiny.DESC, TableFieldType.STR) + table = Table('tname', [ + f1, + f2, + f3 + ], + [[f1], [f2, f3]] + ) + assert table.GetName() == 'tname' + assert table.GetFieldByDestiny(TableFieldDestiny.KEY).m_Name == 'f1' + assert table.GetFieldNameByDestiny(TableFieldDestiny.KEY) == 'f1' + assert table.GetFieldByDestiny(TableFieldDestiny.KEY).m_Destiny == TableFieldDestiny.KEY + assert table.GetFieldByDestiny(TableFieldDestiny.KEY).m_Type == TableFieldType.INT + assert table.GetFieldIDByDestiny(TableFieldDestiny.KEY) == 0 + assert table.GetFieldByDestiny(TableFieldDestiny.NAME).m_Name == 'f2' + assert table.GetFieldNameByDestiny(TableFieldDestiny.NAME) == 'f2' + assert table.GetFieldByDestiny(TableFieldDestiny.NAME).m_Destiny == TableFieldDestiny.NAME + assert table.GetFieldByDestiny(TableFieldDestiny.NAME).m_Type == TableFieldType.STR + assert table.GetFieldIDByDestiny(TableFieldDestiny.NAME) == 1 + assert table.GetFieldByDestiny(TableFieldDestiny.DESC).m_Name == 'f3' + assert table.GetFieldNameByDestiny(TableFieldDestiny.DESC) == 'f3' + assert table.GetFieldByDestiny(TableFieldDestiny.DESC).m_Destiny == TableFieldDestiny.DESC + assert table.GetFieldByDestiny(TableFieldDestiny.DESC).m_Type == TableFieldType.STR + assert table.GetFieldIDByDestiny(TableFieldDestiny.DESC) == 2 + + assert table.GetFieldByDestiny(TableFieldDestiny.PHOTO) == None + assert table.GetFieldIDByDestiny(TableFieldDestiny.PHOTO) == None + assert table.GetFieldNameByDestiny(TableFieldDestiny.PHOTO) == None + + assert table.GetFieldsCount() == 3 + + print(table.GetInitTableRequest()) + assert table.GetInitTableRequest() == 'CREATE TABLE IF NOT EXISTS tname(f1 INTEGER PRIMARY KEY, f2 TEXT, f3 TEXT, UNIQUE(f1), UNIQUE(f2, f3));' + + item = [10, 'i1', 'i2'] + assert table.ReplaceAllFieldTags('#f1 #f2 #f3', item) == '10 i1 i2' diff --git a/bot_sys/bot_bd.py b/bot_sys/bot_bd.py index 1b59a51..ec81174 100644 --- a/bot_sys/bot_bd.py +++ b/bot_sys/bot_bd.py @@ -6,30 +6,21 @@ from bot_sys import log # Работа с базой данных -# Имя файла БД -g_bd_file_name = 'bot.db' -def GetBDFileName(): - return g_bd_file_name - -# --------------------------------------------------------- -# Функции работы с базой - -# --------------------------------------------------------- - def GetBDDateTimeNow(): return 'datetime(\'now\')' -def BDExecute(a_Commands): - for cmd in a_Commands: - SQLRequestToBD(cmd, commit = True) +def SelectBDTemplate(a_Bot, a_TableName): + def SelectBD(): + return a_Bot.SQLRequest(f'SELECT * FROM {a_TableName}') + return SelectBD -def SelectBDTemplate(a_TableName): +def RequestSelectTemplate(a_Bot, a_TableName): def SelectBD(): - return SQLRequestToBD(f'SELECT * FROM {a_TableName}') + return a_Bot.SQLRequest(f'SELECT * FROM {a_TableName}') return SelectBD -def SQLRequestToBD(a_Request : str, commit = False, return_error = False, param = None): - db = sqlite3.connect(GetBDFileName()) +def SQLRequest(a_Log, a_BDFileName, a_Request : str, commit = False, return_error = False, param = None): + db = sqlite3.connect(a_BDFileName) cursor = db.cursor() result = [] error = None @@ -42,11 +33,12 @@ def SQLRequestToBD(a_Request : str, commit = False, return_error = False, param if commit: db.commit() except sqlite3.Error as e: - log.Error(f'Ошибка при обработке запроса [{a_Request}]:{str(e)}') + a_Log.Error(f'Ошибка при обработке запроса [{a_Request}]:{str(e)}') error = "Ошибка sqlite3:" + str(e) cursor.close() db.close() - if not error and commit: log.Success(f'Выполнен запрос [{a_Request}]') + if not error and commit: + a_Log.Success(f'Выполнен запрос [{a_Request}]') if return_error: return result, error return result diff --git a/bot_sys/bot_messages.py b/bot_sys/bot_messages.py new file mode 100644 index 0000000..c032df4 --- /dev/null +++ b/bot_sys/bot_messages.py @@ -0,0 +1,83 @@ +#-*-coding utf-8-*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +# Работа с сообщениями + +class BotMessage: + def __init__(self, a_BotMessages, a_MessageName : str, a_MessageDesc : str, a_Language : str, a_PhotoID : str, a_DateTime): + self.m_BotMessages = a_BotMessages + self.m_MessageName = a_MessageName + self.m_MessageDesc = a_MessageDesc + self.m_Language = a_Language + self.m_PhotoID = a_PhotoID + self.m_DateTime = a_DateTime + + def StaticCopy(self): + return BotMessage(None, self.m_MessageName, self.m_MessageDesc, self.m_Language, self.m_PhotoID, self.m_DateTime) + + def GetName(self): + return self.m_MessageName + + def GetDesc(self): + return self.m_MessageDesc + + def UpdateDesc(self, a_Desc): + self.m_MessageDesc = a_Desc + + def GetLanguage(self): + return self.m_Language + + def GetPhotoID(self): + return self.m_PhotoID + + def UpdatePhotoID(self, a_PhotoID): + self.m_PhotoID = a_PhotoID + + def __str__(self): + msg = self.GetMessageForLang(self.m_Language) + return msg.GetDesc() + + def GetMessageForLang(self, a_Language): + if not self.m_BotMessages: + return self + last_update = self.m_BotMessages.m_LastUpdate + new_msg = self + if self.m_DateTime < last_update: + msg = self.m_BotMessages.GetMessages() + if not msg.get(a_Language, None): + a_Language = self.m_Language + if not msg.get(a_Language, None): + a_Language = self.m_BotMessages.a_DefaultLanguage + new_msg = msg[a_Language].get(self.m_MessageName, self) + if a_Language == self.m_Language: + self.m_MessageDesc = new_msg.m_MessageDesc + self.m_Language = new_msg.m_Language + self.m_PhotoID = new_msg.m_PhotoID + self.m_DateTime = new_msg.m_DateTime + return new_msg + +def MakeBotMessage(a_MessageDesc): + return BotMessage(None, '', a_MessageDesc, None, 0, None) + +class BotMessages: + def __init__(self, a_DefaultLanguage): + self.m_DefaultLanguage = a_DefaultLanguage + self.m_Messages = {} + self.m_LastUpdate = None + + def GetMessages(self): + return self.m_Messages + + def UpdateSignal(self, a_DateTime): + self.m_LastUpdate = a_DateTime + + def CreateMessage(self, a_MessageName, a_MessageDesc, a_DateTime, a_MessagePhotoID = 0, a_MessageLang = None): + if not a_MessageLang: + a_MessageLang = self.m_DefaultLanguage + cur_msg = BotMessage(self, a_MessageName, a_MessageDesc, a_MessageLang, a_MessagePhotoID, a_DateTime) + msg = self.GetMessages() + if not msg.get(a_MessageLang, None): + msg[a_MessageLang] = {} + msg[a_MessageLang][a_MessageName] = cur_msg + return cur_msg + diff --git a/bot_sys/interfaces.py b/bot_sys/interfaces.py new file mode 100644 index 0000000..e65a760 --- /dev/null +++ b/bot_sys/interfaces.py @@ -0,0 +1,38 @@ +#-*-coding utf-8-*- +# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) + +from abc import ABC, abstractmethod + +class IBot(ABC): + @abstractmethod + def GetRootIDs(self): + pass + + @abstractmethod + def GetLog(self): + pass + + @abstractmethod + def SQLRequest(self, a_Request : str, commit = False, return_error = False, param = None): + pass + + @abstractmethod + async def SendMessage(self, a_UserID, a_Message, a_PhotoIDs, a_KeyboardButtons, a_InlineKeyboardButtons, parse_mode=None): + pass + + @abstractmethod + async def SendDocument(self, a_UserID, a_Document, a_Caption, a_KeyboardButtons, a_InlineKeyboardButtons): + pass + + @abstractmethod + def RegisterMessageHandler(self, a_MessageHandler, a_CheckFunc=None, commands=None, regexp=None, content_types=None, state=None): + pass + + @abstractmethod + def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc=None, commands=None, regexp=None, content_types=None, state=None): + pass + + @abstractmethod + def StartPolling(self): + pass + diff --git a/bot_sys/keyboard.py b/bot_sys/keyboard.py index 62e98df..c598ca5 100644 --- a/bot_sys/keyboard.py +++ b/bot_sys/keyboard.py @@ -4,8 +4,9 @@ # Работа с кнопками и клавиатурой from bot_sys import user_access -from aiogram import types, Bot, Dispatcher + from aiogram.types import ReplyKeyboardRemove, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton +from aiogram import types class ButtonWithAccess: def __init__(self, a_Label, a_AccessMode : user_access.AccessMode, a_AccessString): @@ -24,29 +25,39 @@ def GetButtons(a_ModList): import math def Chunks(a_List, a_ChunkSize): + chunk_list = [] for i in range(0, len(a_List), a_ChunkSize): - yield a_List[i: i + a_ChunkSize] + chunk_list += [a_List[i: i + a_ChunkSize]] + return chunk_list def GetButtonInRowCount(a_AllKeyCount): - return min(max(int(math.sqrt(a_AllKeyCount) // 1), 1), 4) + return min(max(int(math.sqrt(a_AllKeyCount) // 1), 1), 3) -def MakeKeyboard(a_ButtonList : [ButtonWithAccess], a_UserGroups): +# TODO перенести KeyboardButton в MakeAiogramKeyboard +def MakeButtons(a_Bot, a_ButtonList : [ButtonWithAccess], a_UserGroups): buttons = [] for b in a_ButtonList: - if user_access.CheckAccessString(b.access_string, a_UserGroups, b.access_mode): - buttons += [types.KeyboardButton(b.label)] + if not b.label: + continue + label = str(b.label) + if user_access.CheckAccess(a_Bot.GetRootIDs(), b.access_string, a_UserGroups, b.access_mode): + buttons += [types.KeyboardButton(label)] step = GetButtonInRowCount(len(buttons)) - key = types.ReplyKeyboardMarkup(keyboard=Chunks(buttons, step), resize_keyboard = True) - return key + return Chunks(buttons, step) -def MakeKeyboardRemove(): - return types.ReplyKeyboardRemove() +def MakeKeyboard(a_ButtonList : [ButtonWithAccess], a_UserGroups): + return MakeAiogramKeyboard(MakeButtons(a_ButtonList, a_UserGroups)) def MakeKeyboardForMods(a_ModList, a_UserGroups): buttons = GetButtons(a_ModList) return MakeKeyboard(buttons, a_UserGroups) class InlineButton: + def __init__(self, a_Label, a_CallBackData): + self.label = a_Label + self.callback_data = str(a_CallBackData) + +class InlineButtonWithAccess: def __init__(self, a_Label, a_CallBackPrefix, a_CallBackData, a_AccessString, a_AccessMode): self.label = a_Label self.callback_prefix = a_CallBackPrefix @@ -54,12 +65,36 @@ class InlineButton: self.access_string = a_AccessString self.access_mode = a_AccessMode -def MakeInlineKeyboard(a_ButtonList : [InlineButton], a_UserGroups): +def MakeInlineKeyboardButtons(a_Bot, a_ButtonList : [InlineButtonWithAccess], a_UserGroups): buttons = [] for b in a_ButtonList: - if user_access.CheckAccessString(b.access_string, a_UserGroups, b.access_mode): - buttons += [types.InlineKeyboardButton(text = b.label, callback_data = f'{b.callback_prefix}{b.callback_data}')] + if user_access.CheckAccess(a_Bot.GetRootIDs(), b.access_string, a_UserGroups, b.access_mode): + data = f'{b.callback_prefix}{b.callback_data}' + assert len(data) < 41 # Телеграм больше не поддерживает + buttons += [InlineButton(b.label, data)] step = GetButtonInRowCount(len(buttons)) - inline_keyboard = InlineKeyboardMarkup(inline_keyboard=Chunks(buttons, step)) - return inline_keyboard + return Chunks(buttons, step) + +# ------------------------------- + + +def MakeKeyboardRemove(): + return types.ReplyKeyboardRemove() + +def MakeAiogramInlineKeyboards(a_ButtonList : [InlineButton]): + buttons = [] + for row in a_ButtonList: + r = [] + for b in row: + r += [types.InlineKeyboardButton(text = str(b.label), callback_data = b.callback_data)] + buttons += [r] + + button_list_chunks = Chunks(buttons, 20) + result = [] + for c in button_list_chunks: + result += [InlineKeyboardMarkup(inline_keyboard=c)] + + return result +def MakeAiogramKeyboard(a_ButtonList : [[str]]): + return types.ReplyKeyboardMarkup(keyboard=a_ButtonList, resize_keyboard = True) diff --git a/bot_sys/log.py b/bot_sys/log.py index cfb28e3..fd8adb6 100644 --- a/bot_sys/log.py +++ b/bot_sys/log.py @@ -10,48 +10,52 @@ # Error - Ошибка. # Success - Успех. -# Файл лога -g_log_file_name = 'log.txt' - from bot_sys import config import colorama import datetime colorama.init() -def GetTimeNow(): - return datetime.datetime.now() - -def GetTime(): - now = GetTimeNow() - time = now.strftime(f"[%d.%m.%Y, %H:%M]") - return time - -def Info(a_LogMessage): - time = GetTime() - WriteToFile(f'{time} | {a_LogMessage}') - print(f"{time} {colorama.Back.BLUE}{colorama.Style.BRIGHT} ИНФО {colorama.Style.RESET_ALL} | {a_LogMessage}") - -def Warn(a_LogMessage): - time = GetTime() - WriteToFile(f'{time} | {a_LogMessage}') - print(f"{time} {colorama.Back.YELLOW}{colorama.Style.BRIGHT} ВНИМАНИЕ {colorama.Style.RESET_ALL} | {a_LogMessage}") - -def Error(a_LogMessage): - time = GetTime() - WriteToFile(f'{time} | {a_LogMessage}') - print(f"{time} {colorama.Back.RED}{colorama.Style.BRIGHT} ОШИБКА {colorama.Style.RESET_ALL} | {a_LogMessage}") - -def Success(a_LogMessage): - time = GetTime() - WriteToFile(f'{time} | {a_LogMessage}') - print(f"{time} {colorama.Back.GREEN}{colorama.Style.BRIGHT} УСПЕХ {colorama.Style.RESET_ALL} | {a_LogMessage}") - -def WriteToFile(a_LogMessage): - if config.g_log_to_file != True: - return - - f = open(g_log_file_name, 'a+') - f.write(a_LogMessage) - f.write('\n') - f.close() +class Log: + def __init__(self, a_FileName): + self.m_FileName = a_FileName + + def GetFileName(self): + return self.m_FileName + + def GetTimeNow(self): + return datetime.datetime.now() + + def GetTime(self): + now = self.GetTimeNow() + time = now.strftime(f"[%d.%m.%Y, %H:%M]") + return time + + def Info(self, a_LogMessage): + time = self.GetTime() + self.WriteToFile(f'{time} | {a_LogMessage}') + print(f"{time} {colorama.Back.BLUE}{colorama.Style.BRIGHT} ИНФО {colorama.Style.RESET_ALL} | {a_LogMessage}") + + def Warn(self, a_LogMessage): + time = self.GetTime() + self.WriteToFile(f'{time} | {a_LogMessage}') + print(f"{time} {colorama.Back.YELLOW}{colorama.Style.BRIGHT} ВНИМАНИЕ {colorama.Style.RESET_ALL} | {a_LogMessage}") + + def Error(self, a_LogMessage): + time = self.GetTime() + self.WriteToFile(f'{time} | {a_LogMessage}') + print(f"{time} {colorama.Back.RED}{colorama.Style.BRIGHT} ОШИБКА {colorama.Style.RESET_ALL} | {a_LogMessage}") + + def Success(self, a_LogMessage): + time = self.GetTime() + self.WriteToFile(f'{time} | {a_LogMessage}') + print(f"{time} {colorama.Back.GREEN}{colorama.Style.BRIGHT} УСПЕХ {colorama.Style.RESET_ALL} | {a_LogMessage}") + + def WriteToFile(self, a_LogMessage): + if not self.m_FileName: + return + + f = open(self.m_FileName, 'a+') + f.write(a_LogMessage) + f.write('\n') + f.close() diff --git a/bot_sys/user_access.py b/bot_sys/user_access.py index 2823c7d..abe3127 100644 --- a/bot_sys/user_access.py +++ b/bot_sys/user_access.py @@ -54,8 +54,8 @@ def CheckAccessItem(a_AccessItem : str, a_AccessMode : AccessMode): return False # Возвращает возможность доступа пользователю a_UserGroups в элемент с правами a_AccessValue по режиму доступа a_AccessMode -def CheckAccessString(a_AccessValue : str, a_UserGroups : UserGroups, a_AccessMode : AccessMode): - if a_UserGroups.user_id in config.GetRootIDs(): +def CheckAccess(a_RootIDs, a_AccessValue : str, a_UserGroups : UserGroups, a_AccessMode : AccessMode): + if a_UserGroups.user_id in a_RootIDs: return True for i in a_AccessValue.split(';'): d = i.split('=') @@ -72,99 +72,125 @@ def Test(): assert '1234' in ['123', '1234'] assert not '1234' in ['123', '12345'] + # root имеет полный доступ вне зависимости от a_AccessValue и a_UserGroups и a_AccessMode + roots = ['1234'] for am in AccessMode.ADD, AccessMode.DELETE, AccessMode.EDIT, AccessMode.VIEW, AccessMode.ACCEES_EDIT: - assert CheckAccessString('1234=+', UserGroups('1234', []), am) - assert not CheckAccessString('1234=-', UserGroups('1234', []), am) - assert CheckAccessString('1234=+;gr1=+', UserGroups('1234', ['gr1']), am) - assert CheckAccessString('1234=-;gr1=+', UserGroups('1234', ['gr1']), am) - assert not CheckAccessString('1234=+', UserGroups('123', []), am) - assert not CheckAccessString('1234=-', UserGroups('123', []), am) - assert not CheckAccessString('1234=+;gr1=+', UserGroups('123', ['gr']), am) - assert not CheckAccessString('1234=-;gr1=+', UserGroups('123', ['gr']), am) - assert not CheckAccessString('1234=+;gr=+', UserGroups('123', ['gr1']), am) - assert not CheckAccessString('1234=-;gr=+', UserGroups('123', ['gr1']), am) - - assert CheckAccessString('123=-;1234=a', UserGroups('1234', []), AccessMode.ADD) - assert CheckAccessString('123=-;1234=d', UserGroups('1234', []), AccessMode.DELETE) - assert CheckAccessString('123=-;1234=e', UserGroups('1234', []), AccessMode.EDIT) - assert CheckAccessString('123=-;1234=r', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert CheckAccessString('123=-;1234=v', UserGroups('1234', []), AccessMode.VIEW) - assert CheckAccessString('123=-;gr1=a', UserGroups('1234', ['gr1']), AccessMode.ADD) - assert CheckAccessString('123=-;gr1=d', UserGroups('1234', ['gr1']), AccessMode.DELETE) - assert CheckAccessString('123=-;gr1=e', UserGroups('1234', ['gr1']), AccessMode.EDIT) - assert CheckAccessString('123=-;gr1=r', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) - assert CheckAccessString('123=-;gr1=v', UserGroups('1234', ['gr1']), AccessMode.VIEW) - assert CheckAccessString('123=-;1234=daver', UserGroups('1234', []), AccessMode.ADD) - assert CheckAccessString('123=-;1234=dav', UserGroups('1234', []), AccessMode.DELETE) - assert CheckAccessString('123=-;1234=edv', UserGroups('1234', []), AccessMode.EDIT) - assert CheckAccessString('123=-;1234=rav', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert CheckAccessString('123=-;1234=va', UserGroups('1234', []), AccessMode.VIEW) - assert CheckAccessString('123=-;gr1=avr', UserGroups('1234', ['gr1']), AccessMode.ADD) - assert CheckAccessString('123=-;gr1=daver', UserGroups('1234', ['gr1']), AccessMode.DELETE) - assert CheckAccessString('123=-;gr1=eva', UserGroups('1234', ['gr1']), AccessMode.EDIT) - assert CheckAccessString('123=-;gr1=re', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) - assert CheckAccessString('123=-;gr1=vad', UserGroups('1234', ['gr1']), AccessMode.VIEW) - - assert not CheckAccessString('123=-;1234=d', UserGroups('1234', []), AccessMode.ADD) - assert not CheckAccessString('123=-;1234=a', UserGroups('1234', []), AccessMode.DELETE) - assert not CheckAccessString('123=-;1234=r', UserGroups('1234', []), AccessMode.EDIT) - assert not CheckAccessString('123=-;1234=v', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert not CheckAccessString('123=-;1234=e', UserGroups('1234', []), AccessMode.VIEW) - assert not CheckAccessString('123=-;gr1=d', UserGroups('1234', ['gr']), AccessMode.ADD) - assert not CheckAccessString('123=-;gr1=a', UserGroups('1234', ['gr']), AccessMode.DELETE) - assert not CheckAccessString('123=-;gr1=v', UserGroups('1234', ['gr']), AccessMode.EDIT) - assert not CheckAccessString('123=-;gr1=e', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) - assert not CheckAccessString('123=-;gr1=r', UserGroups('1234', ['gr']), AccessMode.VIEW) - assert not CheckAccessString('123=-;1234=dver', UserGroups('1234', []), AccessMode.ADD) - assert not CheckAccessString('123=-;1234=av', UserGroups('1234', []), AccessMode.DELETE) - assert not CheckAccessString('123=-;1234=dv', UserGroups('1234', []), AccessMode.EDIT) - assert not CheckAccessString('123=-;1234=av', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert not CheckAccessString('123=-;1234=a', UserGroups('1234', []), AccessMode.VIEW) - assert not CheckAccessString('123=-;gr1=vr', UserGroups('1234', ['gr']), AccessMode.ADD) - assert not CheckAccessString('123=-;gr1=aver', UserGroups('1234', ['gr']), AccessMode.DELETE) - assert not CheckAccessString('123=-;gr1=va', UserGroups('1234', ['gr']), AccessMode.EDIT) - assert not CheckAccessString('123=-;gr1=ea', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) - assert not CheckAccessString('123=-;gr1=ad', UserGroups('1234', ['gr']), AccessMode.VIEW) - - assert CheckAccessString(f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.ADD) - assert CheckAccessString(f'123=-;{user_access_group_all}=d', UserGroups('1234', []), AccessMode.DELETE) - assert CheckAccessString(f'123=-;{user_access_group_all}=e', UserGroups('1234', []), AccessMode.EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=r', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=v', UserGroups('1234', []), AccessMode.VIEW) - assert CheckAccessString(f'123=-;{user_access_group_all}=a', UserGroups('1234', ['gr1']), AccessMode.ADD) - assert CheckAccessString(f'123=-;{user_access_group_all}=d', UserGroups('1234', ['gr1']), AccessMode.DELETE) - assert CheckAccessString(f'123=-;{user_access_group_all}=e', UserGroups('1234', ['gr1']), AccessMode.EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=r', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=v', UserGroups('1234', ['gr1']), AccessMode.VIEW) - assert CheckAccessString(f'123=-;{user_access_group_all}=daver', UserGroups('1234', []), AccessMode.ADD) - assert CheckAccessString(f'123=-;{user_access_group_all}=dav', UserGroups('1234', []), AccessMode.DELETE) - assert CheckAccessString(f'123=-;{user_access_group_all}=edv', UserGroups('1234', []), AccessMode.EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=rav', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=va', UserGroups('1234', []), AccessMode.VIEW) - assert CheckAccessString(f'123=-;{user_access_group_all}=avr', UserGroups('1234', ['gr1']), AccessMode.ADD) - assert CheckAccessString(f'123=-;{user_access_group_all}=daver', UserGroups('1234', ['gr1']), AccessMode.DELETE) - assert CheckAccessString(f'123=-;{user_access_group_all}=eva', UserGroups('1234', ['gr1']), AccessMode.EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=re', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) - assert CheckAccessString(f'123=-;{user_access_group_all}=vad', UserGroups('1234', ['gr1']), AccessMode.VIEW) - - assert not CheckAccessString(f'123=-;{user_access_group_all}=d', UserGroups('1234', []), AccessMode.ADD) - assert not CheckAccessString(f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.DELETE) - assert not CheckAccessString(f'123=-;{user_access_group_all}=r', UserGroups('1234', []), AccessMode.EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=v', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=e', UserGroups('1234', []), AccessMode.VIEW) - assert not CheckAccessString(f'123=-;gr1=d;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.ADD) - assert not CheckAccessString(f'123=-;gr1=a;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.DELETE) - assert not CheckAccessString(f'123=-;gr1=v;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.EDIT) - assert not CheckAccessString(f'123=-;gr1=e;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) - assert not CheckAccessString(f'123=-;gr1=r;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.VIEW) - assert not CheckAccessString(f'123=-;{user_access_group_all}=dver', UserGroups('1234', []), AccessMode.ADD) - assert not CheckAccessString(f'123=-;{user_access_group_all}=av', UserGroups('1234', []), AccessMode.DELETE) - assert not CheckAccessString(f'123=-;{user_access_group_all}=dv', UserGroups('1234', []), AccessMode.EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=av', UserGroups('1234', []), AccessMode.ACCEES_EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.VIEW) - assert not CheckAccessString(f'123=-;{user_access_group_all}=vr', UserGroups('1234', ['gr']), AccessMode.ADD) - assert not CheckAccessString(f'123=-;{user_access_group_all}=aver', UserGroups('1234', ['gr']), AccessMode.DELETE) - assert not CheckAccessString(f'123=-;{user_access_group_all}=va', UserGroups('1234', ['gr']), AccessMode.EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=ea', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) - assert not CheckAccessString(f'123=-;{user_access_group_all}=ad', UserGroups('1234', ['gr']), AccessMode.VIEW) + assert CheckAccess(roots, '1234=+', UserGroups('1234', []), am) + assert CheckAccess(roots, '1234=-', UserGroups('1234', []), am) + assert CheckAccess(roots, '1234=+;gr1=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '1234=-;gr1=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '1234=+', UserGroups('1234', []), am) + assert CheckAccess(roots, '1234=-', UserGroups('1234', []), am) + assert CheckAccess(roots, '1234=+;gr1=+', UserGroups('1234', ['gr']), am) + assert CheckAccess(roots, '1234=-;gr1=+', UserGroups('1234', ['gr']), am) + assert CheckAccess(roots, '1234=+;gr=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '1234=-;gr=+', UserGroups('1234', ['gr1']), am) + + assert CheckAccess(roots, '123=+', UserGroups('1234', []), am) + assert CheckAccess(roots, '124=-', UserGroups('1234', []), am) + assert CheckAccess(roots, '134=+;gr1=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '134=-;gr1=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '124=+', UserGroups('1234', []), am) + assert CheckAccess(roots, '124=-', UserGroups('1234', []), am) + assert CheckAccess(roots, '134=+;gr1=+', UserGroups('1234', ['gr']), am) + assert CheckAccess(roots, '134=-;gr1=+', UserGroups('1234', ['gr']), am) + assert CheckAccess(roots, '124=+;gr=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '124=-;gr=+', UserGroups('1234', ['gr1']), am) + + roots = ['12'] + for am in AccessMode.ADD, AccessMode.DELETE, AccessMode.EDIT, AccessMode.VIEW, AccessMode.ACCEES_EDIT: + assert CheckAccess(roots, '1234=+', UserGroups('1234', []), am) + assert not CheckAccess(roots, '1234=-', UserGroups('1234', []), am) + assert CheckAccess(roots, '1234=+;gr1=+', UserGroups('1234', ['gr1']), am) + assert CheckAccess(roots, '1234=-;gr1=+', UserGroups('1234', ['gr1']), am) + assert not CheckAccess(roots, '1234=+', UserGroups('123', []), am) + assert not CheckAccess(roots, '1234=-', UserGroups('123', []), am) + assert not CheckAccess(roots, '1234=+;gr1=+', UserGroups('123', ['gr']), am) + assert not CheckAccess(roots, '1234=-;gr1=+', UserGroups('123', ['gr']), am) + assert not CheckAccess(roots, '1234=+;gr=+', UserGroups('123', ['gr1']), am) + assert not CheckAccess(roots, '1234=-;gr=+', UserGroups('123', ['gr1']), am) + + assert CheckAccess(roots, '123=-;1234=a', UserGroups('1234', []), AccessMode.ADD) + assert CheckAccess(roots, '123=-;1234=d', UserGroups('1234', []), AccessMode.DELETE) + assert CheckAccess(roots, '123=-;1234=e', UserGroups('1234', []), AccessMode.EDIT) + assert CheckAccess(roots, '123=-;1234=r', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, '123=-;1234=v', UserGroups('1234', []), AccessMode.VIEW) + assert CheckAccess(roots, '123=-;gr1=a', UserGroups('1234', ['gr1']), AccessMode.ADD) + assert CheckAccess(roots, '123=-;gr1=d', UserGroups('1234', ['gr1']), AccessMode.DELETE) + assert CheckAccess(roots, '123=-;gr1=e', UserGroups('1234', ['gr1']), AccessMode.EDIT) + assert CheckAccess(roots, '123=-;gr1=r', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, '123=-;gr1=v', UserGroups('1234', ['gr1']), AccessMode.VIEW) + assert CheckAccess(roots, '123=-;1234=daver', UserGroups('1234', []), AccessMode.ADD) + assert CheckAccess(roots, '123=-;1234=dav', UserGroups('1234', []), AccessMode.DELETE) + assert CheckAccess(roots, '123=-;1234=edv', UserGroups('1234', []), AccessMode.EDIT) + assert CheckAccess(roots, '123=-;1234=rav', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, '123=-;1234=va', UserGroups('1234', []), AccessMode.VIEW) + assert CheckAccess(roots, '123=-;gr1=avr', UserGroups('1234', ['gr1']), AccessMode.ADD) + assert CheckAccess(roots, '123=-;gr1=daver', UserGroups('1234', ['gr1']), AccessMode.DELETE) + assert CheckAccess(roots, '123=-;gr1=eva', UserGroups('1234', ['gr1']), AccessMode.EDIT) + assert CheckAccess(roots, '123=-;gr1=re', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, '123=-;gr1=vad', UserGroups('1234', ['gr1']), AccessMode.VIEW) + + assert not CheckAccess(roots, '123=-;1234=d', UserGroups('1234', []), AccessMode.ADD) + assert not CheckAccess(roots, '123=-;1234=a', UserGroups('1234', []), AccessMode.DELETE) + assert not CheckAccess(roots, '123=-;1234=r', UserGroups('1234', []), AccessMode.EDIT) + assert not CheckAccess(roots, '123=-;1234=v', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, '123=-;1234=e', UserGroups('1234', []), AccessMode.VIEW) + assert not CheckAccess(roots, '123=-;gr1=d', UserGroups('1234', ['gr']), AccessMode.ADD) + assert not CheckAccess(roots, '123=-;gr1=a', UserGroups('1234', ['gr']), AccessMode.DELETE) + assert not CheckAccess(roots, '123=-;gr1=v', UserGroups('1234', ['gr']), AccessMode.EDIT) + assert not CheckAccess(roots, '123=-;gr1=e', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, '123=-;gr1=r', UserGroups('1234', ['gr']), AccessMode.VIEW) + assert not CheckAccess(roots, '123=-;1234=dver', UserGroups('1234', []), AccessMode.ADD) + assert not CheckAccess(roots, '123=-;1234=av', UserGroups('1234', []), AccessMode.DELETE) + assert not CheckAccess(roots, '123=-;1234=dv', UserGroups('1234', []), AccessMode.EDIT) + assert not CheckAccess(roots, '123=-;1234=av', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, '123=-;1234=a', UserGroups('1234', []), AccessMode.VIEW) + assert not CheckAccess(roots, '123=-;gr1=vr', UserGroups('1234', ['gr']), AccessMode.ADD) + assert not CheckAccess(roots, '123=-;gr1=aver', UserGroups('1234', ['gr']), AccessMode.DELETE) + assert not CheckAccess(roots, '123=-;gr1=va', UserGroups('1234', ['gr']), AccessMode.EDIT) + assert not CheckAccess(roots, '123=-;gr1=ea', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, '123=-;gr1=ad', UserGroups('1234', ['gr']), AccessMode.VIEW) + + assert CheckAccess(roots, f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.ADD) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=d', UserGroups('1234', []), AccessMode.DELETE) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=e', UserGroups('1234', []), AccessMode.EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=r', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=v', UserGroups('1234', []), AccessMode.VIEW) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=a', UserGroups('1234', ['gr1']), AccessMode.ADD) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=d', UserGroups('1234', ['gr1']), AccessMode.DELETE) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=e', UserGroups('1234', ['gr1']), AccessMode.EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=r', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=v', UserGroups('1234', ['gr1']), AccessMode.VIEW) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=daver', UserGroups('1234', []), AccessMode.ADD) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=dav', UserGroups('1234', []), AccessMode.DELETE) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=edv', UserGroups('1234', []), AccessMode.EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=rav', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=va', UserGroups('1234', []), AccessMode.VIEW) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=avr', UserGroups('1234', ['gr1']), AccessMode.ADD) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=daver', UserGroups('1234', ['gr1']), AccessMode.DELETE) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=eva', UserGroups('1234', ['gr1']), AccessMode.EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=re', UserGroups('1234', ['gr1']), AccessMode.ACCEES_EDIT) + assert CheckAccess(roots, f'123=-;{user_access_group_all}=vad', UserGroups('1234', ['gr1']), AccessMode.VIEW) + + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=d', UserGroups('1234', []), AccessMode.ADD) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.DELETE) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=r', UserGroups('1234', []), AccessMode.EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=v', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=e', UserGroups('1234', []), AccessMode.VIEW) + assert not CheckAccess(roots, f'123=-;gr1=d;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.ADD) + assert not CheckAccess(roots, f'123=-;gr1=a;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.DELETE) + assert not CheckAccess(roots, f'123=-;gr1=v;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.EDIT) + assert not CheckAccess(roots, f'123=-;gr1=e;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, f'123=-;gr1=r;{user_access_group_all}=-', UserGroups('1234', ['gr']), AccessMode.VIEW) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=dver', UserGroups('1234', []), AccessMode.ADD) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=av', UserGroups('1234', []), AccessMode.DELETE) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=dv', UserGroups('1234', []), AccessMode.EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=av', UserGroups('1234', []), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=a', UserGroups('1234', []), AccessMode.VIEW) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=vr', UserGroups('1234', ['gr']), AccessMode.ADD) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=aver', UserGroups('1234', ['gr']), AccessMode.DELETE) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=va', UserGroups('1234', ['gr']), AccessMode.EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=ea', UserGroups('1234', ['gr']), AccessMode.ACCEES_EDIT) + assert not CheckAccess(roots, f'123=-;{user_access_group_all}=ad', UserGroups('1234', ['gr']), AccessMode.VIEW) diff --git a/bot_sys/user_messages.py b/bot_sys/user_messages.py deleted file mode 100644 index 61e39b2..0000000 --- a/bot_sys/user_messages.py +++ /dev/null @@ -1,56 +0,0 @@ -#-*-coding utf-8-*- -# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) - -import sqlite3 -from bot_sys import log - -# Работа ссообщениями - -default_language = 'ru' - -g_messages = None -def GetMessages(): - global g_messages - if not g_messages: - g_messages = {} - return g_messages - -g_last_update = None -def UpdateSignal(a_DateTime): - global g_last_update - g_last_update = a_DateTime -# --------------------------------------------------------- -# Функции работы с собщениями - -# --------------------------------------------------------- -class Message: - def __init__(self, a_MessageName : str, a_MessageDesc : str, a_Language : str, a_PhotoID : str, a_DateTime): - self.m_MessageName = a_MessageName - self.m_MessageDesc = a_MessageDesc - self.m_Language = a_Language - self.m_PhotoID = a_PhotoID - self.m_DateTime = a_DateTime - - def __str__(self): - global g_last_update - last_update = g_last_update - if self.m_DateTime < last_update: - msg = GetMessages() - if not msg.get(self.m_Language, None): - msg[self.m_Language] = {} - new_msg = msg[self.m_Language].get(self.m_MessageName, self) - self.m_MessageName = new_msg.m_MessageName - self.m_MessageDesc = new_msg.m_MessageDesc - self.m_PhotoID = new_msg.m_PhotoID - self.m_DateTime = last_update - return f'{self.m_MessageDesc}' - -def MSG(a_MessageName, a_MessageDesc, a_UpdateMSG, a_DateTime): - cur_msg = Message(a_MessageName, a_MessageDesc, default_language, 0, a_DateTime) - msg = GetMessages() - if not msg.get(default_language, None): - msg[default_language] = {} - if not msg[default_language].get(a_MessageName, None): - msg[default_language][a_MessageName] = cur_msg - a_UpdateMSG(cur_msg) - diff --git a/main.py b/main.py index f91a227..f48c1ad 100644 --- a/main.py +++ b/main.py @@ -4,45 +4,117 @@ log_start_message = 'Бот успешно запущен!' import os -from aiogram import Bot, types -from aiogram.utils import executor -from aiogram.dispatcher import Dispatcher -from aiogram.contrib.fsm_storage.memory import MemoryStorage -import sqlite3 -from bot_sys import config, log, bot_bd, user_access, user_messages -from bot_modules import profile, start, projects, groups, access, backup, tasks, needs, comments, messages, languages - -storage = MemoryStorage() -bot = Bot(token = config.GetTelegramBotApiToken(), parse_mode = types.ParseMode.HTML) -dp = Dispatcher(bot, storage = storage) - -# Первичная инициализация модулей. Все модули должны быть прописаны в списке modules -modules = [tasks, access, profile, start, projects, groups, backup, needs, comments, messages, languages] - -init_bd_cmd = [] + +from bot_sys import config, log, aiogram_bot, bot_messages, bd_table, user_access +from bot_modules import mod_agregator, start, profile, backup, groups, access, projects, tasks, needs, comments, languages, messages, buttons + +bd_file_name = 'bot.db' + +log_file_name = 'log.txt' + +g_Log = log.Log(log_file_name) +g_Bot = aiogram_bot.AiogramBot(config.GetTelegramBotApiToken(), bd_file_name, config.GetRootIDs(), g_Log) + +default_language = 'ru' + +g_BotMessages = bot_messages.BotMessages(default_language) +g_BotButtons = bot_messages.BotMessages(default_language) + +g_ModuleAgregator = mod_agregator.ModuleAgregator() + +mod_start_name = start.module_name +mod_tasks_name = tasks.module_name +mod_needs_name = needs.module_name +mod_comments_name = comments.module_name +mod_projects_name = projects.module_name +mod_languages_name = languages.module_name +mod_messages_name = messages.module_name +mod_buttons_name = buttons.module_name + +start_mod_list = [mod_start_name] + +mod_access = access.ModuleAccess(start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_access) + +mod_groups = groups.ModuleGroups(start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_groups) + +mod_profile = profile.ModuleProfile(start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_profile) + +mod_backup = backup.ModuleBackup(start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_backup) + +start_mod_name_list = [mod_start_name, mod_tasks_name, mod_needs_name, mod_comments_name] +mod_project = projects.ModuleProjects(None, mod_tasks_name, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_project) + +start_mod_name_list = [mod_start_name]#, mod_projects_name, mod_needs_name, mod_comments_name] +mod_tasks = tasks.ModuleTasks(mod_projects_name, mod_needs_name, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_tasks) + +start_mod_name_list = [mod_start_name]#, mod_projects_name, mod_tasks_name, mod_comments_name] +mod_needs= needs.ModuleNeeds(mod_tasks_name, mod_comments_name, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_needs) + +start_mod_name_list = [mod_start_name]#, mod_projects_name, mod_tasks_name, mod_needs_name] +mod_comments= comments.ModuleComments(mod_needs_name, None, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_comments) + +start_mod_name_list = [mod_start_name, mod_messages_name, mod_buttons_name] +mod_languages = languages.ModuleLanguages(None, mod_messages_name, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_languages) + +start_mod_name_list = [mod_start_name] +mod_messages = messages.ModuleMessages(mod_languages_name, None, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_messages) + +start_mod_name_list = [mod_start_name] +mod_buttons = buttons.ModuleButtons(mod_languages_name, None, start_mod_name_list, start_mod_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_buttons) + +start_mod_name_list = [ + mod_profile.GetName(), + mod_backup.GetName(), + mod_groups.GetName(), + mod_access.GetName(), + mod_project.GetName(), + mod_languages.GetName(), + ] +mod_start = start.ModuleStart(start_mod_name_list, g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log) +g_ModuleAgregator.AddModule(mod_start) + +# Первичная инициализация модулей. +modules = g_ModuleAgregator.GetModList() + +init_bd_cmds = [] for m in modules: c = m.GetInitBDCommands() if not c is None: - init_bd_cmd += c + init_bd_cmds += c + # Первичная инициализация базы данных -bot_bd.BDExecute(init_bd_cmd) +for c in init_bd_cmds: + g_Bot.SQLRequest(c, commit = True) -user_messages.UpdateSignal(log.GetTimeNow()) +g_BotMessages.UpdateSignal(g_Log.GetTimeNow()) +g_BotButtons.UpdateSignal(g_Log.GetTimeNow()) -languages.FlushLanguages() -messages.FlushMessages() +mod_languages.FlushLanguages() +mod_messages.FlushMessages() +mod_buttons.FlushMessages() for m in modules: - m.RegisterHandlers(dp) + m.RegisterHandlers() # Юнит тесты модулей и файлов -test_mods = [user_access] +test_mods = [user_access, bd_table] for m in test_mods: m.Test() if __name__ == '__main__': # os.system('clear') # os.system('cls') - log.Success(log_start_message) + g_Log.Success(log_start_message) -executor.start_polling(dp) +g_Bot.StartPolling() diff --git a/template/bd_item.py b/template/bd_item.py index 1c6e1e0..b0cadc6 100644 --- a/template/bd_item.py +++ b/template/bd_item.py @@ -4,8 +4,8 @@ # Работа с элементом в БД from enum import Enum -from bot_sys import user_access, bot_bd, keyboard, log -from bot_modules import groups, access +from bot_sys import user_access, bot_bd, keyboard, bot_messages +from bot_modules import groups_utils, access_utils from template import simple_message from aiogram import types @@ -20,7 +20,7 @@ canсel_button_name = "🚫 Отменить" def HashPrefix(a_Str): # callback data в сообщении имеет ограниченную длину, поэтому сокращаем префикс - #log.Info(f'HashPrefix {md5(a_Str)[0:8]}: - {a_Str}') + #a_Bot.GetLog().Info(f'HashPrefix {md5(a_Str)[0:8]}: - {a_Str}') return f'{md5(a_Str)[0:8]}:' class FieldType(Enum): @@ -31,7 +31,10 @@ def GetCheckForPrefixFunc(a_Prefix): return lambda x: x.data.startswith(a_Prefix) def GetCheckForTextFunc(a_Text): - return lambda x: x.text == a_Text + return lambda x: x.text == str(a_Text) + +def GetCheckForCommandsFunc(a_Commands): + return lambda x: x.commands == a_Commands def GetKeyDataFromCallbackMessage(a_Message, a_Prefix): key_item_id = None @@ -39,60 +42,60 @@ def GetKeyDataFromCallbackMessage(a_Message, a_Prefix): key_item_id = str(a_Message.data).replace(a_Prefix, '') return key_item_id -def GetCancelKeyboardButtonsTemplate(a_AccessFunc, a_AccessMode): +def GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, a_AccessMode): def GetCancelKeyboardButtons(a_Message, a_UserGroups): cur_buttons = [ keyboard.ButtonWithAccess(canсel_button_name, a_AccessMode, a_AccessFunc()), ] - return keyboard.MakeKeyboard(cur_buttons, a_UserGroups) + return keyboard.MakeButtons(a_Bot, cur_buttons, a_UserGroups) return GetCancelKeyboardButtons -def GetSkipAndCancelKeyboardButtonsTemplate(a_AccessFunc, a_AccessMode): +def GetSkipAndCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, a_AccessMode): def GetSkipAndCancelKeyboardButtons(a_Message, a_UserGroups): cur_buttons = [ keyboard.ButtonWithAccess(skip_button_name, a_AccessMode, a_AccessFunc()), keyboard.ButtonWithAccess(canсel_button_name, a_AccessMode, a_AccessFunc()), ] - return keyboard.MakeKeyboard(cur_buttons, a_UserGroups) + return keyboard.MakeButtons(a_Bot, cur_buttons, a_UserGroups) return GetSkipAndCancelKeyboardButtons -def GetAllItemsTemplate(a_TableName): +def GetAllItemsTemplate(a_Bot, a_TableName): def GetAllItems(): - return bot_bd.SelectBDTemplate(a_TableName)() + return bot_bd.SelectBDTemplate(a_Bot, a_TableName)() return GetAllItems -def GetBDItemsTemplate(a_TableName : str, a_KeyName : str): +def GetBDItemsTemplate(a_Bot, a_TableName : str, a_KeyName : str): def GetBDItem(a_KeyValue): - return bot_bd.SQLRequestToBD(f'SELECT * FROM {a_TableName} WHERE {a_KeyName} = ?', param = ([a_KeyValue])) + return a_Bot.SQLRequest(f'SELECT * FROM {a_TableName} WHERE {a_KeyName} = ?', param = ([a_KeyValue])) return GetBDItem -def DeleteBDItemInTableTemplate(a_TableName : str, a_KeyName : str): +def DeleteBDItemInTableTemplate(a_Bot, a_TableName : str, a_KeyName : str): def DeleteBDItem(a_KeyValue): - return bot_bd.SQLRequestToBD(f'DELETE FROM {a_TableName} WHERE {a_KeyName} = ?', commit = True, return_error = True, param = ([a_KeyValue])) + return a_Bot.SQLRequest(f'DELETE FROM {a_TableName} WHERE {a_KeyName} = ?', commit = True, return_error = True, param = ([a_KeyValue])) return DeleteBDItem -def EditBDItemInTableTemplate(a_TableName : str, a_KeyName : str, a_FieldName : str): +def EditBDItemInTableTemplate(a_Bot, a_TableName : str, a_KeyName : str, a_FieldName : str): def EditBDItemInTable(a_KeyValue, a_FieldValue): - return bot_bd.SQLRequestToBD(f'UPDATE {a_TableName} SET {a_FieldName}=? WHERE {a_KeyName} = ?', commit = True, return_error = True, param = ([a_FieldValue, a_KeyValue])) + return a_Bot.SQLRequest(f'UPDATE {a_TableName} SET {a_FieldName}=? WHERE {a_KeyName} = ?', commit = True, return_error = True, param = ([a_FieldValue, a_KeyValue])) return EditBDItemInTable -def CheckAccessBDItemTemplate(a_TableName, a_KeyName, a_KeyValue, a_WorkFunc, a_AccessMode : user_access.AccessMode): +def CheckAccessBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_KeyValue, a_WorkFunc, a_AccessMode : user_access.AccessMode): async def CheckAccessBDItem(a_CallbackQuery : types.CallbackQuery): user_id = str(a_CallbackQuery.from_user.id) - user_groups = groups.GetUserGroupData(user_id) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) item_id = a_KeyValue - item = GetBDItemsTemplate(a_TableName, a_KeyName)(item_id) + item = GetBDItemsTemplate(a_Bot, a_TableName, a_KeyName)(item_id) if len(item) < 1: msg = item_not_found.replace('{item_id}', str(item_id)).replace('{a_TableName}', a_TableName) - log.Error(msg) - return simple_message.WorkFuncResult(msg), None + a_Bot.GetLog().Error(msg) + return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(msg)), None result_work_func = await a_WorkFunc(a_CallbackQuery, item[0]) - if result_work_func is None or result_work_func.string_message is None: + if result_work_func is None or result_work_func.m_BotMessage is None: return result_work_func, result_work_func - if not result_work_func.item_access is None and not user_access.CheckAccessString(result_work_func.item_access, user_groups, a_AccessMode): - return simple_message.WorkFuncResult(access.access_denied_message), None + if not result_work_func.item_access is None and not user_access.CheckAccess(a_Bot.GetRootIDs(), result_work_func.item_access, user_groups, a_AccessMode): + return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(access_utils.access_denied_message)), None return None, result_work_func return CheckAccessBDItem diff --git a/template/bd_item_add.py b/template/bd_item_add.py index 2ea4aa5..2bcb39d 100644 --- a/template/bd_item_add.py +++ b/template/bd_item_add.py @@ -3,23 +3,18 @@ # Добавление элемента в БД -from bot_sys import user_access, bot_bd, log -from bot_modules import access, groups +from bot_sys import user_access, bot_bd, bot_messages +from bot_modules import access_utils, groups_utils from template import simple_message, bd_item_select, bd_item -from aiogram import types -from aiogram.dispatcher import FSMContext -from aiogram.dispatcher.filters.state import State, StatesGroup - - cancel_message = ''' 🚫 Добавление отменено ''' -def StartAddBDItemTemplate(a_FSM, a_FSMStart, a_MessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.ADD): - async def StartAddBDItem(a_CallbackQuery : types.CallbackQuery, state : FSMContext): +def StartAddBDItemTemplate(a_Bot, a_FSM, a_FSMStart, a_MessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.ADD): + async def StartAddBDItem(a_CallbackQuery, state): user_id = str(a_CallbackQuery.from_user.id) - user_groups = groups.GetUserGroupData(user_id) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) parent_id = bd_item.GetKeyDataFromCallbackMessage(a_CallbackQuery, a_Prefix) res_of_work_func = None check = None @@ -30,7 +25,7 @@ def StartAddBDItemTemplate(a_FSM, a_FSMStart, a_MessageFunc, a_ParentTableName, item_data[a_ParentKeyFieldName] = parent_id if parent_id: - check, res_of_work_func = await bd_item.CheckAccessBDItemTemplate(a_ParentTableName, a_ParentKeyFieldName, parent_id, a_MessageFunc, access_mode)(a_CallbackQuery) + 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) @@ -39,36 +34,36 @@ def StartAddBDItemTemplate(a_FSM, a_FSMStart, a_MessageFunc, a_ParentTableName, check.keyboard_func = a_FinishButtonFunc return check return res_of_work_func - return simple_message.SimpleMessageTemplate(StartAddBDItem, a_ButtonFunc, a_AccessFunc, access_mode) + return simple_message.SimpleMessageTemplate(a_Bot, StartAddBDItem, a_ButtonFunc, None, a_AccessFunc, access_mode) -def FinishAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): - return FinishOrNextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_ButtonFunc, True, access_mode = access_mode, field_type = field_type) +def FinishAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): + return FinishOrNextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_ButtonFunc, True, access_mode = access_mode, field_type = field_type) -def NextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): - return FinishOrNextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, False, access_mode = access_mode, field_type = field_type) +def NextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): + return FinishOrNextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, False, access_mode = access_mode, field_type = field_type) -def FinishOrNextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, a_Finish, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): - async def FinishAddBDItem(a_Message : types.CallbackQuery, state : FSMContext): +def FinishOrNextAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, a_Finish, access_mode = user_access.AccessMode.ADD, field_type = bd_item.FieldType.text): + async def FinishAddBDItem(a_Message, state): state_func = None if a_Finish: state_func = state.finish else: state_func = a_FSM.next user_id = str(a_Message.from_user.id) - user_groups = groups.GetUserGroupData(user_id) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) error = None res_of_work_func = None check = None async with state.proxy() as item_data: if a_Message.text == bd_item.canсel_button_name: await state.finish() - return simple_message.WorkFuncResult(cancel_message, keyboard_func = a_FinishButtonFunc) + return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(cancel_message), keyboard_func = a_FinishButtonFunc) parent_id = None if a_ParentKeyFieldName: parent_id = item_data[a_ParentKeyFieldName] if parent_id: - check, res_of_work_func = await bd_item.CheckAccessBDItemTemplate(a_ParentTableName, a_ParentKeyFieldName, parent_id, a_MessageFunc, access_mode)(a_Message) + 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) @@ -83,7 +78,7 @@ def FinishOrNextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_P else: if a_Message.photo == None or len(a_Message.photo) == 0: await state.finish() - return simple_message.WorkFuncResult(error_photo_type_message, keyboard_func = a_FinishButtonFunc) + return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(error_photo_type_message), keyboard_func = a_FinishButtonFunc) field_value = a_Message.photo[0].file_id else: field_value = a_Message.text @@ -92,31 +87,32 @@ def FinishOrNextAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_P res, error = a_AddBDItemFunc(item_data, user_id) await state_func() if error: - return simple_message.WorkFuncResult(error) + return simple_message.WorkFuncResult(bot_messages.MakeBotMessage(error)) return res_of_work_func - return simple_message.SimpleMessageTemplate(FinishAddBDItem, a_ButtonFunc, a_AccessFunc, access_mode) + return simple_message.SimpleMessageTemplate(a_Bot, FinishAddBDItem, a_ButtonFunc, None, a_AccessFunc, access_mode) -def AddBDItem3RegisterHandlers(dp, a_StartCheckFunc, a_FSM, a_FSMName, a_FSMDesc, a_FSMPhoto, a_AddBDItemFunc, a_AddNameMessageFunc, a_AddDescMessageFunc, a_AddPhotoMessageFunc, a_FinishMessageFunc, a_ParentPrefix, a_ParentTableName : str, a_ParentKeyFieldName, a_NameField, a_DescField, a_PhotoField, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.ADD): - keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_AccessFunc, access_mode) - keyboard_skip_and_cancel = bd_item.GetSkipAndCancelKeyboardButtonsTemplate(a_AccessFunc, access_mode) - reg_func = dp.register_message_handler +def AddBDItem3RegisterHandlers(a_Bot, a_StartCheckFunc, a_FSM, a_FSMName, a_FSMDesc, a_FSMPhoto, a_AddBDItemFunc, a_AddNameMessageFunc, a_AddDescMessageFunc, a_AddPhotoMessageFunc, a_FinishMessageFunc, a_ParentPrefix, a_ParentTableName : str, a_ParentKeyFieldName, a_NameField, a_DescField, a_PhotoField, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.ADD): + keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, access_mode) + keyboard_skip_and_cancel = bd_item.GetSkipAndCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, access_mode) + reg_func = a_Bot.RegisterMessageHandler if a_ParentTableName: - reg_func = dp.register_callback_query_handler - reg_func(StartAddBDItemTemplate(a_FSM, a_FSMName, a_AddNameMessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_ParentPrefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), a_StartCheckFunc) + reg_func = a_Bot.RegisterCallbackHandler + reg_func(StartAddBDItemTemplate(a_Bot, a_FSM, a_FSMName, a_AddNameMessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_ParentPrefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), a_StartCheckFunc) - dp.register_message_handler(NextAddBDItemTemplate(a_FSM, None, a_ParentTableName, a_ParentKeyFieldName, a_NameField, a_AddDescMessageFunc, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.text), state = a_FSMName) - dp.register_message_handler(NextAddBDItemTemplate(a_FSM, None, a_ParentTableName, a_ParentKeyFieldName, a_DescField, a_AddPhotoMessageFunc, a_AccessFunc, keyboard_skip_and_cancel, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.text), state = a_FSMDesc) - dp.register_message_handler(FinishAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_PhotoField, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.photo), content_types = ['photo', 'text'], state = a_FSMPhoto) + # TODO: Сделать возможность не указывать все поля. пусть a_FSMName и a_NameField например могут быть пустыми. Возможно лучше вообще передавать список полей и их fsm + a_Bot.RegisterMessageHandler(NextAddBDItemTemplate(a_Bot, a_FSM, None, a_ParentTableName, a_ParentKeyFieldName, a_NameField, a_AddDescMessageFunc, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.text), state = a_FSMName) + a_Bot.RegisterMessageHandler(NextAddBDItemTemplate(a_Bot, a_FSM, None, a_ParentTableName, a_ParentKeyFieldName, a_DescField, a_AddPhotoMessageFunc, a_AccessFunc, keyboard_skip_and_cancel, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.text), state = a_FSMDesc) + a_Bot.RegisterMessageHandler(FinishAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_PhotoField, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = bd_item.FieldType.photo), content_types = ['photo', 'text'], state = a_FSMPhoto) -def AddBDItem1RegisterHandlers(dp, a_StartCheckFunc, a_FSM, a_AddBDItemFunc, a_AddMessageFunc, a_FinishMessageFunc, a_ParentPrefix, a_ParentTableName : str, a_ParentKeyFieldName, a_FieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, a_FieldType, access_mode = user_access.AccessMode.ADD): - keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_AccessFunc, access_mode) - reg_func = dp.register_message_handler +def AddBDItem1RegisterHandlers(a_Bot, a_StartCheckFunc, a_FSM, a_AddBDItemFunc, a_AddMessageFunc, a_FinishMessageFunc, a_ParentPrefix, a_ParentTableName : str, a_ParentKeyFieldName, a_FieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, a_FieldType, access_mode = user_access.AccessMode.ADD): + keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, access_mode) + reg_func = a_Bot.RegisterMessageHandler if a_ParentTableName: - reg_func = dp.register_callback_query_handler - reg_func(StartAddBDItemTemplate(a_FSM, a_FSM.bd_item, a_AddMessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_ParentPrefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), a_StartCheckFunc) - finish_handler = FinishAddBDItemTemplate(a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = a_FieldType) + reg_func = a_Bot.RegisterCallbackHandler + reg_func(StartAddBDItemTemplate(a_Bot, a_FSM, a_FSM.bd_item, a_AddMessageFunc, a_ParentTableName, a_ParentKeyFieldName, a_ParentPrefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), a_StartCheckFunc) + finish_handler = FinishAddBDItemTemplate(a_Bot, a_FSM, a_AddBDItemFunc, a_ParentTableName, a_ParentKeyFieldName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = a_FieldType) if a_FieldType == bd_item.FieldType.photo: - dp.register_message_handler(finish_handler, content_types = ['photo', 'text'], state = a_FSM.bd_item) + a_Bot.RegisterMessageHandler(finish_handler, content_types = ['photo', 'text'], state = a_FSM.bd_item) else: - dp.register_message_handler(finish_handler, state = a_FSM.bd_item) + a_Bot.RegisterMessageHandler(finish_handler, state = a_FSM.bd_item) diff --git a/template/bd_item_delete.py b/template/bd_item_delete.py index 033c5de..7c7a355 100644 --- a/template/bd_item_delete.py +++ b/template/bd_item_delete.py @@ -4,40 +4,41 @@ # удаление элемента в БД from bot_sys import user_access, bot_bd, keyboard -from bot_modules import access, groups +from bot_modules import access_utils, groups_utils from template import simple_message, bd_item_select, bd_item -from aiogram import types - -def DeleteBDItemTemplate(a_TableName, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, delete = True, access_mode = user_access.AccessMode.DELETE): - async def DeleteBDItem(a_CallbackQuery : types.CallbackQuery, state = None): +def DeleteBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, delete = True, access_mode = user_access.AccessMode.DELETE): + async def DeleteBDItem(a_CallbackQuery, state = None): user_id = str(a_CallbackQuery.from_user.id) - user_groups = groups.GetUserGroupData(user_id) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) item_id = str(a_CallbackQuery.data).replace(a_Prefix, '') - check, res_of_pre_del = await bd_item.CheckAccessBDItemTemplate(a_TableName, a_KeyName, item_id, a_PreDeleteWorkFunc, access_mode)(a_CallbackQuery) + check, res_of_pre_del = await bd_item.CheckAccessBDItemTemplate(a_Bot, a_TableName, a_KeyName, item_id, a_PreDeleteWorkFunc, access_mode)(a_CallbackQuery) if not check is None: return check if not delete: return res_of_pre_del - result, error = bd_item.DeleteBDItemInTableTemplate(a_TableName, a_KeyName)(item_id) + result, error = bd_item.DeleteBDItemInTableTemplate(a_Bot, a_TableName, a_KeyName)(item_id) if not error is None: msg = error - log.Error(error) + a_Bot.GetLog().Error(error) return simple_message.WorkFuncResult(error) return await a_PostDeleteWorkFunc(a_CallbackQuery, item_id) - return simple_message.SimpleMessageTemplate(DeleteBDItem, a_ButtonFunc, a_AccessFunc, access_mode) + return simple_message.SimpleMessageTemplate(a_Bot, DeleteBDItem, a_ButtonFunc, None, a_AccessFunc, access_mode) -def DeleteBDItemRegisterHandlers(dp, a_PrevPrefix, a_StartCheckFunc, a_TableName : str, a_KeyName, a_ParentIDFieldName,a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.DELETE): - reg_func = dp.register_message_handler +def SelectAndDeleteBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_StartCheckFunc, a_TableName : str, a_KeyName, a_ParentIDFieldName,a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.DELETE): + reg_func = a_Bot.RegisterMessageHandler if a_ParentIDFieldName: - reg_func = dp.register_callback_query_handler + reg_func = a_Bot.RegisterCallbackHandler a_Prefix = bd_item.HashPrefix(f'delete_{a_TableName}_{a_KeyName}:') - sel_handler = bd_item_select.SelectDBItemTemplate(a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode) + sel_handler = bd_item_select.SelectDBItemTemplate(a_Bot, a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode) reg_func(sel_handler, a_StartCheckFunc) - dp.register_callback_query_handler(DeleteBDItemTemplate(a_TableName, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode), bd_item.GetCheckForPrefixFunc(a_Prefix)) + a_Bot.RegisterCallbackHandler(DeleteBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode), bd_item.GetCheckForPrefixFunc(a_Prefix)) + +def DeleteBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_TableName : str, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.DELETE): + a_Bot.RegisterCallbackHandler(DeleteBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_PreDeleteWorkFunc, a_PostDeleteWorkFunc, a_PrevPrefix, a_AccessFunc, a_ButtonFunc, access_mode), bd_item.GetCheckForPrefixFunc(a_PrevPrefix)) diff --git a/template/bd_item_edit.py b/template/bd_item_edit.py index 99e3e44..a665349 100644 --- a/template/bd_item_edit.py +++ b/template/bd_item_edit.py @@ -3,14 +3,10 @@ # Редактирование элемента в БД -from bot_sys import user_access, bot_bd, log -from bot_modules import access, groups +from bot_sys import user_access, bot_bd +from bot_modules import access_utils, groups_utils from template import simple_message, bd_item_select, bd_item, bd_item_add -from aiogram import types -from aiogram.dispatcher import FSMContext -from aiogram.dispatcher.filters.state import State, StatesGroup - cancel_message = ''' 🚫 Редактирование отменено ''' @@ -19,33 +15,35 @@ error_photo_type_message = ''' 🚫 Фотографий не найдено ''' -def StartEditBDItemTemplate(a_FSM, a_MessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.EDIT): - return bd_item_add.StartAddBDItemTemplate(a_FSM, a_FSM.item_field, a_MessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = access_mode) +def StartEditBDItemTemplate(a_Bot, a_FSM, a_MessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = user_access.AccessMode.EDIT): + return bd_item_add.StartAddBDItemTemplate(a_Bot, a_FSM, a_FSM.item_field, a_MessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, a_ButtonFunc, a_FinishButtonFunc, access_mode = access_mode) -def FinishEditBDItemTemplate(a_FSM, a_TableName, a_KeyName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.EDIT, field_type = bd_item.FieldType.text): +def FinishEditBDItemTemplate(a_Bot, a_FSM, a_TableName, a_KeyName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, a_OnChangeFunc, access_mode = user_access.AccessMode.EDIT, field_type = bd_item.FieldType.text): def EditBDItemFunc(a_ItemData, a_UserID): item_id = a_ItemData[a_KeyName] field_value = a_ItemData[a_FieldName] - res, error = bd_item.EditBDItemInTableTemplate(a_TableName, a_KeyName, a_FieldName)(item_id, field_value) + res, error = bd_item.EditBDItemInTableTemplate(a_Bot, a_TableName, a_KeyName, a_FieldName)(item_id, field_value) if error: - log.Error(f'Пользователю {a_UserID} не удалось изменить поле в таблице {a_TableName} ключу {a_KeyName}={item_id}. Новое значение поля {a_FieldName}={field_value}. Ошибка: {error}') + a_Bot.GetLog().Error(f'Пользователю {a_UserID} не удалось изменить поле в таблице {a_TableName} ключу {a_KeyName}={item_id}. Новое значение поля {a_FieldName}={field_value}. Ошибка: {error}') else: - log.Success(f'Пользователь {a_UserID} изменил поле в таблице {a_TableName} ключу {a_KeyName}={item_id}. Новое значение поля {a_FieldName}={field_value}.') + a_Bot.GetLog().Success(f'Пользователь {a_UserID} изменил поле в таблице {a_TableName} ключу {a_KeyName}={item_id}. Новое значение поля {a_FieldName}={field_value}.') + + a_OnChangeFunc() return res, error - return bd_item_add.FinishAddBDItemTemplate(a_FSM, EditBDItemFunc, a_TableName, a_KeyName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode, field_type = field_type) + return bd_item_add.FinishAddBDItemTemplate(a_Bot, a_FSM, EditBDItemFunc, a_TableName, a_KeyName, a_FieldName, a_MessageFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode, field_type = field_type) -def EditBDItemRegisterHandlers(dp, a_PrevPrefix, a_FSM, a_StartCheckFunc, a_StartMessage, a_EditMessageFunc, a_FinishMessageFunc, a_TableName : str, a_KeyName, a_ParentIDFieldName, a_FieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.EDIT, field_type = bd_item.FieldType.text): - reg_func = dp.register_message_handler +def EditBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_FSM, a_StartCheckFunc, a_StartMessage, a_EditMessageFunc, a_FinishMessageFunc, a_TableName : str, a_KeyName, a_ParentIDFieldName, a_FieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_AccessFunc, a_ButtonFunc, a_OnChangeFunc, access_mode = user_access.AccessMode.EDIT, field_type = bd_item.FieldType.text): + reg_func = a_Bot.RegisterMessageHandler if a_ParentIDFieldName: - reg_func = dp.register_callback_query_handler + reg_func = a_Bot.RegisterCallbackHandler - keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_AccessFunc, access_mode) + keyboard_cancel = bd_item.GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, access_mode) a_Prefix = bd_item.HashPrefix(f'edit_{a_TableName}_{a_KeyName}_{a_FieldName}:') - sel_handler = bd_item_select.SelectDBItemTemplate(a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode) + sel_handler = bd_item_select.SelectDBItemTemplate(a_Bot, a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode) reg_func(sel_handler, a_StartCheckFunc) - dp.register_callback_query_handler(StartEditBDItemTemplate(a_FSM, a_EditMessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), bd_item.GetCheckForPrefixFunc(a_Prefix)) + a_Bot.RegisterCallbackHandler(StartEditBDItemTemplate(a_Bot, a_FSM, a_EditMessageFunc, a_TableName, a_KeyName, a_Prefix, a_AccessFunc, keyboard_cancel, a_ButtonFunc, access_mode), bd_item.GetCheckForPrefixFunc(a_Prefix)) if field_type == bd_item.FieldType.photo: - dp.register_message_handler(FinishEditBDItemTemplate(a_FSM, a_TableName, a_KeyName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = field_type), content_types = ['photo', 'text'], state = a_FSM.item_field) + a_Bot.RegisterMessageHandler(FinishEditBDItemTemplate(a_Bot, a_FSM, a_TableName, a_KeyName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, a_OnChangeFunc, access_mode, field_type = field_type), content_types = ['photo', 'text'], state = a_FSM.item_field) else: - dp.register_message_handler(FinishEditBDItemTemplate(a_FSM, a_TableName, a_KeyName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, access_mode, field_type = field_type), state = a_FSM.item_field) + a_Bot.RegisterMessageHandler(FinishEditBDItemTemplate(a_Bot, a_FSM, a_TableName, a_KeyName, a_FieldName, a_FinishMessageFunc, a_AccessFunc, a_ButtonFunc, a_OnChangeFunc, access_mode, field_type = field_type), state = a_FSM.item_field) diff --git a/template/bd_item_select.py b/template/bd_item_select.py index e5344e4..2e199bd 100644 --- a/template/bd_item_select.py +++ b/template/bd_item_select.py @@ -4,19 +4,17 @@ # Просмотр элемента в БД from bot_sys import user_access, bot_bd, keyboard -from bot_modules import access, groups +from bot_modules import access_utils, groups_utils from template import simple_message, bd_item -from aiogram import types - -def GetBDItemsListKeyboardButtonsTemplate(a_TableName : str, a_ParentIDFieldName, a_PrevPrefix, a_NextPrefix : str, a_GetButtonNameAndKeyValueAndAccessFunc, access_mode = user_access.AccessMode.VIEW): +def GetBDItemsListKeyboardButtonsTemplate(a_Bot, a_TableName : str, a_ParentIDFieldName, a_PrevPrefix, a_NextPrefix : str, a_GetButtonNameAndKeyValueAndAccessFunc, access_mode = user_access.AccessMode.VIEW): def GetBDItemsListKeyboardButtons(a_Message, a_UserGroups): parent_id = bd_item.GetKeyDataFromCallbackMessage(a_Message, a_PrevPrefix) items = [] if a_ParentIDFieldName and parent_id and parent_id != '': - items = bd_item.GetBDItemsTemplate(a_TableName, a_ParentIDFieldName)(parent_id) + items = bd_item.GetBDItemsTemplate(a_Bot, a_TableName, a_ParentIDFieldName)(parent_id) else: - items = bd_item.GetAllItemsTemplate(a_TableName)() + items = bd_item.GetAllItemsTemplate(a_Bot, a_TableName)() items_button_list = [] for t in items: @@ -24,28 +22,28 @@ def GetBDItemsListKeyboardButtonsTemplate(a_TableName : str, a_ParentIDFieldName if access is None: access = '' if bname: - b = keyboard.InlineButton(bname, a_NextPrefix, key_value, access, access_mode) + b = keyboard.InlineButtonWithAccess(bname, a_NextPrefix, key_value, access, access_mode) items_button_list += [b] - return keyboard.MakeInlineKeyboard(items_button_list, a_UserGroups) + return keyboard.MakeInlineKeyboardButtons(a_Bot, items_button_list, a_UserGroups) return GetBDItemsListKeyboardButtons -def SelectDBItemTemplate(a_TableName : str, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_NextPrefix, access_mode = user_access.AccessMode.VIEW): - keyboard_func = GetBDItemsListKeyboardButtonsTemplate(a_TableName, a_ParentIDFieldName, a_PrevPrefix, a_NextPrefix, a_GetButtonNameAndKeyValueAndAccessFunc) - return simple_message.InfoMessageTemplate(a_StartMessage, keyboard_func, a_AccessFunc, access_mode) +def SelectDBItemTemplate(a_Bot, a_TableName : str, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_NextPrefix, access_mode = user_access.AccessMode.VIEW): + inline_keyboard_func = GetBDItemsListKeyboardButtonsTemplate(a_Bot, a_TableName, a_ParentIDFieldName, a_PrevPrefix, a_NextPrefix, a_GetButtonNameAndKeyValueAndAccessFunc) + return simple_message.InfoMessageTemplate(a_Bot, a_StartMessage, None, inline_keyboard_func, a_AccessFunc, access_mode) -def FirstSelectBDItemRegisterHandlers(dp, a_PrefixBase, a_ButtonName, a_TableName : str, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): +def FirstSelectBDItemRegisterHandlers(a_Bot, a_PrefixBase, a_ButtonName, a_TableName : str, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): a_Prefix = bd_item.HashPrefix(f'first_select_{a_TableName}_{a_KeyName}_in_base_{a_PrefixBase}:') - sel_handler = SelectDBItemTemplate(a_TableName, None, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, None, a_Prefix, access_mode = access_mode) - dp.register_message_handler(sel_handler, text = a_ButtonName) + sel_handler = SelectDBItemTemplate(a_Bot, a_TableName, None, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, None, a_Prefix, access_mode = access_mode) + a_Bot.RegisterMessageHandler(sel_handler, bd_item.GetCheckForTextFunc(a_ButtonName)) return a_Prefix -def NextSelectBDItemRegisterHandlers(dp, a_PrevPrefix, a_ParentIDFieldName, a_TableName : str, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): +def NextSelectBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_ParentIDFieldName, a_TableName : str, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): a_Prefix = bd_item.HashPrefix(f'next_select_{a_TableName}_{a_KeyName}_{a_ParentIDFieldName}_after_prefix_{a_PrevPrefix}:') - sel_handler = SelectDBItemTemplate(a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode = access_mode) - dp.register_callback_query_handler(sel_handler, bd_item.GetCheckForPrefixFunc(a_PrevPrefix)) + sel_handler = SelectDBItemTemplate(a_Bot, a_TableName, a_ParentIDFieldName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_PrevPrefix, a_Prefix, access_mode = access_mode) + a_Bot.RegisterCallbackHandler(sel_handler, bd_item.GetCheckForPrefixFunc(a_PrevPrefix)) return a_Prefix diff --git a/template/bd_item_view.py b/template/bd_item_view.py index 6e896be..e40b06f 100644 --- a/template/bd_item_view.py +++ b/template/bd_item_view.py @@ -4,21 +4,19 @@ # Просмотр элемента в БД from bot_sys import user_access, bot_bd, keyboard -from bot_modules import access, groups +from bot_modules import access_utils, groups_utils from template import simple_message, bd_item_select, bd_item_delete, bd_item -from aiogram import types +def ShowBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_WorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): + return bd_item_delete.DeleteBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_WorkFunc, None, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode = access_mode, delete = False) -def ShowBDItemTemplate(a_TableName, a_KeyName, a_WorkFunc, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): - return bd_item_delete.DeleteBDItemTemplate(a_TableName, a_KeyName, a_WorkFunc, None, a_Prefix, a_AccessFunc, a_ButtonFunc, access_mode = access_mode, delete = False) +def ShowBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): + a_Bot.RegisterCallbackHandler(ShowBDItemTemplate(a_Bot, a_TableName, a_KeyName, a_ShowItemWorkFunc, a_PrevPrefix, a_AccessFunc, a_ButtonFunc, access_mode = access_mode), bd_item.GetCheckForPrefixFunc(a_PrevPrefix)) -def ShowBDItemRegisterHandlers(dp, a_PrevPrefix, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): - dp.register_callback_query_handler(ShowBDItemTemplate(a_TableName, a_KeyName, a_ShowItemWorkFunc, a_PrevPrefix, a_AccessFunc, a_ButtonFunc, access_mode = access_mode), bd_item.GetCheckForPrefixFunc(a_PrevPrefix)) +def FirstSelectAndShowBDItemRegisterHandlers(a_Bot, a_ButtonName, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): + a_Prefix = bd_item_select.FirstSelectBDItemRegisterHandlers(a_Bot, '', a_ButtonName, a_TableName, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = access_mode) + ShowBDItemRegisterHandlers(a_Bot, a_Prefix, a_TableName, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode) -def FirstSelectAndShowBDItemRegisterHandlers(dp, a_ButtonName, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): - a_Prefix = bd_item_select.FirstSelectBDItemRegisterHandlers(dp, '', a_ButtonName, a_TableName, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = access_mode) - ShowBDItemRegisterHandlers(dp, a_Prefix, a_TableName, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode) - -def LastSelectAndShowBDItemRegisterHandlers(dp, a_PrevPrefix, a_ParentIDFieldName, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): - a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(dp, a_PrevPrefix, a_ParentIDFieldName, a_TableName, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = access_mode) - ShowBDItemRegisterHandlers(dp, a_Prefix, a_TableName, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode) +def LastSelectAndShowBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_ParentIDFieldName, a_TableName : str, a_KeyName, a_ShowItemWorkFunc, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, a_ButtonFunc, access_mode = user_access.AccessMode.VIEW): + a_Prefix = bd_item_select.NextSelectBDItemRegisterHandlers(a_Bot, a_PrevPrefix, a_ParentIDFieldName, a_TableName, a_KeyName, a_GetButtonNameAndKeyValueAndAccessFunc, a_StartMessage, a_AccessFunc, access_mode = access_mode) + ShowBDItemRegisterHandlers(a_Bot, a_Prefix, a_TableName, a_KeyName, a_ShowItemWorkFunc, a_AccessFunc, a_ButtonFunc, access_mode = access_mode) diff --git a/template/file_message.py b/template/file_message.py index aa69670..fe7e6a7 100644 --- a/template/file_message.py +++ b/template/file_message.py @@ -4,32 +4,37 @@ # Сообщения для работы с файлами from bot_sys import log, config, user_access -from bot_modules import access, groups -from aiogram import Bot, types +from bot_modules import groups_utils +from template import simple_message -from aiogram.dispatcher import Dispatcher - -bot = Bot(token=config.GetTelegramBotApiToken(), parse_mode=types.ParseMode.HTML) - -def BackupFileTemplate(a_Path, a_CaptionMessage, a_AccessFunc, a_ButtonFunc, a_ErrorMessage): +def BackupFileTemplate(a_Bot, a_Path, a_CaptionMessage, a_AccessFunc, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_ErrorMessage, access_mode = user_access.AccessMode.EDIT): async def BackupFile(a_Message): user_id = str(a_Message.from_user.id) - user_groups= groups.GetUserGroupData(user_id) - if not user_access.CheckAccessString(a_AccessFunc(), user_groups, user_access.AccessMode.EDIT): - return await a_Message.answer(access.access_denied_message, reply_markup = a_ButtonFunc(a_Message, user_groups)) + 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) - document = await GetFile(a_Path) + document = await GetFile(a_Bot, a_Path) if document is None: - return await a_Message.answer(user_id, error_backup_message, reply_markup = a_ButtonFunc(a_Message, user_groups)) - - await bot.send_document(user_id, document, caption = a_CaptionMessage.replace('@time', log.GetTime()), reply_markup = a_ButtonFunc(a_Message, user_groups)) + return 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()) + + 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 BackupFile -async def GetFile(a_Path): +async def GetFile(a_Bot, a_Path): try: document = open(a_Path, 'rb') - log.Success(f'Загружен файл {a_Path}') + a_Bot.GetLog().Success(f'Загружен файл {a_Path}') return document except Exception as e: - log.Error(f'Не удалось загрузить файл {a_Path}. Ошибка {str(e)}') + a_Bot.GetLog().Error(f'Не удалось загрузить файл {a_Path}. Ошибка {str(e)}') return None diff --git a/template/simple_message.py b/template/simple_message.py index b01a6b9..7da195b 100644 --- a/template/simple_message.py +++ b/template/simple_message.py @@ -3,53 +3,78 @@ # Простые информационные сообщения -from bot_sys import user_access, config -from bot_modules import access, groups +from bot_sys import user_access +from bot_modules import access_utils, groups_utils from aiogram import types -from aiogram import Bot -bot = Bot(token=config.GetTelegramBotApiToken(), parse_mode = types.ParseMode.HTML) +def ProxyGetButtonsTemplate(a_GetButtonsFunc1): + def ReturnNone(a_Message, user_groups): + return None + if a_GetButtonsFunc1: + return a_GetButtonsFunc1 + else: + return ReturnNone + +async def SendMessage(a_Bot, a_BotMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_UserID, a_Message, user_groups, parse_mode=None): + return await a_Bot.SendMessage( + a_UserID, + a_BotMessage.GetDesc(), + a_BotMessage.GetPhotoID(), + ProxyGetButtonsTemplate(a_GetButtonsFunc)(a_Message, user_groups), + ProxyGetButtonsTemplate(a_GetInlineButtonsFunc)(a_Message, user_groups), + parse_mode = parse_mode + ) + +async def AccessDeniedMessage(a_Bot, a_GetButtonsFunc, a_UserID, a_Message, user_groups): + return await SendMessage(a_Bot, bot_messages.MakeBotMessage(access_utils.access_denied_message), a_GetButtonsFunc, None, a_UserID, a_Message, user_groups) class WorkFuncResult(): - def __init__(self, a_StringMessage : str, photo_id = None, item_access = None, keyboard_func = None): - self.string_message = a_StringMessage - self.photo_id = photo_id + def __init__(self, a_BotMessage, keyboard_func = None, Inline_keyboard_func = None, item_access = None): + self.m_BotMessage = a_BotMessage self.item_access = item_access self.keyboard_func = keyboard_func + self.Inline_keyboard_func = Inline_keyboard_func - -def InfoMessageTemplate(a_HelpMessage, a_GetButtonsFunc, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): +def InfoMessageTemplate(a_Bot, a_HelpMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): async def GetMessage(a_Message : types.message, state = None): return WorkFuncResult(a_HelpMessage) - return SimpleMessageTemplate(GetMessage, a_GetButtonsFunc, a_AccessFunc, access_mode) + return SimpleMessageTemplate(a_Bot, GetMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_AccessFunc, access_mode = access_mode) -def SimpleMessageTemplate(a_WorkFunc, a_GetButtonsFunc, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): +def SimpleMessageTemplate(a_Bot, a_WorkFunc, a_GetButtonsFunc, a_GetInlineButtonsFunc, a_AccessFunc, access_mode = user_access.AccessMode.VIEW): async def SimpleMessage(a_Message : types.message, state = None): user_id = str(a_Message.from_user.id) - user_groups = groups.GetUserGroupData(user_id) - if not user_access.CheckAccessString(a_AccessFunc(), user_groups, access_mode): - return await bot.send_message(a_Message.from_user.id, access.access_denied_message, reply_markup = a_GetButtonsFunc(a_Message, user_groups)) + lang = str(a_Message.from_user.language_code) + 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 AccessDeniedMessage(a_Bot, a_GetButtonsFunc, user_id, a_Message, user_groups) res = await a_WorkFunc(a_Message, state = state) if res is None: return - + + Inline_keyboard_func = a_GetInlineButtonsFunc + if res.Inline_keyboard_func: + Inline_keyboard_func = res.Inline_keyboard_func + keyboard_func = a_GetButtonsFunc if res.keyboard_func: keyboard_func = res.keyboard_func - - msg = res.string_message + + msg = res.m_BotMessage if msg is None: return - photo_id = res.photo_id - - if not res.item_access is None and not user_access.CheckAccessString(res.item_access, user_groups, access_mode): - return await bot.send_message(a_Message.from_user.id, access.access_denied_message, reply_markup = keyboard_func(a_Message, user_groups)) + if not res.item_access is None and not user_access.CheckAccess(a_Bot.GetRootIDs(), res.item_access, user_groups, access_mode): + return await AccessDeniedMessage(a_Bot, keyboard_func, user_id, a_Message, user_groups) - if photo_id is None or photo_id == 0 or photo_id == '0': - return await bot.send_message(a_Message.from_user.id, msg, reply_markup = keyboard_func(a_Message, user_groups)) + msg = msg.GetMessageForLang(lang).StaticCopy() - await bot.send_photo(user_id, photo_id, msg, reply_markup = keyboard_func(a_Message, user_groups)) + await a_Bot.SendMessage( + user_id, + msg.GetDesc(), + msg.GetPhotoID(), + ProxyGetButtonsTemplate(keyboard_func)(a_Message, user_groups), + ProxyGetButtonsTemplate(Inline_keyboard_func)(a_Message, user_groups) + ) return SimpleMessage diff --git a/template/sql_request.py b/template/sql_request.py index e498ac9..262d781 100644 --- a/template/sql_request.py +++ b/template/sql_request.py @@ -3,11 +3,9 @@ # Сообщения для работы с sql запросами -from bot_sys import bot_bd, log, config, user_access, keyboard -from bot_modules import access, groups - -from aiogram import types -from aiogram.dispatcher import FSMContext +from bot_sys import user_access, keyboard, bot_messages +from bot_modules import groups_utils +from template import bd_item, simple_message canсel_button_name = "🚫 Отменить" @@ -15,46 +13,53 @@ cancel_message = ''' 🚫 Запрос к БД отменён ''' -def GetCancelKeyboardButtons(a_Message, a_UserGroups, a_AccessFunc, a_AccessMode): - cur_buttons = [ - keyboard.ButtonWithAccess(canсel_button_name, a_AccessMode, a_AccessFunc()) - ] - return keyboard.MakeKeyboard(cur_buttons, a_UserGroups) +def GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, a_AccessMode): + def GetCancelKeyboardButtons(a_Message, a_UserGroups): + print ('canсel_button_name', canсel_button_name) + cur_buttons = [ + keyboard.ButtonWithAccess(canсel_button_name, a_AccessMode, a_AccessFunc()) + ] + return keyboard.MakeButtons(a_Bot, cur_buttons, a_UserGroups) + return GetCancelKeyboardButtons -def RequestToBDTemplate(a_StartMessage, a_AccessFunc, a_FSM, a_AccessMode): - async def RequestToBDStart(a_Message : types.message): +def RequestToBDTemplate(a_Bot, a_StartMessage, a_GetButtonsFunc, a_AccessFunc, a_FSM, a_AccessMode): + async def RequestToBDStart(a_Message): user_id = str(a_Message.from_user.id) - user_groups = groups.GetUserGroupData(user_id) - if not user_access.CheckAccessString(a_AccessFunc(), user_groups, a_AccessMode): - return await a_Message.answer(access.access_denied_message, reply_markup = GetCancelKeyboardButtons(a_Message, user_groups, a_AccessFunc, a_AccessMode)) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) + if not user_access.CheckAccess(a_Bot.GetRootIDs(), a_AccessFunc(), user_groups, a_AccessMode): + return await simple_message.AccessDeniedMessage(a_Bot, a_GetButtonsFunc, user_id, a_Message, user_groups) + await a_FSM.sqlRequest.set() - await a_Message.answer(a_StartMessage, reply_markup = GetCancelKeyboardButtons(a_Message, user_groups, a_AccessFunc, a_AccessMode), parse_mode='Markdown') + print ('a_FSM.sqlRequest.set()', a_StartMessage) + await simple_message.SendMessage(a_Bot, a_StartMessage, GetCancelKeyboardButtonsTemplate(a_Bot, a_AccessFunc, a_AccessMode), None, user_id, a_Message, user_groups, parse_mode='Markdown') return RequestToBDStart -def RequestToBDFinishTemplate(a_GetButtonsFunc, a_AccessFunc, a_AccessMode): - async def RequestToBDFinish(a_Message : types.message, state : FSMContext): +def RequestToBDFinishTemplate(a_Bot, a_GetButtonsFunc, a_AccessFunc, a_AccessMode): + async def RequestToBDFinish(a_Message, state): user_id = str(a_Message.from_user.id) - user_groups = groups.GetUserGroupData(user_id) - if not user_access.CheckAccessString(a_AccessFunc(), user_groups, a_AccessMode): - return await a_Message.answer(access.access_denied_message, reply_markup = a_GetButtonsFunc(a_Message, user_groups)) + user_groups = groups_utils.GetUserGroupData(a_Bot, user_id) + if not user_access.CheckAccess(a_Bot.GetRootIDs(), a_AccessFunc(), user_groups, a_AccessMode): + return await simple_message.AccessDeniedMessage(a_Bot, a_GetButtonsFunc, user_id, a_Message, user_groups) + result = '' async with state.proxy() as prjData: if a_Message.text == canсel_button_name: await state.finish() - return await a_Message.answer(cancel_message, reply_markup = a_GetButtonsFunc(a_Message, user_groups)) + return await simple_message.SendMessage(a_Bot, bot_messages.MakeBotMessage(cancel_message), a_GetButtonsFunc, None, user_id, a_Message, user_groups) sql_request = a_Message.text - log.Success(f'Сделан запрос [{sql_request}] пользователем {a_Message.from_user.id}.') - result, error = bot_bd.SQLRequestToBD(sql_request, commit = True, return_error = True) + a_Bot.GetLog().Success(f'Сделан запрос [{sql_request}] пользователем {a_Message.from_user.id}.') + result, error = a_Bot.SQLRequest(sql_request, commit = True, return_error = True) if not error is None: - log.Error(f'Ошибка при выполнении запроса [{sql_request}] от пользователя {a_Message.from_user.id} ответ следующий [{str(error)}].') + a_Bot.GetLog().Error(f'Ошибка при выполнении запроса [{sql_request}] от пользователя {a_Message.from_user.id} ответ следующий [{str(error)}].') result = str(error) else: - log.Success(f'Результат запроса [{sql_request}] от пользователя {a_Message.from_user.id} следующий [{result}].') + a_Bot.GetLog().Success(f'Результат запроса [{sql_request}] от пользователя {a_Message.from_user.id} следующий [{result}].') await state.finish() - await a_Message.answer(str(result), reply_markup = a_GetButtonsFunc(a_Message, user_groups)) + await simple_message.SendMessage(a_Bot, bot_messages.MakeBotMessage(str(result)), a_GetButtonsFunc, None, user_id, a_Message, user_groups) + return RequestToBDFinish -def RequestToBDRegisterHandlers(dp, a_RequestButtonName, a_RequestStartMessage, a_FSM, a_GetButtonsFunc, a_AccessMode, a_AccessFunc): - dp.register_message_handler(RequestToBDTemplate(a_RequestStartMessage, a_AccessFunc, a_FSM, a_AccessMode), text = a_RequestButtonName) - dp.register_message_handler(RequestToBDFinishTemplate(a_GetButtonsFunc, a_AccessFunc, a_AccessMode), state = a_FSM.sqlRequest) +def RequestToBDRegisterHandlers(a_Bot, a_RequestButtonName, a_RequestStartMessage, a_FSM, a_GetButtonsFunc, a_AccessMode, a_AccessFunc): + a_Bot.RegisterMessageHandler(RequestToBDTemplate(a_Bot, a_RequestStartMessage, a_GetButtonsFunc, a_AccessFunc, a_FSM, a_AccessMode), bd_item.GetCheckForTextFunc(a_RequestButtonName)) + a_Bot.RegisterMessageHandler(RequestToBDFinishTemplate(a_Bot, a_GetButtonsFunc, a_AccessFunc, a_AccessMode), None, state = a_FSM.sqlRequest)