From 5d433b7412c6539611f3ba82db452b87f6adc5a3 Mon Sep 17 00:00:00 2001 From: urec56 Date: Fri, 12 Jul 2024 16:29:31 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chat/router.py | 140 +++++++++++--------------------- app/chat/shemas.py | 5 -- app/services/chat_service.py | 90 ++++++++++++++++++++ app/services/message_service.py | 24 +++++- app/unit_of_work.py | 14 +++- app/users/dependencies.py | 2 +- 6 files changed, 174 insertions(+), 101 deletions(-) create mode 100644 app/services/chat_service.py diff --git a/app/chat/router.py b/app/chat/router.py index 1631a3e..788e40d 100644 --- a/app/chat/router.py +++ b/app/chat/router.py @@ -1,14 +1,11 @@ from fastapi import APIRouter, Depends, status -from app.config import settings from app.chat.exceptions import ( - UserDontHavePermissionException, UserCanNotReadThisChatException, ) from app.chat.shemas import ( SMessage, SLastMessages, - SPinnedChat, SAllowedChats, SMessageList, SPinnedChats, @@ -16,10 +13,12 @@ from app.chat.shemas import ( SChangeData, SChatId, ) +from app.services.chat_service import ChatService +from app.services.message_service import MessageService from app.unit_of_work import UnitOfWork -from app.users.dependencies import check_verificated_user_with_exc -from app.utils.auth import AuthService, encode_invitation_token, decode_invitation_token -from app.users.schemas import SCreateInvitationLink, SUser, SInvitationData +from app.users.dependencies import get_verificated_user +from app.utils.auth import AuthService +from app.users.schemas import SCreateInvitationLink, SUser router = APIRouter(prefix="/chat", tags=["Чат"]) @@ -29,10 +28,9 @@ router = APIRouter(prefix="/chat", tags=["Чат"]) status_code=status.HTTP_200_OK, response_model=SAllowedChats, ) -async def get_all_chats(user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): - async with uow: - allowed_chats = await uow.user.get_user_allowed_chats(user.id) - return allowed_chats +async def get_all_chats(user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): + allowed_chats = await ChatService.get_all_chats(uow=uow, user_id=user.id) + return allowed_chats @router.post( @@ -43,20 +41,15 @@ async def get_all_chats(user: SUser = Depends(check_verificated_user_with_exc), async def create_chat( user_to_exclude: int, chat_name: str, - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): if user.id == user_to_exclude: raise UserCanNotReadThisChatException - async with uow: - user_chat_for = await uow.user.find_one(id=user_to_exclude) - chat_id = await uow.chat.create_chat( - user_id=user_to_exclude, 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) - await uow.chat.add_user_to_chat(settings.ADMIN_USER_ID, chat_id) - await uow.commit() - return {"chat_id": chat_id} + chat_id = await ChatService.create_chat( + uow=uow, user_id=user.id, user_to_exclude_id=user_to_exclude, chat_name=chat_name + ) + return {"chat_id": chat_id} @router.post( @@ -65,15 +58,9 @@ async def create_chat( response_model=None, ) async def change_chat_data( - user_data: SChangeData, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork) + user_data: SChangeData, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): - async with uow: - chat = await uow.chat.find_one(chat_id=user_data.chat_id, user_id=user.id) - if chat.created_by != user.id: - raise UserDontHavePermissionException - await uow.chat.change_data( - chat_id=user_data.chat_id, chat_name=user_data.chat_name, avatar_image=user_data.avatar_image - ) + await ChatService.change_chat_data(uow=uow, user_id=user.id, user_data=user_data) @router.get( @@ -81,11 +68,10 @@ async def change_chat_data( status_code=status.HTTP_200_OK, response_model=SMessageList, ) -async def get_last_message(chat_id: int, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): +async def get_last_message(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - message = await uow.chat.get_some_messages(chat_id=chat_id, message_number_from=0, messages_to_get=1) - return message + message = await MessageService.get_some_messages(uow=uow, chat_id=chat_id, message_number_from=0, messages_to_get=1) + return message @router.get( @@ -96,18 +82,17 @@ async def get_last_message(chat_id: int, user: SUser = Depends(check_verificated async def get_some_messages( chat_id: int, last_messages: SLastMessages = Depends(), - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - messages = await uow.chat.get_some_messages( - chat_id=chat_id, - message_number_from=last_messages.messages_loaded, - messages_to_get=last_messages.messages_to_get - ) - - return messages + messages = await MessageService.get_some_messages( + uow=uow, + chat_id=chat_id, + message_number_from=last_messages.messages_loaded, + messages_to_get=last_messages.messages_to_get + ) + return messages @router.get( @@ -118,13 +103,12 @@ async def get_some_messages( async def get_message_by_id( chat_id: int, message_id: int, - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - message = await uow.chat.get_message_by_id(message_id=message_id) - return message + message = await MessageService.get_message_by_id(uow=uow, message_id=message_id) + return message @router.get( @@ -134,13 +118,11 @@ async def get_message_by_id( ) async def create_invitation_link( chat_id: int, - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - invitation_data = SInvitationData.model_validate({"chat_id": chat_id}) - invitation_token = encode_invitation_token(invitation_data) - invitation_link = settings.INVITATION_LINK_HOST + "/api/chat/invite_to_chat/" + invitation_token + invitation_link = ChatService.create_invitation_link(chat_id=chat_id) return {"invitation_link": invitation_link} @@ -151,16 +133,10 @@ async def create_invitation_link( ) async def invite_to_chat( invitation_token: str, - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): - invitation_data = decode_invitation_token(invitation_token) - async with uow: - chat = await uow.chat.find_one(chat_id=invitation_data.chat_id, user_id=user.id) - if user.id == chat.chat_for: - raise UserCanNotReadThisChatException - await uow.chat.add_user_to_chat(chat_id=invitation_data.chat_id, user_id=user.id) - await uow.commit() + await ChatService.invite_to_chat(uow=uow, user_id=user.id, invitation_token=invitation_token) @router.delete( @@ -168,13 +144,8 @@ async def invite_to_chat( status_code=status.HTTP_200_OK, response_model=None, ) -async def delete_chat(chat_id: int, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): - async with uow: - chat = await uow.chat.find_one(chat_id=chat_id, user_id=user.id) - if not user.id == chat.created_by: - raise UserDontHavePermissionException - await uow.chat.delete_chat(chat_id) - await uow.commit() +async def delete_chat(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): + await ChatService.delete_chat(uow=uow, user_id=user.id, chat_id=chat_id) @router.delete( @@ -185,41 +156,30 @@ async def delete_chat(chat_id: int, user: SUser = Depends(check_verificated_user async def delete_user_from_chat( chat_id: int, user_id: int, - user: SUser = Depends(check_verificated_user_with_exc), + user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork) ): - async with uow: - chat = await uow.chat.find_one(chat_id=chat_id, user_id=user.id) - if not user.id == chat.created_by: - raise UserDontHavePermissionException - await uow.chat.delete_user_from_chat(chat_id=chat_id, user_id=user_id) - await uow.commit() + await ChatService.delete_user_from_chat(uow=uow, user_id=user.id, chat_id=chat_id, user_id_for_delete=user_id) @router.post( "/pin_chat", status_code=status.HTTP_200_OK, - response_model=SPinnedChat, + response_model=None, ) -async def pinn_chat(chat_id: int, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): +async def pin_chat(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - await uow.chat.pin_chat(chat_id=chat_id, user_id=user.id) - await uow.commit() - return {"chat_id": chat_id, "user_id": user.id} + await ChatService.pin_chat(uow=uow, user_id=user.id, chat_id=chat_id) @router.delete( "/unpin_chat", status_code=status.HTTP_200_OK, - response_model=SPinnedChat, + response_model=None, ) -async def unpinn_chat(chat_id: int, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): +async def unpinn_chat(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - await uow.chat.unpin_chat(chat_id=chat_id, user_id=user.id) - await uow.commit() - return {"chat_id": chat_id, "user_id": user.id} + await ChatService.unpin_chat(uow=uow, user_id=user.id, chat_id=chat_id) @router.get( @@ -227,10 +187,9 @@ async def unpinn_chat(chat_id: int, user: SUser = Depends(check_verificated_user status_code=status.HTTP_200_OK, response_model=SPinnedChats, ) -async def get_pinned_chats(user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): - async with uow: - pinned_chats = await uow.chat.get_pinned_chats(user_id=user.id) - return pinned_chats +async def get_pinned_chats(user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): + pinned_chats = await ChatService.get_pinned_chats(uow=uow, user_id=user.id) + return pinned_chats @router.get( @@ -238,8 +197,7 @@ async def get_pinned_chats(user: SUser = Depends(check_verificated_user_with_exc status_code=status.HTTP_200_OK, response_model=SPinnedMessages, ) -async def pinned_messages(chat_id: int, user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)): +async def pinned_messages(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)): await AuthService.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id) - async with uow: - pinned_messages = await uow.chat.get_pinned_messages(chat_id=chat_id) - return pinned_messages + pinned_messages = await MessageService.get_pinned_messages(uow=uow, chat_id=chat_id) + return pinned_messages diff --git a/app/chat/shemas.py b/app/chat/shemas.py index bbdbf4d..95b33f1 100644 --- a/app/chat/shemas.py +++ b/app/chat/shemas.py @@ -26,11 +26,6 @@ class SLastMessages(BaseModel): messages_to_get: int -class SPinnedChat(BaseModel): - user_id: int - chat_id: int - - class SChat(BaseModel): chat_id: int chat_for: int diff --git a/app/services/chat_service.py b/app/services/chat_service.py new file mode 100644 index 0000000..3745965 --- /dev/null +++ b/app/services/chat_service.py @@ -0,0 +1,90 @@ +from app.chat.exceptions import UserDontHavePermissionException, UserCanNotReadThisChatException +from app.chat.shemas import SAllowedChats, SChangeData, SPinnedChats +from app.config import settings +from app.unit_of_work import UnitOfWork +from app.users.schemas import SInvitationData +from app.utils.auth import encode_invitation_token, decode_invitation_token + + +class ChatService: + @staticmethod + async def get_all_chats(uow: UnitOfWork, user_id: int) -> SAllowedChats: + async with uow: + allowed_chats = await uow.user.get_user_allowed_chats(user_id=user_id) + return allowed_chats + + @staticmethod + async def create_chat(uow: UnitOfWork, user_id: int, user_to_exclude_id: int, chat_name: str) -> int: + async with uow: + user_chat_for = await uow.user.find_one(id=user_to_exclude_id) + 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) + await uow.chat.add_user_to_chat(settings.ADMIN_USER_ID, chat_id) + await uow.commit() + return chat_id + + @staticmethod + async def change_chat_data(uow: UnitOfWork, user_id: int, user_data: SChangeData) -> None: + async with uow: + chat = await uow.chat.find_one(chat_id=user_data.chat_id, user_id=user_id) + if chat.created_by != user_id: + raise UserDontHavePermissionException + await uow.chat.change_data( + chat_id=user_data.chat_id, chat_name=user_data.chat_name, avatar_image=user_data.avatar_image + ) + + @staticmethod + def create_invitation_link(chat_id: int) -> str: + invitation_data = SInvitationData.model_validate({"chat_id": chat_id}) + invitation_token = encode_invitation_token(invitation_data) + invitation_link = settings.INVITATION_LINK_HOST + "/api/chat/invite_to_chat/" + invitation_token + return invitation_link + + @staticmethod + async def invite_to_chat(uow: UnitOfWork, user_id: int, invitation_token: str) -> None: + invitation_data = decode_invitation_token(invitation_token) + async with uow: + chat = await uow.chat.find_one(chat_id=invitation_data.chat_id, user_id=user_id) + if user_id == chat.chat_for: + raise UserCanNotReadThisChatException + await uow.chat.add_user_to_chat(chat_id=invitation_data.chat_id, user_id=user_id) + await uow.commit() + + @staticmethod + async def delete_chat(uow: UnitOfWork, user_id: int, chat_id: int) -> None: + async with uow: + chat = await uow.chat.find_one(chat_id=chat_id, user_id=user_id) + if not user_id == chat.created_by: + raise UserDontHavePermissionException + await uow.chat.delete_chat(chat_id) + await uow.commit() + + @staticmethod + async def delete_user_from_chat(uow: UnitOfWork, user_id: int, chat_id: int, user_id_for_delete: int) -> None: + async with uow: + chat = await uow.chat.find_one(chat_id=chat_id, user_id=user_id) + if not user_id == chat.created_by: + raise UserDontHavePermissionException + await uow.chat.delete_user_from_chat(chat_id=chat_id, user_id=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 diff --git a/app/services/message_service.py b/app/services/message_service.py index 1b29b73..3743b27 100644 --- a/app/services/message_service.py +++ b/app/services/message_service.py @@ -1,4 +1,4 @@ -from app.chat.shemas import SMessage, SSendMessage +from app.chat.shemas import SMessage, SSendMessage, SPinnedMessages, SMessageList from app.unit_of_work import UnitOfWork @@ -45,3 +45,25 @@ class MessageService: async with uow: await uow.chat.unpin_message(chat_id=chat_id, message_id=message_id) await uow.commit() + + @staticmethod + async def get_message_by_id(uow: UnitOfWork, message_id: int) -> SMessage: + async with uow: + message = await uow.chat.get_message_by_id(message_id=message_id) + return message + + @staticmethod + async def get_pinned_messages(uow: UnitOfWork, chat_id: int) -> SPinnedMessages: + async with uow: + pinned_messages = await uow.chat.get_pinned_messages(chat_id=chat_id) + return pinned_messages + + @staticmethod + async def get_some_messages( + uow: UnitOfWork, chat_id: int, message_number_from: int, messages_to_get: int + ) -> SMessageList: + async with uow: + message = await uow.chat.get_some_messages( + chat_id=chat_id, message_number_from=message_number_from, messages_to_get=messages_to_get + ) + return message diff --git a/app/unit_of_work.py b/app/unit_of_work.py index e85230e..2bc7f45 100644 --- a/app/unit_of_work.py +++ b/app/unit_of_work.py @@ -1,6 +1,9 @@ +from sqlalchemy.exc import SQLAlchemyError + from app.dao.chat import ChatDAO from app.database import async_session_maker from app.dao.user import UserDAO +from app.exceptions import BlackPhoenixException class UnitOfWork: @@ -13,9 +16,14 @@ class UnitOfWork: self.user = UserDAO(self.session) self.chat = ChatDAO(self.session) - async def __aexit__(self, *args): - await self.rollback() - await self.session.close() + async def __aexit__(self, exc_type, exc, tb): + try: + await self.rollback() + await self.session.close() + except SQLAlchemyError: + raise BlackPhoenixException + if isinstance(exc, SQLAlchemyError): + raise BlackPhoenixException async def commit(self): await self.session.commit() diff --git a/app/users/dependencies.py b/app/users/dependencies.py index 25612b1..7e06655 100644 --- a/app/users/dependencies.py +++ b/app/users/dependencies.py @@ -42,7 +42,7 @@ async def get_current_user(token: str = Depends(get_token), uow=Depends(UnitOfWo return user -async def check_verificated_user_with_exc(user: SUser = Depends(get_current_user)) -> SUser: +async def get_verificated_user(user: SUser = Depends(get_current_user)) -> SUser: if not user.role >= settings.VERIFICATED_USER: raise UserMustConfirmEmailException return user