Browse Source

Start модуль готов

pull/2/head
Alexei 2 years ago
parent
commit
b90f1a32cc
  1. 12
      bot_modules/access_utils.py
  2. 2
      bot_modules/mod_agregator.py
  3. 86
      bot_modules/mod_simple_message.py
  4. 104
      bot_modules/start.py
  5. 8
      bot_sys/aiogram_bot.py
  6. 68
      bot_sys/bot_messages.py
  7. 5
      bot_sys/interfaces.py
  8. 49
      main.py
  9. 3
      template/bd_item.py
  10. 14
      template/simple_message.py

12
bot_modules/access_utils.py

@ -0,0 +1,12 @@
# -*- coding: utf8 -*-
# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) <AlexeiBv+mirocod_platform_bot@narod.ru>
# Права пользователей. Утилиты
table_name = 'module_access'
mod_name_field = 'modName'
moduleaccess_field = 'modAccess'
mod_default_access_field = 'itemDefaultAccess'
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}');"

2
bot_modules/mod_agregator.py

@ -11,3 +11,5 @@ class ModuleAgregator:
def AddModule(a_Module): def AddModule(a_Module):
self.m_Modules[a_Module.GetName()] = a_Module self.m_Modules[a_Module.GetName()] = a_Module
def GetModList():
self.m_Modules.items()

86
bot_modules/mod_simple_message.py

@ -0,0 +1,86 @@
# -*- coding: utf8 -*-
# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) <AlexeiBv+mirocod_platform_bot@narod.ru>
# Простой модуль с одним сообщением
from bot_sys import keyboard, user_access
from bot_modules import access_utils
from template import simple_message
class SimpleMessageModule(mod_interface.IModule):
def __init__(self, a_StartMessage, a_StartButtonName, 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_StartButtonName = CreateButton(f'{GetName()}_start', a_StartButtonName)
self.m_StartMessage = CreateMessage(f'{GetName()}_start', a_StartMessage)
async def StartMessageHandler(a_Message, state = None):
return 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,
None,
self.m_GetStartKeyboardButtonsFunc,
self.m_GetAccessFunc
)
# Основной обработчик главного сообщения
async def StartMessageHandler(a_Message, state = None):
return simple_message.WorkFuncResult(self.m_StartMessage)
def CreateMessage(a_MessageName, a_MessageDesc):
msg = self.m_BotMessages.CreateMessage(a_MessageName, a_MessageDesc, self.m_Log.GetTimeNow())
return msg
def CreateButton(a_ButtonName, a_ButtonDesc):
btn = self.m_BotButtons.CreateMessage(a_ButtonName, a_ButtonDesc, self.m_Log.GetTimeNow())
return btn
def GetStartKeyboardButtons(a_Message, a_UserGroups):
def GetButtons(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
buttons = GetButtons(self.m_ChildModuleNameList)
return MakeButtons(buttons, a_UserGroups)
def GetInitBDCommands():
return [
access_utils.GetAccessForModuleRequest(GetName(), self.m_InitAccess, self.m_InitAccess),
]
def GetAccess():
return self.m_Bot.GetAccessForModule(module_name)
def GetModuleButtons():
return [
keyboard.ButtonWithAccess(self.m_StartButtonName, user_access.AccessMode.VIEW, GetAccess()),
]
def RegisterHandlers():
self.m_Bot.RegisterMessageHandler(
self.m_StartMessageHandler,
bd_item.GetCheckForTextFunc(self.m_StartButtonName)
)

104
bot_modules/start.py

@ -3,76 +3,44 @@
# Стартовое меню # Стартовое меню
from bot_sys import log, config, keyboard, user_access, user_messages from bot_sys import user_access
from bot_modules import profile, projects, groups, access, backup, languages from bot_modules import mod_simple_message
from template import simple_message
from aiogram.dispatcher import Dispatcher class ModuleStart(mod_simple_message.SimpleMessageModule):
def __init__(self, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log):
def MSG(a_MessageName, a_MessageDesc): msg = '''
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}=+');"
]
# ---------------------------------------------------------
# Сообщения
MSG('start_message', '''
<b>Добро пожаловать!</b> <b>Добро пожаловать!</b>
Выберите возможные действия на кнопках ниже ''' Выберите возможные действия на кнопках ниже '''
) start_menu_button_name = "☰ Главное меню"
a_InitAccess = f'{user_access.user_access_group_all}=+'
start_menu_button_name = "☰ Главное меню" super().__init__(self, msg, start_menu_button_name, a_InitAccess, a_ChildModuleNameList, a_Bot, a_ModuleAgregator, a_BotMessages, a_BotButtons, a_Log)
# --------------------------------------------------------- def GetName():
# Работа с кнопками return 'start'
def GetStartKeyboardButtons(a_Message, a_UserGroups): # Основной обработчик главного сообщения
mods = [profile, projects, groups, access, backup, languages] async def StartMessageHandler(a_Message, state = None):
return keyboard.MakeKeyboardForMods(mods, a_UserGroups) 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)
async def StartMenu(a_Message, state = None): profile.AddUser(user_id, user_name, first_name, last_name, is_bot, language_code)
user_id = str(a_Message.from_user.id) self.m_Log.Info(f'Пользователь {user_id} {user_name} авторизовался в боте. Полные данные {a_Message.from_user}.')
user_name = str(a_Message.from_user.username) return super().StartMessageHandler(a_Message, state)
first_name = str(a_Message.from_user.first_name)
last_name = str(a_Message.from_user.last_name) def RegisterHandlers():
is_bot = str(a_Message.from_user.is_bot) super().RegisterHandlers()
language_code = str(a_Message.from_user.language_code) self.m_Bot.RegisterMessageHandler(
profile.AddUser(user_id, user_name, first_name, last_name, is_bot, language_code) self.m_StartMessageHandler,
log.Info(f'Пользователь {user_id} {user_name} авторизовался в боте. Полные данные {a_Message.from_user}.') bd_item.GetCheckForCommandsFunc(['start'])
return simple_message.WorkFuncResult(start_message) )
# ---------------------------------------------------------
# API
#def GetStartKeyboardButtons(a_Message, a_UserGroups):
# Инициализация БД # mods = [profile, projects, groups, access, backup, languages]
def GetInitBDCommands(): # return keyboard.MakeKeyboardForMods(mods, a_UserGroups)
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.SimpleMessageTemplateLegacy(StartMenu, GetStartKeyboardButtons, GetAccess), commands = ['start'])
dp.register_message_handler(simple_message.SimpleMessageTemplateLegacy(StartMenu, GetStartKeyboardButtons, GetAccess), text = start_menu_button_name)

8
bot_sys/aiogram_bot.py

@ -7,6 +7,7 @@ from aiogram import types
from aiogram import Bot from aiogram import Bot
from aiogram.dispatcher import Dispatcher from aiogram.dispatcher import Dispatcher
from aiogram.contrib.fsm_storage.memory import MemoryStorage from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.utils import executor
class AiogramBot(interfaces.IBot): class AiogramBot(interfaces.IBot):
def __init__(self, a_TelegramBotApiToken, a_BDFileName, a_RootIDs, a_Log): def __init__(self, a_TelegramBotApiToken, a_BDFileName, a_RootIDs, a_Log):
@ -74,8 +75,11 @@ class AiogramBot(interfaces.IBot):
) )
def RegisterMessageHandler(self, a_MessageHandler, a_CheckFunc): def RegisterMessageHandler(self, a_MessageHandler, a_CheckFunc):
self.m_Dispatcher.register_message_handler(a_MessageHandler, a_CheckFunc) self.m_Dispatcher.register_message_handler(a_MessageHandler, a_CheckFunc)
def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc): def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc):
self.m_Dispatcher.register_callback_query_handler(a_CallbackHandler, a_CheckFunc) self.m_Dispatcher.register_callback_query_handler(a_CallbackHandler, a_CheckFunc)
def StartPolling(self):
executor.start_polling(self.m_Dispatcher)

68
bot_sys/bot_messages.py

@ -0,0 +1,68 @@
#-*-coding utf-8-*-
# Общественное достояние, 2023, Алексей Безбородов (Alexei Bezborodov) <AlexeiBv+mirocod_platform_bot@narod.ru>
# Работа с сообщениями
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 GetName():
return self.m_MessageName
def GetDesc():
return self.m_MessageDesc
def GetLanguage():
return self.m_Language
def GetPhotoID():
return self.m_PhotoID
def __str__(self):
msg = GetMessageForLang(self.m_Language)
return msg.GetDesc()
def GetMessageForLang(self, a_Language):
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
class BotMessages:
def __init__(self, a_DefaultLanguage):
self.a_DefaultLanguage = a_DefaultLanguage
self.m_Messages = {}
self.m_LastUpdate = None
def GetMessages():
return self.m_Messages
def UpdateSignal(a_DateTime):
self.m_LastUpdate = a_DateTime
def CreateMessage(a_MessageName, a_MessageDesc, a_DateTime):
cur_msg = BotMessage(a_MessageName, a_MessageDesc, self.a_DefaultLanguage, 0, a_DateTime)
msg = GetMessages()
if not msg.get(self.a_DefaultLanguage, None):
msg[self.a_DefaultLanguage] = {}
if not msg[self.a_DefaultLanguage].get(a_MessageName, None):
msg[self.a_DefaultLanguage][a_MessageName] = cur_msg
return cur_msg

5
bot_sys/interfaces.py

@ -39,3 +39,8 @@ class IBot(ABC):
@abstractmethod @abstractmethod
def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc): def RegisterCallbackHandler(self, a_CallbackHandler, a_CheckFunc):
pass pass
@abstractmethod
def StartPolling(self):
pass

49
main.py

@ -4,36 +4,43 @@
log_start_message = 'Бот успешно запущен!' log_start_message = 'Бот успешно запущен!'
import os import os
from aiogram import Bot, types
from aiogram.utils import executor from bot_sys import config, log, bot_bd, user_access, aiogram_bot, bot_messages
from aiogram.dispatcher import Dispatcher from bot_modules import mod_agregator, start #, projects, groups, access, backup, tasks, needs, comments, messages, profile, languages
from aiogram.contrib.fsm_storage.memory import MemoryStorage
import sqlite3 g_Log = log
from bot_sys import config, log, bot_bd, user_access, user_messages g_Bot = aiogram_bot.AiogramBot(config.GetTelegramBotApiToken(), bot_bd.GetBDFileName(), config.GetRootIDs(), g_Log):
from bot_modules import profile, start, projects, groups, access, backup, tasks, needs, comments, messages, languages
default_language = 'ru'
storage = MemoryStorage()
bot = Bot(token = config.GetTelegramBotApiToken(), parse_mode = types.ParseMode.HTML) g_BotMessages = bot_messages.BotMessages(default_language)
dp = Dispatcher(bot, storage = storage) g_BotButtons = bot_messages.BotMessages(default_language)
g_ModuleAgregator = mod_agregator.ModuleAgregator()
mod_start = start.ModuleStart([], g_Bot, g_ModuleAgregator, g_BotMessages, g_BotButtons, g_Log)
g_ModuleAgregator.AddModule(mod_start)
# Первичная инициализация модулей. Все модули должны быть прописаны в списке modules # Первичная инициализация модулей. Все модули должны быть прописаны в списке modules
modules = [tasks, access, profile, start, projects, groups, backup, needs, comments, messages, languages] modules = g_ModuleAgregator.GetModList() # [start] #tasks, access, profile, projects, groups, backup, needs, comments, messages, languages]
init_bd_cmd = [] init_bd_cmds = []
for m in modules: for m in modules:
c = m.GetInitBDCommands() c = m.GetInitBDCommands()
if not c is None: 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() #languages.FlushLanguages()
messages.FlushMessages() #messages.FlushMessages()
for m in modules: for m in modules:
m.RegisterHandlers(dp) m.RegisterHandlers()
# Юнит тесты модулей и файлов # Юнит тесты модулей и файлов
test_mods = [user_access] test_mods = [user_access]
@ -43,6 +50,6 @@ for m in test_mods:
if __name__ == '__main__': if __name__ == '__main__':
# os.system('clear') # os.system('clear')
# os.system('cls') # os.system('cls')
log.Success(log_start_message) g_Log.Success(log_start_message)
executor.start_polling(dp) g_Bot.StartPolling()

3
template/bd_item.py

@ -33,6 +33,9 @@ def GetCheckForPrefixFunc(a_Prefix):
def GetCheckForTextFunc(a_Text): def GetCheckForTextFunc(a_Text):
return lambda x: x.text == a_Text return lambda x: x.text == a_Text
def GetCheckForCommandsFunc(a_Commands):
return lambda x: x.commands == a_Commands
def GetKeyDataFromCallbackMessage(a_Message, a_Prefix): def GetKeyDataFromCallbackMessage(a_Message, a_Prefix):
key_item_id = None key_item_id = None
if a_Prefix and hasattr(a_Message, 'data'): if a_Prefix and hasattr(a_Message, 'data'):

14
template/simple_message.py

@ -8,9 +8,8 @@ from bot_modules import access
from aiogram import types from aiogram import types
class WorkFuncResult(): class WorkFuncResult():
def __init__(self, a_StringMessage : str, photo_id = None, item_access = None): def __init__(self, a_BotMessage, item_access = None):
self.string_message = a_StringMessage self.m_BotMessage = a_BotMessage
self.photo_id = photo_id
self.item_access = item_access self.item_access = item_access
def InfoMessageTemplate(a_Bot, a_HelpMessage, a_GetButtonsFunc, a_GetInlineButtonsFunc, 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):
@ -39,6 +38,7 @@ def SimpleMessageTemplate(a_Bot, a_WorkFunc, a_GetButtonsFunc, a_GetInlineButton
async def SimpleMessage(a_Message : types.message, state = None): async def SimpleMessage(a_Message : types.message, state = None):
user_id = str(a_Message.from_user.id) user_id = str(a_Message.from_user.id)
lang = str(a_Message.from_user.language_code)
user_groups = a_Bot.GetUserGroupData(user_id) user_groups = a_Bot.GetUserGroupData(user_id)
if not user_access.CheckAccess(a_Bot.GetRootIDs(), a_AccessFunc(), user_groups, access_mode): if not user_access.CheckAccess(a_Bot.GetRootIDs(), a_AccessFunc(), user_groups, access_mode):
return await AccessDeniedMessage(user_id, a_Message, user_groups) return await AccessDeniedMessage(user_id, a_Message, user_groups)
@ -47,17 +47,19 @@ def SimpleMessageTemplate(a_Bot, a_WorkFunc, a_GetButtonsFunc, a_GetInlineButton
if res is None: if res is None:
return return
msg = res.string_message msg = res.m_BotMessage
if msg is None: if msg is None:
return return
if not res.item_access is None and not user_access.CheckAccess(a_Bot.GetRootIDs(), res.item_access, user_groups, access_mode): 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(user_id, a_Message, user_groups) return await AccessDeniedMessage(user_id, a_Message, user_groups)
msg = msg.GetMessageForLang(lang)
await a_Bot.SendMessage( await a_Bot.SendMessage(
user_id, user_id,
msg, msg.GetDesc(),
res.photo_id, msg.GetPhotoID(),
ProxyGetButtonsTemplate(a_GetInlineButtonsFunc)(a_Message, user_groups), ProxyGetButtonsTemplate(a_GetInlineButtonsFunc)(a_Message, user_groups),
ProxyGetButtonsTemplate(a_GetButtonsFunc)(a_Message, user_groups) ProxyGetButtonsTemplate(a_GetButtonsFunc)(a_Message, user_groups)
) )

Loading…
Cancel
Save