from datetime import timedelta from urllib.parse import urljoin from pydantic import ValidationError from app.chat.exceptions import UserDontHavePermissionException, UserCanNotReadThisChatException, \ UserAlreadyInChatException from app.chat.shemas import SAllowedChats, SChangeData, SPinnedChats, SChat from app.config import settings from app.services.redis_service import RedisService from app.services.user_service import UserService from app.utils.unit_of_work import UnitOfWork from app.users.schemas import SInvitationData from app.services.auth_service import AuthService class ChatService: @staticmethod async def find_chat(uow: UnitOfWork, chat_id: int, user_id: int) -> SChat: async with uow: chat = await uow.chat.find_one(chat_id=chat_id, user_id=user_id) return chat @staticmethod async def get_all_chats(uow: UnitOfWork, user_id: int) -> SAllowedChats: try: async with RedisService() as redis: allowed_chats = await redis.get_value(key=f"user_allowed_chats: {user_id}", model=SAllowedChats) return allowed_chats except ValidationError: async with uow: allowed_chats = await uow.user.get_user_allowed_chats(user_id=user_id) async with RedisService() as redis: await redis.set_key( key=f"user_allowed_chats: {user_id}", expire_time=timedelta(minutes=30), value=allowed_chats.model_dump_json() ) return allowed_chats @staticmethod async def create_chat(uow: UnitOfWork, user_id: int, user_to_exclude_id: int, chat_name: str) -> int: if user_id == user_to_exclude_id: raise UserCanNotReadThisChatException user_chat_for = await UserService.find_user(uow=uow, id=user_to_exclude_id) async with uow: chat_id = await uow.chat.create_chat( user_id=user_to_exclude_id, chat_name=chat_name, created_by=user_id, avatar_image=user_chat_for.avatar_image ) await uow.chat.add_user_to_chat(user_id, chat_id) if user_id != settings.ADMIN_USER_ID: await uow.chat.add_user_to_chat(settings.ADMIN_USER_ID, chat_id) async with RedisService(is_raise=True) as redis: await redis.delete_key(key=f"user_allowed_chats: {user_id}") await uow.commit() return chat_id @classmethod async def change_chat_data(cls, uow: UnitOfWork, user_id: int, user_data: SChangeData) -> None: chat = await cls.find_chat(uow=uow, chat_id=user_data.chat_id, user_id=user_id) if chat.created_by != user_id: raise UserDontHavePermissionException async with uow: await uow.chat.change_data( chat_id=user_data.chat_id, chat_name=user_data.chat_name, avatar_image=user_data.avatar_image ) async with RedisService(is_raise=True) as redis: await redis.delete_key(key=f"user_allowed_chats: {user_id}") await uow.commit() @staticmethod def create_invitation_link(chat_id: int) -> str: invitation_data = SInvitationData.model_validate({"chat_id": chat_id}) invitation_token = AuthService.encode_invitation_token(invitation_data) invitation_link = urljoin(settings.INVITATION_LINK_HOST, f"/submit#code={invitation_token}") return invitation_link @classmethod async def invite_to_chat(cls, uow: UnitOfWork, user_id: int, invitation_token: str) -> None: invitation_data = AuthService.decode_invitation_token(invitation_token) chat = await cls.find_chat(uow=uow, chat_id=invitation_data.chat_id, user_id=user_id) if user_id == chat.chat_for: raise UserCanNotReadThisChatException async with uow: await uow.chat.add_user_to_chat(chat_id=invitation_data.chat_id, user_id=user_id) async with RedisService(is_raise=True) as redis: await redis.delete_key(key=f"user_allowed_chats: {user_id}") await uow.commit() @classmethod async def delete_chat(cls, uow: UnitOfWork, user_id: int, chat_id: int) -> None: chat = await cls.find_chat(uow=uow, chat_id=chat_id, user_id=user_id) if not user_id == chat.created_by: raise UserDontHavePermissionException async with uow: await uow.chat.delete_chat(chat_id) async with RedisService(is_raise=True) as redis: await redis.delete_key(key=f"user_allowed_chats: {user_id}") await uow.commit() @classmethod async def delete_user_from_chat(cls, uow: UnitOfWork, user_id: int, chat_id: int, user_id_for_delete: int) -> None: chat = await cls.find_chat(uow=uow, chat_id=chat_id, user_id=user_id) if not user_id == chat.created_by: raise UserDontHavePermissionException async with uow: await uow.chat.delete_user_from_chat(chat_id=chat_id, user_id=user_id_for_delete) async with RedisService(is_raise=True) as redis: await redis.delete_key(key=f"user_allowed_chats: {user_id_for_delete}") await uow.commit() @staticmethod async def pin_chat(uow: UnitOfWork, user_id: int, chat_id: int) -> None: async with uow: await uow.chat.pin_chat(chat_id=chat_id, user_id=user_id) await uow.commit() @staticmethod async def unpin_chat(uow: UnitOfWork, user_id: int, chat_id: int) -> None: async with uow: await uow.chat.unpin_chat(chat_id=chat_id, user_id=user_id) await uow.commit() @staticmethod async def get_pinned_chats(uow: UnitOfWork, user_id: int) -> SPinnedChats: async with uow: pinned_chats = await uow.chat.get_pinned_chats(user_id=user_id) return pinned_chats