Deleted mysql support, redis password, webhook, keyboard constructors, filters, loguru.
Added support of decorators in handlers Added function to notify admins on startup
This commit is contained in:
		
							parent
							
								
									13ff8d0478
								
							
						
					
					
						commit
						eab45a5088
					
				
							
								
								
									
										44
									
								
								bot.py
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								bot.py
									
									
									
									
									
								
							| 
						 | 
					@ -1,42 +1,36 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aiogram import Bot, Dispatcher, types
 | 
					from aiogram import Bot, Dispatcher, types
 | 
				
			||||||
from aiogram.contrib.fsm_storage.redis import RedisStorage2
 | 
					from aiogram.contrib.fsm_storage.redis import RedisStorage2
 | 
				
			||||||
from aiohttp import web
 | 
					 | 
				
			||||||
from loguru import logger
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import filters
 | 
					 | 
				
			||||||
import handlers
 | 
					 | 
				
			||||||
import middlewares
 | 
					 | 
				
			||||||
from data import config
 | 
					from data import config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bot = Bot(token=config.BOT_TOKEN, parse_mode=types.ParseMode.HTML)
 | 
					bot = Bot(token=config.BOT_TOKEN, parse_mode=types.ParseMode.HTML)
 | 
				
			||||||
storage = RedisStorage2(**config.aiogram_redis)
 | 
					storage = RedisStorage2(**config.aiogram_redis)
 | 
				
			||||||
dp = Dispatcher(bot, storage=storage)
 | 
					dp = Dispatcher(bot, storage=storage)
 | 
				
			||||||
 | 
					logging.basicConfig(format=u'%(filename)s [LINE:%(lineno)d] #%(levelname)-8s [%(asctime)s]  %(message)s',
 | 
				
			||||||
 | 
					                    level=logging.INFO,
 | 
				
			||||||
 | 
					                    # level=logging.DEBUG,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# noinspection PyUnusedLocal
 | 
					async def on_startup(dp):
 | 
				
			||||||
async def on_startup(web_app: web.Application):
 | 
					    import filters
 | 
				
			||||||
 | 
					    import middlewares
 | 
				
			||||||
    filters.setup(dp)
 | 
					    filters.setup(dp)
 | 
				
			||||||
    middlewares.setup(dp)
 | 
					    middlewares.setup(dp)
 | 
				
			||||||
    handlers.errors.setup(dp)
 | 
					
 | 
				
			||||||
    handlers.user.setup(dp)
 | 
					    from utils.notify_admins import on_startup_notify
 | 
				
			||||||
    await dp.bot.delete_webhook()
 | 
					    await on_startup_notify(dp)
 | 
				
			||||||
    await dp.bot.set_webhook(config.WEBHOOK_URL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def execute(req: web.Request) -> web.Response:
 | 
					async def on_shutdown(dp):
 | 
				
			||||||
    upds = [types.Update(**(await req.json()))]
 | 
					    await bot.close()
 | 
				
			||||||
    Bot.set_current(dp.bot)
 | 
					    await storage.close()
 | 
				
			||||||
    Dispatcher.set_current(dp)
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        await dp.process_updates(upds)
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        logger.error(e)
 | 
					 | 
				
			||||||
    finally:
 | 
					 | 
				
			||||||
        return web.Response()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    app = web.Application()
 | 
					    from aiogram import executor
 | 
				
			||||||
    app.on_startup.append(on_startup)
 | 
					    from handlers import dp
 | 
				
			||||||
    app.add_routes([web.post(config.WEBHOOK_PATH, execute)])
 | 
					
 | 
				
			||||||
    web.run_app(app, port=5151, host='localhost')
 | 
					    executor.start_polling(dp, on_startup=on_startup)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,31 +1,20 @@
 | 
				
			||||||
BOT_TOKEN = ''
 | 
					import os
 | 
				
			||||||
BASE_URL = 'https://example.com'  # Webhook domain
 | 
					 | 
				
			||||||
WEBHOOK_PATH = f'/webhook/bot/{BOT_TOKEN}'
 | 
					 | 
				
			||||||
WEBHOOK_URL = f'{BASE_URL}{WEBHOOK_PATH}'
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
admins = []
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ip = {
 | 
					load_dotenv()
 | 
				
			||||||
    'db':    '',
 | 
					 | 
				
			||||||
    'redis': '',
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
mysql_info = {
 | 
					BOT_TOKEN = str(os.getenv("BOT_TOKEN"))
 | 
				
			||||||
    'host':     ip['db'],
 | 
					admins = [
 | 
				
			||||||
    'user':     '',
 | 
					]
 | 
				
			||||||
    'password': '',
 | 
					
 | 
				
			||||||
    'db':       '',
 | 
					ip = os.getenv("ip")
 | 
				
			||||||
    'maxsize':  5,
 | 
					 | 
				
			||||||
    'port':     3306,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
aiogram_redis = {
 | 
					aiogram_redis = {
 | 
				
			||||||
    'host':     ip['redis'],
 | 
					    'host': ip,
 | 
				
			||||||
    'password': ''
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
redis = {
 | 
					redis = {
 | 
				
			||||||
    'address':  (ip['redis'], 6379),
 | 
					    'address': (ip, 6379),
 | 
				
			||||||
    'password': '',
 | 
					 | 
				
			||||||
    'encoding': 'utf8'
 | 
					    'encoding': 'utf8'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,9 @@
 | 
				
			||||||
from aiogram import Dispatcher
 | 
					from aiogram import Dispatcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .is_admin import AdminFilter
 | 
					
 | 
				
			||||||
 | 
					# from .is_admin import AdminFilter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup(dp: Dispatcher):
 | 
					def setup(dp: Dispatcher):
 | 
				
			||||||
    dp.filters_factory.bind(AdminFilter)
 | 
					    # dp.filters_factory.bind(AdminFilter)
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
from aiogram import types
 | 
					 | 
				
			||||||
from aiogram.dispatcher.filters import BoundFilter
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from data import config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AdminFilter(BoundFilter):
 | 
					 | 
				
			||||||
    key = 'is_admin'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, is_admin):
 | 
					 | 
				
			||||||
        self.is_admin = is_admin
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    async def check(self, message: types.Message):
 | 
					 | 
				
			||||||
        return message.from_user.id in config.admins
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,2 +1,4 @@
 | 
				
			||||||
from . import errors
 | 
					from .errors import dp
 | 
				
			||||||
from . import user
 | 
					from .users import dp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ["dp"]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,3 @@
 | 
				
			||||||
from aiogram import Dispatcher
 | 
					from .error_handler import dp
 | 
				
			||||||
from aiogram.utils import exceptions
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .not_modified import message_not_modified, message_to_delete_not_found
 | 
					__all__ = ["dp"]
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def setup(dp: Dispatcher):
 | 
					 | 
				
			||||||
    dp.register_errors_handler(message_not_modified, exception=exceptions.MessageNotModified)
 | 
					 | 
				
			||||||
    dp.register_errors_handler(message_to_delete_not_found, exception=exceptions.MessageToDeleteNotFound)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										56
									
								
								handlers/errors/error_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								handlers/errors/error_handler.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from bot import dp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dp.errors_handler()
 | 
				
			||||||
 | 
					async def errors_handler(update, exception):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Exceptions handler. Catches all exceptions within task factory tasks.
 | 
				
			||||||
 | 
					    :param dispatcher:
 | 
				
			||||||
 | 
					    :param update:
 | 
				
			||||||
 | 
					    :param exception:
 | 
				
			||||||
 | 
					    :return: stdout logging
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    from aiogram.utils.exceptions import (Unauthorized, InvalidQueryID, TelegramAPIError,
 | 
				
			||||||
 | 
					                                          CantDemoteChatCreator, MessageNotModified, MessageToDeleteNotFound,
 | 
				
			||||||
 | 
					                                          MessageTextIsEmpty, RetryAfter,
 | 
				
			||||||
 | 
					                                          CantParseEntities, MessageCantBeDeleted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, CantDemoteChatCreator):
 | 
				
			||||||
 | 
					        logging.debug("Can't demote chat creator")
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, MessageNotModified):
 | 
				
			||||||
 | 
					        logging.debug('Message is not modified')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					    if isinstance(exception, MessageCantBeDeleted):
 | 
				
			||||||
 | 
					        logging.debug('Message cant be deleted')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, MessageToDeleteNotFound):
 | 
				
			||||||
 | 
					        logging.debug('Message to delete not found')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, MessageTextIsEmpty):
 | 
				
			||||||
 | 
					        logging.debug('MessageTextIsEmpty')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, Unauthorized):
 | 
				
			||||||
 | 
					        logging.info(f'Unauthorized: {exception}')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, InvalidQueryID):
 | 
				
			||||||
 | 
					        logging.exception(f'InvalidQueryID: {exception} \nUpdate: {update}')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if isinstance(exception, TelegramAPIError):
 | 
				
			||||||
 | 
					        logging.exception(f'TelegramAPIError: {exception} \nUpdate: {update}')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					    if isinstance(exception, RetryAfter):
 | 
				
			||||||
 | 
					        logging.exception(f'RetryAfter: {exception} \nUpdate: {update}')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					    if isinstance(exception, CantParseEntities):
 | 
				
			||||||
 | 
					        logging.exception(f'CantParseEntities: {exception} \nUpdate: {update}')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					    logging.exception(f'Update: {update} \n{exception}')
 | 
				
			||||||
| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
from aiogram import types
 | 
					 | 
				
			||||||
from aiogram.utils import exceptions
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def message_not_modified(update: types.Update, error: exceptions.MessageNotModified):
 | 
					 | 
				
			||||||
    return True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def message_to_delete_not_found(update: types.Update, error: exceptions.MessageToDeleteNotFound):
 | 
					 | 
				
			||||||
    return True
 | 
					 | 
				
			||||||
							
								
								
									
										0
									
								
								handlers/groups/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								handlers/groups/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
from aiogram import Dispatcher
 | 
					 | 
				
			||||||
from aiogram.dispatcher.filters import CommandStart, CommandHelp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .help import bot_help
 | 
					 | 
				
			||||||
from .start import bot_start
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def setup(dp: Dispatcher):
 | 
					 | 
				
			||||||
    dp.register_message_handler(bot_start, CommandStart())
 | 
					 | 
				
			||||||
    dp.register_message_handler(bot_help, CommandHelp())
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +0,0 @@
 | 
				
			||||||
from aiogram import types
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def bot_start(msg: types.Message):
 | 
					 | 
				
			||||||
    await msg.answer(f'Привет, {msg.from_user.full_name}!')
 | 
					 | 
				
			||||||
							
								
								
									
										5
									
								
								handlers/users/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								handlers/users/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					from .help import dp
 | 
				
			||||||
 | 
					from .start import dp
 | 
				
			||||||
 | 
					from .echo import dp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ["dp"]
 | 
				
			||||||
							
								
								
									
										7
									
								
								handlers/users/echo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								handlers/users/echo.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					from aiogram import types
 | 
				
			||||||
 | 
					from bot import dp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dp.message_handler()
 | 
				
			||||||
 | 
					async def bot_start(message: types.Message):
 | 
				
			||||||
 | 
					    await message.answer(message.text)
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,16 @@
 | 
				
			||||||
from aiogram import types
 | 
					from aiogram import types
 | 
				
			||||||
 | 
					from aiogram.dispatcher.filters.builtin import CommandStart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from bot import dp
 | 
				
			||||||
from utils.misc import rate_limit
 | 
					from utils.misc import rate_limit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@rate_limit(5, 'help')
 | 
					@rate_limit(5, 'help')
 | 
				
			||||||
async def bot_help(msg: types.Message):
 | 
					@dp.message_handler(CommandStart())
 | 
				
			||||||
 | 
					async def bot_help(message: types.Message):
 | 
				
			||||||
    text = [
 | 
					    text = [
 | 
				
			||||||
        'Список команд: ',
 | 
					        'Список команд: ',
 | 
				
			||||||
        '/start - Начать диалог',
 | 
					        '/start - Начать диалог',
 | 
				
			||||||
        '/help - Получить справку'
 | 
					        '/help - Получить справку'
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    await msg.answer('\n'.join(text))
 | 
					    await message.answer('\n'.join(text))
 | 
				
			||||||
							
								
								
									
										9
									
								
								handlers/users/start.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								handlers/users/start.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					from aiogram import types
 | 
				
			||||||
 | 
					from aiogram.dispatcher.filters.builtin import CommandStart
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from bot import dp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dp.message_handler(CommandStart())
 | 
				
			||||||
 | 
					async def bot_start(message: types.Message):
 | 
				
			||||||
 | 
					    await message.answer(f'Привет, {message.from_user.full_name}!')
 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
from typing import List
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from . import utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DefaultConstructor:
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def _create_kb(actions: List[str], schema: List[int]) -> ReplyKeyboardMarkup:
 | 
					 | 
				
			||||||
        btns = []
 | 
					 | 
				
			||||||
        for a in actions:
 | 
					 | 
				
			||||||
            btns.append(KeyboardButton(a))
 | 
					 | 
				
			||||||
        kb = utils.misc.arrange_default_schema(btns, schema)
 | 
					 | 
				
			||||||
        return kb
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
from . import misc
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
from typing import List
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def arrange_default_schema(buttons: List[KeyboardButton], count: List[int]) -> ReplyKeyboardMarkup:
 | 
					 | 
				
			||||||
    kb = ReplyKeyboardMarkup(resize_keyboard=True)
 | 
					 | 
				
			||||||
    kb.row_width = max(count)
 | 
					 | 
				
			||||||
    if sum(count) != len(buttons):
 | 
					 | 
				
			||||||
        raise ValueError('Количество кнопок не совпадает со схемой')
 | 
					 | 
				
			||||||
    tmplist = []
 | 
					 | 
				
			||||||
    for a in count:
 | 
					 | 
				
			||||||
        tmplist.append([])
 | 
					 | 
				
			||||||
        for _ in range(a):
 | 
					 | 
				
			||||||
            tmplist[-1].append(buttons.pop(0))
 | 
					 | 
				
			||||||
    kb.keyboard = tmplist
 | 
					 | 
				
			||||||
    return kb
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					from aiogram.utils.callback_data import CallbackData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					some_callback = CallbackData("new")
 | 
				
			||||||
| 
						 | 
					@ -1,21 +0,0 @@
 | 
				
			||||||
from typing import List, Tuple, Dict
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
 | 
					 | 
				
			||||||
from aiogram.utils.callback_data import CallbackData
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from . import utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class InlineConstructor:
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def _create_kb(actions: List[Tuple[str, Dict[str, str], CallbackData]], schema: List[int]) -> InlineKeyboardMarkup:
 | 
					 | 
				
			||||||
        btns = []
 | 
					 | 
				
			||||||
        for a, b, c in actions:
 | 
					 | 
				
			||||||
            btns.append(
 | 
					 | 
				
			||||||
                InlineKeyboardButton(
 | 
					 | 
				
			||||||
                    text=a,
 | 
					 | 
				
			||||||
                    callback_data=c.new(**b)
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        kb = utils.misc.arrange_inline_schema(btns, schema)
 | 
					 | 
				
			||||||
        return kb
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
from . import misc
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
from typing import List
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def arrange_inline_schema(buttons: List[InlineKeyboardButton], count: List[int]) -> InlineKeyboardMarkup:
 | 
					 | 
				
			||||||
    kb = InlineKeyboardMarkup()
 | 
					 | 
				
			||||||
    kb.row_width = max(count)
 | 
					 | 
				
			||||||
    if sum(count) != len(buttons):
 | 
					 | 
				
			||||||
        raise ValueError('Количество кнопок не совпадает со схемой')
 | 
					 | 
				
			||||||
    tmplist = []
 | 
					 | 
				
			||||||
    for a in count:
 | 
					 | 
				
			||||||
        tmplist.append([])
 | 
					 | 
				
			||||||
        for _ in range(a):
 | 
					 | 
				
			||||||
            tmplist[-1].append(buttons.pop(0))
 | 
					 | 
				
			||||||
    kb.inline_keyboard = tmplist
 | 
					 | 
				
			||||||
    return kb
 | 
					 | 
				
			||||||
| 
						 | 
					@ -4,4 +4,4 @@ from .throttling import ThrottlingMiddleware
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup(dp: Dispatcher):
 | 
					def setup(dp: Dispatcher):
 | 
				
			||||||
    dp.middleware.setup(ThrottlingMiddleware)
 | 
					    dp.middleware.setup(ThrottlingMiddleware())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,3 @@
 | 
				
			||||||
aiomysql==0.0.20
 | 
					 | 
				
			||||||
aiogram==2.7
 | 
					aiogram==2.7
 | 
				
			||||||
aiohttp==3.6.2
 | 
					aiohttp==3.6.2
 | 
				
			||||||
aioredis==1.3.1
 | 
					aioredis==1.3.1
 | 
				
			||||||
loguru==0.4.1
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
from . import user
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
from . import db_api
 | 
					from . import db_api
 | 
				
			||||||
from . import misc
 | 
					from . import misc
 | 
				
			||||||
from . import redis
 | 
					from . import redis
 | 
				
			||||||
 | 
					from .notify_admins import on_startup_notify
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,47 +0,0 @@
 | 
				
			||||||
import asyncio
 | 
					 | 
				
			||||||
from typing import Optional, Dict, Any, Union, List
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import aiomysql
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from data import config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RawConnection:
 | 
					 | 
				
			||||||
    connection_pool = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    async def _make_request(
 | 
					 | 
				
			||||||
            sql: str,
 | 
					 | 
				
			||||||
            params: Union[tuple, List[tuple]] = None,
 | 
					 | 
				
			||||||
            fetch: bool = False,
 | 
					 | 
				
			||||||
            mult: bool = False,
 | 
					 | 
				
			||||||
            retries_count: int = 5
 | 
					 | 
				
			||||||
    ) -> Optional[Union[List[Dict[str, Any]], Dict[str, Any]]]:
 | 
					 | 
				
			||||||
        if RawConnection.connection_pool is None:
 | 
					 | 
				
			||||||
            RawConnection.connection_pool = await aiomysql.create_pool(**config.mysql_info)
 | 
					 | 
				
			||||||
        async with RawConnection.connection_pool.acquire() as conn:
 | 
					 | 
				
			||||||
            conn: aiomysql.Connection = conn
 | 
					 | 
				
			||||||
            async with conn.cursor(aiomysql.DictCursor) as cur:
 | 
					 | 
				
			||||||
                cur: aiomysql.DictCursor = cur
 | 
					 | 
				
			||||||
                for i in range(retries_count):
 | 
					 | 
				
			||||||
                    try:
 | 
					 | 
				
			||||||
                        if isinstance(params, list):
 | 
					 | 
				
			||||||
                            await cur.executemany(sql, params)
 | 
					 | 
				
			||||||
                        else:
 | 
					 | 
				
			||||||
                            await cur.execute(sql, params)
 | 
					 | 
				
			||||||
                    except aiomysql.OperationalError as e:
 | 
					 | 
				
			||||||
                        if 'Deadlock found' in str(e):
 | 
					 | 
				
			||||||
                            await asyncio.sleep(1)
 | 
					 | 
				
			||||||
                    except aiomysql.InternalError as e:
 | 
					 | 
				
			||||||
                        if 'Deadlock found' in str(e):
 | 
					 | 
				
			||||||
                            await asyncio.sleep(1)
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        break
 | 
					 | 
				
			||||||
                if fetch:
 | 
					 | 
				
			||||||
                    if mult:
 | 
					 | 
				
			||||||
                        r = await cur.fetchall()
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        r = await cur.fetchone()
 | 
					 | 
				
			||||||
                    return r
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    await conn.commit()
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								utils/notify_admins.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								utils/notify_admins.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aiogram import Dispatcher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from data.config import admins
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def on_startup_notify(dp: Dispatcher):
 | 
				
			||||||
 | 
					    for admin in admins:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            await dp.bot.send_message(admin, "Бот Запущен")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        except Exception as err:
 | 
				
			||||||
 | 
					            logging.exception(err)
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user