Source code for quackamollie.core.bot.decorator.user_chat_registered

# -*- coding: utf-8 -*-
__all__ = ["ensure_user_chat_registered"]
__author__ = "QuacktorAI"
__copyright__ = "Copyright 2024, Forge of Absurd Ducks"
__credits__ = ["QuacktorAI"]

from aiogram.types import Message, CallbackQuery
from functools import wraps
from sqlalchemy import select
from typing import Callable, Union

from quackamollie.core.cli.settings import get_settings_from_context, QuackamollieSettings
from quackamollie.core.database.model import User, Chat


[docs] def ensure_user_chat_registered(func: Callable) -> Callable: """ Decorator to encapsulate aiogram message or query handlers in order to ensure that the user already registered using the `/start` command before calling the encapsulated handler. If not, it asks the user to register using the `/start` command. :param func: The function to encapsulate :type func: Callable :return: The encapsulated function :rtype: Callable """ @wraps(func) async def user_chat_registered_wrapper(query_msg: Union[Message, CallbackQuery], *args, **kwargs): """ Encapsulate aiogram message or query handlers to ensure only requests from registered users are handled :param query_msg: Undifferentiated Message or CallbackQuery as given by aiogram router :type query_msg: Union[Message, CallbackQuery] """ # Differentiate between queries and messages in order to get chat ID message: Message = query_msg.message if isinstance(query_msg, CallbackQuery) else query_msg user_id: int = query_msg.from_user.id chat_id: int = message.chat.id # Get settings for SQLAlchemy interaction quackamollie_settings: QuackamollieSettings = get_settings_from_context() async_session = quackamollie_settings.session async with async_session() as session: user_result = await session.execute(select(User.id).where(User.id == user_id).limit(1)) user = user_result.scalars().first() chat_result = await session.execute(select(Chat.id).where(Chat.id == chat_id).limit(1)) chat = chat_result.scalars().first() # If IDs of user and chat can be retrieved from database, the request is forwarded to the encapsulated function if user is not None and chat is not None: return await func(query_msg, *args, **kwargs) else: # Return a message stating to use the command '/start' when starting a new chat return await message.answer("⚠ The user or chat are not initialized, please run the command /start" " to initialize a new chat with me.") return user_chat_registered_wrapper