Рефакторинг, убрал лишнее ооп
This commit is contained in:
parent
f21cedbb81
commit
fd03106c74
12 changed files with 452 additions and 496 deletions
|
@ -13,11 +13,9 @@ from app.chat.shemas import (
|
|||
SChatId,
|
||||
Responses,
|
||||
)
|
||||
from app.services.chat_service import ChatService
|
||||
from app.services.message_service import MessageService
|
||||
from app.services import chat_service, message_service, auth_service
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.dependencies import get_verificated_user
|
||||
from app.services.auth_service import AuthService
|
||||
from app.users.schemas import SCreateInvitationLink, SUser
|
||||
|
||||
router = APIRouter(prefix="/chat", tags=["Чат"])
|
||||
|
@ -51,7 +49,7 @@ router = APIRouter(prefix="/chat", tags=["Чат"])
|
|||
},
|
||||
)
|
||||
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)
|
||||
allowed_chats = await chat_service.get_all_chats(uow=uow, user_id=user.id)
|
||||
return allowed_chats
|
||||
|
||||
|
||||
|
@ -88,7 +86,7 @@ async def create_chat(
|
|||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
chat_id = await ChatService.create_chat(
|
||||
chat_id = await chat_service.create_chat(
|
||||
uow=uow,
|
||||
user_id=user.id,
|
||||
user_to_exclude_id=user_to_exclude,
|
||||
|
@ -129,8 +127,8 @@ async def change_chat_data(
|
|||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
await AuthService.validate_user_access_to_chat(uow=uow, chat_id=user_data.chat_id, user_id=user.id)
|
||||
await ChatService.change_chat_data(uow=uow, user_id=user.id, user_data=user_data)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=user_data.chat_id, user_id=user.id)
|
||||
await chat_service.change_chat_data(uow=uow, user_id=user.id, user_data=user_data)
|
||||
|
||||
|
||||
@router.get(
|
||||
|
@ -161,8 +159,8 @@ async def change_chat_data(
|
|||
},
|
||||
)
|
||||
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)
|
||||
message = await MessageService.get_some_messages(uow=uow, chat_id=chat_id, message_number_from=0, messages_to_get=1)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
message = await message_service.get_some_messages(uow=uow, chat_id=chat_id, message_number_from=0, messages_to_get=1)
|
||||
return message
|
||||
|
||||
|
||||
|
@ -199,8 +197,8 @@ async def get_some_messages(
|
|||
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)
|
||||
messages = await MessageService.get_some_messages(
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
messages = await message_service.get_some_messages(
|
||||
uow=uow,
|
||||
chat_id=chat_id,
|
||||
message_number_from=last_messages.messages_loaded,
|
||||
|
@ -242,8 +240,8 @@ async def get_message_by_id(
|
|||
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)
|
||||
message = await MessageService.get_message_by_id(uow=uow, message_id=message_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
message = await message_service.get_message_by_id(uow=uow, message_id=message_id)
|
||||
return message
|
||||
|
||||
|
||||
|
@ -279,8 +277,8 @@ async def create_invitation_link(
|
|||
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_link = ChatService.create_invitation_link(chat_id=chat_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
invitation_link = chat_service.create_invitation_link(chat_id=chat_id)
|
||||
return {"invitation_link": invitation_link}
|
||||
|
||||
|
||||
|
@ -316,7 +314,7 @@ async def invite_to_chat(
|
|||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
await ChatService.invite_to_chat(uow=uow, user_id=user.id, invitation_token=invitation_token)
|
||||
await chat_service.invite_to_chat(uow=uow, user_id=user.id, invitation_token=invitation_token)
|
||||
|
||||
|
||||
@router.delete(
|
||||
|
@ -347,7 +345,7 @@ async def invite_to_chat(
|
|||
},
|
||||
)
|
||||
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)
|
||||
await chat_service.delete_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
|
||||
|
||||
@router.delete(
|
||||
|
@ -383,7 +381,7 @@ async def delete_user_from_chat(
|
|||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
await ChatService.delete_user_from_chat(uow=uow, user_id=user.id, chat_id=chat_id, user_id_for_delete=user_id)
|
||||
await chat_service.delete_user_from_chat(uow=uow, user_id=user.id, chat_id=chat_id, user_id_for_delete=user_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
|
@ -414,8 +412,8 @@ async def delete_user_from_chat(
|
|||
},
|
||||
)
|
||||
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)
|
||||
await ChatService.pin_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
await chat_service.pin_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
|
||||
|
||||
@router.delete(
|
||||
|
@ -445,9 +443,9 @@ async def pin_chat(chat_id: int, user: SUser = Depends(get_verificated_user), uo
|
|||
},
|
||||
},
|
||||
)
|
||||
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)
|
||||
await ChatService.unpin_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
async def unpin_chat(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)):
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
await chat_service.unpin_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
|
||||
|
||||
@router.get(
|
||||
|
@ -478,7 +476,7 @@ async def unpinn_chat(chat_id: int, user: SUser = Depends(get_verificated_user),
|
|||
},
|
||||
)
|
||||
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)
|
||||
pinned_chats = await chat_service.get_pinned_chats(uow=uow, user_id=user.id)
|
||||
return pinned_chats
|
||||
|
||||
|
||||
|
@ -510,6 +508,6 @@ async def get_pinned_chats(user: SUser = Depends(get_verificated_user), uow=Depe
|
|||
},
|
||||
)
|
||||
async def get_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)
|
||||
pinned_messages = await MessageService.get_pinned_messages(uow=uow, chat_id=chat_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, chat_id=chat_id, user_id=user.id)
|
||||
pinned_messages = await message_service.get_pinned_messages(uow=uow, chat_id=chat_id)
|
||||
return pinned_messages
|
||||
|
|
|
@ -8,9 +8,8 @@ from fastapi import WebSocket, WebSocketDisconnect, Depends, HTTPException, stat
|
|||
from app.chat.exceptions import UseWSException, MessageNotFoundException, MessageAlreadyPinnedException
|
||||
from app.exceptions import IncorrectDataException
|
||||
from app.chat.exceptions import UserDontHavePermissionException
|
||||
from app.services.message_service import MessageService
|
||||
from app.services import message_service, auth_service
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.services.auth_service import AuthService
|
||||
from app.chat.router import router
|
||||
from app.chat.shemas import SSendMessage, SDeleteMessage, SEditMessage, SPinMessage, SUnpinMessage, Responses
|
||||
from app.dependencies import get_current_user_ws, get_token, get_subprotocol_ws, get_verificated_user
|
||||
|
@ -33,7 +32,10 @@ class ConnectionManager:
|
|||
self.active_connections[chat_id].append(websocket)
|
||||
|
||||
async def disconnect(
|
||||
self, chat_id: int, websocket: WebSocket, code_and_reason: tuple[int, str] | None = None
|
||||
self,
|
||||
chat_id: int,
|
||||
websocket: WebSocket,
|
||||
code_and_reason: tuple[int, str] | None = None,
|
||||
) -> None:
|
||||
self.active_connections[chat_id].remove(websocket)
|
||||
if code_and_reason:
|
||||
|
@ -54,7 +56,7 @@ class ConnectionManager:
|
|||
async def _send(uow: UnitOfWork, user_id: int, chat_id: int, message: dict) -> dict:
|
||||
message = SSendMessage.model_validate(message)
|
||||
|
||||
new_message = await MessageService.send_message(
|
||||
new_message = await message_service.send_message(
|
||||
uow=uow,
|
||||
user_id=user_id,
|
||||
chat_id=chat_id,
|
||||
|
@ -74,7 +76,7 @@ class ConnectionManager:
|
|||
if message.user_id != user_id:
|
||||
raise UserDontHavePermissionException
|
||||
|
||||
await MessageService.delete_message(uow=uow, message_id=message.id)
|
||||
await message_service.delete_message(uow=uow, message_id=message.id)
|
||||
new_message = {"id": str(message.id), "flag": "delete"}
|
||||
return new_message
|
||||
|
||||
|
@ -85,7 +87,7 @@ class ConnectionManager:
|
|||
if message.user_id != user_id:
|
||||
raise UserDontHavePermissionException
|
||||
|
||||
await MessageService.edit_message(
|
||||
await message_service.edit_message(
|
||||
uow=uow,
|
||||
message_id=message.id,
|
||||
new_message=message.new_message,
|
||||
|
@ -102,7 +104,7 @@ class ConnectionManager:
|
|||
@staticmethod
|
||||
async def _pin(uow: UnitOfWork, _: int, chat_id: int, message: dict) -> dict:
|
||||
message = SPinMessage.model_validate(message)
|
||||
pinned_message = await MessageService.pin_message(
|
||||
pinned_message = await message_service.pin_message(
|
||||
uow=uow,
|
||||
chat_id=chat_id,
|
||||
user_id=message.user_id,
|
||||
|
@ -118,7 +120,7 @@ class ConnectionManager:
|
|||
@staticmethod
|
||||
async def _unpin(uow: UnitOfWork, _: int, chat_id: int, message: dict) -> dict:
|
||||
message = SUnpinMessage.model_validate(message)
|
||||
await MessageService.unpin_message(uow=uow, chat_id=chat_id, message_id=message.id)
|
||||
await message_service.unpin_message(uow=uow, chat_id=chat_id, message_id=message.id)
|
||||
new_message = {"flag": "unpin", "id": str(message.id)}
|
||||
return new_message
|
||||
|
||||
|
@ -137,8 +139,8 @@ async def websocket_endpoint(
|
|||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
try:
|
||||
await AuthService.check_verificated_user(uow=uow, user_id=user.id)
|
||||
await AuthService.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await auth_service.check_verificated_user(uow=uow, user_id=user.id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await manager.connect(chat_id, websocket, subprotocol)
|
||||
while True:
|
||||
data = await websocket.receive_json()
|
||||
|
@ -210,11 +212,11 @@ class PollingManager:
|
|||
raise HTTPException(status_code=status.HTTP_408_REQUEST_TIMEOUT, detail="Client disconnected")
|
||||
|
||||
async def prepare(
|
||||
self,
|
||||
uow: UnitOfWork,
|
||||
user_id: int,
|
||||
chat_id: int,
|
||||
message: SSendMessage | SDeleteMessage | SEditMessage | SPinMessage | SUnpinMessage,
|
||||
self,
|
||||
uow: UnitOfWork,
|
||||
user_id: int,
|
||||
chat_id: int,
|
||||
message: SSendMessage | SDeleteMessage | SEditMessage | SPinMessage | SUnpinMessage,
|
||||
) -> None:
|
||||
message = message.model_dump()
|
||||
await manager.broadcast(uow=uow, user_id=user_id, chat_id=chat_id, message=message)
|
||||
|
@ -222,9 +224,9 @@ class PollingManager:
|
|||
await self.send(chat_id=chat_id, message=message)
|
||||
|
||||
async def send(
|
||||
self,
|
||||
chat_id: int,
|
||||
message: dict,
|
||||
self,
|
||||
chat_id: int,
|
||||
message: dict,
|
||||
) -> None:
|
||||
self.messages[chat_id].append(message)
|
||||
while self.waiters[chat_id]:
|
||||
|
@ -266,7 +268,7 @@ polling_manager = PollingManager()
|
|||
},
|
||||
)
|
||||
async def poll(chat_id: int, user: SUser = Depends(get_verificated_user), uow=Depends(UnitOfWork)):
|
||||
await AuthService.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
return await polling_manager.poll(chat_id)
|
||||
|
||||
|
||||
|
@ -298,10 +300,10 @@ async def poll(chat_id: int, user: SUser = Depends(get_verificated_user), uow=De
|
|||
},
|
||||
)
|
||||
async def send(
|
||||
chat_id: int,
|
||||
message: SSendMessage | SDeleteMessage | SEditMessage | SPinMessage | SUnpinMessage,
|
||||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
chat_id: int,
|
||||
message: SSendMessage | SDeleteMessage | SEditMessage | SPinMessage | SUnpinMessage,
|
||||
user: SUser = Depends(get_verificated_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
await AuthService.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await auth_service.validate_user_access_to_chat(uow=uow, user_id=user.id, chat_id=chat_id)
|
||||
await polling_manager.prepare(uow=uow, user_id=user.id, chat_id=chat_id, message=message)
|
||||
|
|
|
@ -7,7 +7,7 @@ from jose import JWTError, jwt, ExpiredSignatureError
|
|||
from app.config import settings
|
||||
from app.exceptions import IncorrectTokenFormatException, TokenMissingException, TokenExpiredException
|
||||
|
||||
from app.services.user_service import UserService
|
||||
from app.services import user_service
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.users.schemas import SUser
|
||||
from app.users.exceptions import UserNotFoundException, UserMustConfirmEmailException
|
||||
|
@ -33,7 +33,7 @@ async def get_current_user(token: str = Depends(get_token), uow=Depends(UnitOfWo
|
|||
if not user_id:
|
||||
raise UserNotFoundException
|
||||
|
||||
user = await UserService.find_user(uow=uow, id=int(user_id))
|
||||
user = await user_service.find_user(uow=uow, id=int(user_id))
|
||||
|
||||
return user
|
||||
|
||||
|
@ -62,7 +62,7 @@ async def get_current_user_ws(token: str = Depends(get_token_ws), uow=Depends(Un
|
|||
if not user_id:
|
||||
raise UserNotFoundException
|
||||
|
||||
user = await UserService.find_user(uow=uow, id=int(user_id))
|
||||
user = await user_service.find_user(uow=uow, id=int(user_id))
|
||||
|
||||
return user
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from fastapi import APIRouter, UploadFile, status, Depends
|
||||
|
||||
from app.images.shemas import SImageUrl, Responses
|
||||
from app.services.image_service import ImageService
|
||||
from app.services import image_service
|
||||
from app.dependencies import get_verificated_user
|
||||
|
||||
router = APIRouter(prefix="/images", tags=["Загрузка картинок"])
|
||||
|
@ -35,7 +35,7 @@ router = APIRouter(prefix="/images", tags=["Загрузка картинок"])
|
|||
},
|
||||
)
|
||||
async def upload_avatar(file: UploadFile, _=Depends(get_verificated_user)):
|
||||
image_url = await ImageService.upload_file_returning_str(file, "upload_avatar")
|
||||
image_url = await image_service.upload_file_returning_str(file, "upload_avatar")
|
||||
return {"image_url": image_url}
|
||||
|
||||
|
||||
|
@ -67,5 +67,5 @@ async def upload_avatar(file: UploadFile, _=Depends(get_verificated_user)):
|
|||
},
|
||||
)
|
||||
async def upload_image(file: UploadFile, _=Depends(get_verificated_user)):
|
||||
image_url = await ImageService.upload_file_returning_str(file, "upload_image")
|
||||
image_url = await image_service.upload_file_returning_str(file, "upload_image")
|
||||
return {"image_url": image_url}
|
||||
|
|
|
@ -15,82 +15,71 @@ from app.chat.exceptions import ChatNotFoundException, UserCanNotReadThisChatExc
|
|||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.users.schemas import SUser, SInvitationData
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # bcrypt не умеет больше 72 байт хешировать. Остальное обрезаем
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
# bcrypt не умеет больше 72 байт хешировать. Остальное обрезаем
|
||||
|
||||
cipher_suite = Fernet(settings.INVITATION_LINK_TOKEN_KEY)
|
||||
|
||||
class AuthService:
|
||||
@staticmethod
|
||||
def get_password_hash(password: str) -> str:
|
||||
return pwd_context.hash(password.encode("utf-8")[:72])
|
||||
def get_password_hash(password: str) -> str:
|
||||
return pwd_context.hash(password.encode("utf-8")[:72])
|
||||
|
||||
@staticmethod
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
return pwd_context.verify(plain_password.encode("utf-8")[:72], hashed_password)
|
||||
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
||||
return pwd_context.verify(plain_password.encode("utf-8")[:72], hashed_password)
|
||||
|
||||
@staticmethod
|
||||
def create_access_token(data: dict[str, str | datetime]) -> str:
|
||||
to_encode = data.copy()
|
||||
expire = datetime.now(UTC) + timedelta(days=30)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, settings.ALGORITHM)
|
||||
return encoded_jwt
|
||||
def create_access_token(data: dict[str, str | datetime]) -> str:
|
||||
to_encode = data.copy()
|
||||
expire = datetime.now(UTC) + timedelta(days=30)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, settings.ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
@staticmethod
|
||||
def encode_invitation_token(user_data: SInvitationData) -> str:
|
||||
invitation_token = cipher_suite.encrypt(user_data.model_dump_json().encode())
|
||||
return invitation_token.decode()
|
||||
def encode_invitation_token(user_data: SInvitationData) -> str:
|
||||
invitation_token = cipher_suite.encrypt(user_data.model_dump_json().encode())
|
||||
return invitation_token.decode()
|
||||
|
||||
@staticmethod
|
||||
def decode_invitation_token(invitation_token: str) -> SInvitationData:
|
||||
try:
|
||||
user_code = invitation_token.encode()
|
||||
user_data = cipher_suite.decrypt(user_code)
|
||||
return SInvitationData.model_validate_json(user_data)
|
||||
except InvalidToken:
|
||||
raise WrongCodeException
|
||||
def decode_invitation_token(invitation_token: str) -> SInvitationData:
|
||||
try:
|
||||
user_code = invitation_token.encode()
|
||||
user_data = cipher_suite.decrypt(user_code)
|
||||
return SInvitationData.model_validate_json(user_data)
|
||||
except InvalidToken:
|
||||
raise WrongCodeException
|
||||
|
||||
@staticmethod
|
||||
def encode_confirmation_token(confirmation_code: str) -> str:
|
||||
invitation_token = cipher_suite.encrypt(confirmation_code.encode())
|
||||
return invitation_token.decode()
|
||||
def encode_confirmation_token(confirmation_code: str) -> str:
|
||||
invitation_token = cipher_suite.encrypt(confirmation_code.encode())
|
||||
return invitation_token.decode()
|
||||
|
||||
@staticmethod
|
||||
def decode_confirmation_token(invitation_token: str) -> str:
|
||||
try:
|
||||
user_code = invitation_token.encode()
|
||||
confirmation_code = cipher_suite.decrypt(user_code).decode()
|
||||
return confirmation_code
|
||||
except InvalidToken:
|
||||
raise WrongCodeException
|
||||
def decode_confirmation_token(invitation_token: str) -> str:
|
||||
try:
|
||||
user_code = invitation_token.encode()
|
||||
confirmation_code = cipher_suite.decrypt(user_code).decode()
|
||||
return confirmation_code
|
||||
except InvalidToken:
|
||||
raise WrongCodeException
|
||||
|
||||
@classmethod
|
||||
def get_confirmation_code(cls, user_code: str) -> str:
|
||||
return user_code if len(user_code) == 6 else cls.decode_confirmation_token(user_code)
|
||||
def get_confirmation_code(user_code: str) -> str:
|
||||
return user_code if len(user_code) == 6 else decode_confirmation_token(user_code)
|
||||
|
||||
@classmethod
|
||||
async def authenticate_user(cls, uow: UnitOfWork, email_or_username: str, password: str) -> SUser:
|
||||
try:
|
||||
async with uow:
|
||||
user = await uow.user.find_one_by_username_or_email(username=email_or_username, email=email_or_username)
|
||||
if not cls.verify_password(password, user.hashed_password):
|
||||
raise IncorrectAuthDataException
|
||||
return user
|
||||
except UserNotFoundException:
|
||||
raise IncorrectAuthDataException
|
||||
|
||||
@classmethod
|
||||
async def check_verificated_user(cls, uow: UnitOfWork, user_id: int) -> None:
|
||||
async def authenticate_user(uow: UnitOfWork, email_or_username: str, password: str) -> SUser:
|
||||
try:
|
||||
async with uow:
|
||||
user = await uow.user.find_one(id=user_id)
|
||||
if user.role < settings.VERIFICATED_USER:
|
||||
raise UserMustConfirmEmailException
|
||||
user = await uow.user.find_one_by_username_or_email(username=email_or_username, email=email_or_username)
|
||||
if not verify_password(password, user.hashed_password):
|
||||
raise IncorrectAuthDataException
|
||||
return user
|
||||
except UserNotFoundException:
|
||||
raise IncorrectAuthDataException
|
||||
|
||||
@classmethod
|
||||
async def validate_user_access_to_chat(cls, uow: UnitOfWork, user_id: int, chat_id: int) -> None:
|
||||
try:
|
||||
async with uow:
|
||||
await uow.chat.find_chat(chat_id=chat_id, user_id=user_id)
|
||||
except ChatNotFoundException:
|
||||
raise UserCanNotReadThisChatException
|
||||
async def check_verificated_user(uow: UnitOfWork, user_id: int) -> None:
|
||||
async with uow:
|
||||
user = await uow.user.find_one(id=user_id)
|
||||
if user.role < settings.VERIFICATED_USER:
|
||||
raise UserMustConfirmEmailException
|
||||
|
||||
async def validate_user_access_to_chat(uow: UnitOfWork, user_id: int, chat_id: int) -> None:
|
||||
try:
|
||||
async with uow:
|
||||
await uow.chat.find_chat(chat_id=chat_id, user_id=user_id)
|
||||
except ChatNotFoundException:
|
||||
raise UserCanNotReadThisChatException
|
||||
|
||||
|
|
|
@ -7,132 +7,118 @@ from app.chat.exceptions import UserDontHavePermissionException, UserCanNotReadT
|
|||
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.services import user_service, auth_service
|
||||
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 def find_chat(uow: UnitOfWork, chat_id: int, user_id: int) -> SChat:
|
||||
async with uow:
|
||||
chat = await uow.chat.find_chat(chat_id=chat_id, user_id=user_id)
|
||||
return chat
|
||||
|
||||
async def find_one(uow: UnitOfWork, chat_id: int) -> SChat:
|
||||
async with uow:
|
||||
chat = await uow.chat.find_one(chat_id=chat_id)
|
||||
return chat
|
||||
|
||||
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:
|
||||
chat = await uow.chat.find_chat(chat_id=chat_id, user_id=user_id)
|
||||
return chat
|
||||
|
||||
@staticmethod
|
||||
async def find_one(uow: UnitOfWork, chat_id: int) -> SChat:
|
||||
async with uow:
|
||||
chat = await uow.chat.find_one(chat_id=chat_id)
|
||||
return chat
|
||||
|
||||
@staticmethod
|
||||
async def get_all_chats(uow: UnitOfWork, user_id: int) -> SAllowedChats:
|
||||
try:
|
||||
allowed_chats = await uow.user.get_user_allowed_chats(user_id=user_id)
|
||||
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
|
||||
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
|
||||
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 user_service.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()
|
||||
async def change_chat_data(uow: UnitOfWork, user_id: int, user_data: SChangeData) -> None:
|
||||
chat = await 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"/submitNewChat#code={invitation_token}")
|
||||
return invitation_link
|
||||
def create_invitation_link(chat_id: int) -> str:
|
||||
invitation_data = SInvitationData.model_validate({"chat_id": chat_id})
|
||||
invitation_token = auth_service.encode_invitation_token(invitation_data)
|
||||
invitation_link = urljoin(settings.INVITATION_LINK_HOST, f"/submitNewChat#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_one(uow=uow, chat_id=invitation_data.chat_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()
|
||||
async def invite_to_chat(uow: UnitOfWork, user_id: int, invitation_token: str) -> None:
|
||||
invitation_data = auth_service.decode_invitation_token(invitation_token)
|
||||
chat = await find_one(uow=uow, chat_id=invitation_data.chat_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()
|
||||
async def delete_chat(uow: UnitOfWork, user_id: int, chat_id: int) -> None:
|
||||
chat = await 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()
|
||||
async def delete_user_from_chat(uow: UnitOfWork, user_id: int, chat_id: int, user_id_for_delete: int) -> None:
|
||||
chat = await 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()
|
||||
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()
|
||||
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
|
||||
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
|
||||
|
|
|
@ -6,28 +6,25 @@ from httpx import AsyncClient, Response
|
|||
from app.config import settings
|
||||
|
||||
|
||||
class ImageService:
|
||||
@staticmethod
|
||||
async def upload_file(file: UploadFile, remote_server_url: str) -> Response:
|
||||
try:
|
||||
file_content = await file.read()
|
||||
async with AsyncClient() as ac:
|
||||
response = await ac.post(
|
||||
remote_server_url,
|
||||
files={"file": file_content},
|
||||
timeout=20,
|
||||
)
|
||||
if response.status_code != 200:
|
||||
raise HTTPException(status_code=response.status_code, detail=response.json()["detail"])
|
||||
return response
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
async def upload_file(file: UploadFile, remote_server_url: str) -> Response:
|
||||
try:
|
||||
file_content = await file.read()
|
||||
async with AsyncClient() as ac:
|
||||
response = await ac.post(
|
||||
remote_server_url,
|
||||
files={"file": file_content},
|
||||
timeout=20,
|
||||
)
|
||||
if response.status_code != 200:
|
||||
raise HTTPException(status_code=response.status_code, detail=response.json()["detail"])
|
||||
return response
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@classmethod
|
||||
async def upload_file_returning_str(cls, file: UploadFile, sub_str: str) -> str:
|
||||
remote_server_url = urljoin(settings.IMAGE_UPLOAD_SERVER, sub_str)
|
||||
response = await cls.upload_file(file, remote_server_url)
|
||||
image_url = response.json()["image_url"]
|
||||
image_url = urljoin(settings.IMAGE_UPLOAD_SERVER, image_url)
|
||||
return image_url
|
||||
async def upload_file_returning_str(file: UploadFile, sub_str: str) -> str:
|
||||
remote_server_url = urljoin(settings.IMAGE_UPLOAD_SERVER, sub_str)
|
||||
response = await upload_file(file, remote_server_url)
|
||||
image_url = response.json()["image_url"]
|
||||
image_url = urljoin(settings.IMAGE_UPLOAD_SERVER, image_url)
|
||||
return image_url
|
||||
|
||||
|
|
|
@ -2,137 +2,130 @@ from datetime import datetime, UTC, timedelta
|
|||
from uuid import UUID
|
||||
|
||||
from app.chat.shemas import SMessage, SSendMessage, SPinnedMessages, SMessageList, SMessageRaw, SMessageRawList
|
||||
from app.services.user_service import UserService
|
||||
from app.services import user_service
|
||||
from app.users.schemas import SUser
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
|
||||
|
||||
class MessageService:
|
||||
users: dict[int, tuple[SUser, datetime]] = {}
|
||||
_users: dict[int, tuple[SUser, datetime]] = {}
|
||||
|
||||
@classmethod
|
||||
async def _get_cached_user(cls, uow: UnitOfWork, user_id: int) -> SUser:
|
||||
if user_id in cls.users and cls.users[user_id][1] > datetime.now(UTC):
|
||||
return cls.users[user_id][0]
|
||||
async def _get_cached_user(uow: UnitOfWork, user_id: int) -> SUser:
|
||||
if user_id in _users and _users[user_id][1] > datetime.now(UTC):
|
||||
return _users[user_id][0]
|
||||
|
||||
user = await UserService.find_user(uow=uow, id=user_id)
|
||||
cls.users[user_id] = user, datetime.now(UTC) + timedelta(minutes=5)
|
||||
return user
|
||||
user = await user_service.find_user(uow=uow, id=user_id)
|
||||
_users[user_id] = user, datetime.now(UTC) + timedelta(minutes=5)
|
||||
return user
|
||||
|
||||
@classmethod
|
||||
async def _add_avatar_image_and_username_to_message(cls, uow: UnitOfWork, message: SMessageRaw) -> SMessage:
|
||||
user = await cls._get_cached_user(uow=uow, user_id=message.user_id)
|
||||
message = message.model_dump()
|
||||
message["avatar_image"] = str(user.avatar_image)
|
||||
message["username"] = user.username
|
||||
return SMessage.model_validate(message)
|
||||
|
||||
@classmethod
|
||||
async def _add_avatar_image_and_username_to_message_list(
|
||||
cls,
|
||||
uow: UnitOfWork,
|
||||
messages: SMessageRawList,
|
||||
) -> SMessageList:
|
||||
return SMessageList.model_validate(
|
||||
{
|
||||
"messages": [
|
||||
await cls._add_avatar_image_and_username_to_message(uow=uow, message=message)
|
||||
for message in messages.message_raw_list
|
||||
] if messages.message_raw_list else None
|
||||
}
|
||||
async def _add_avatar_image_and_username_to_message(uow: UnitOfWork, message: SMessageRaw) -> SMessage:
|
||||
user = await _get_cached_user(uow=uow, user_id=message.user_id)
|
||||
message = message.model_dump()
|
||||
message["avatar_image"] = str(user.avatar_image)
|
||||
message["username"] = user.username
|
||||
return SMessage.model_validate(message)
|
||||
|
||||
|
||||
async def _add_avatar_image_and_username_to_message_list(
|
||||
uow: UnitOfWork,
|
||||
messages: SMessageRawList,
|
||||
) -> SMessageList:
|
||||
return SMessageList.model_validate(
|
||||
{
|
||||
"messages": [
|
||||
await _add_avatar_image_and_username_to_message(uow=uow, message=message)
|
||||
for message in messages.message_raw_list
|
||||
] if messages.message_raw_list else None
|
||||
}
|
||||
)
|
||||
|
||||
async def send_message(
|
||||
uow: UnitOfWork,
|
||||
user_id: int,
|
||||
chat_id: int,
|
||||
message: SSendMessage,
|
||||
) -> SMessage:
|
||||
async with uow:
|
||||
if message.answer:
|
||||
answer_message = await uow.message.get_message_by_id(message_id=message.answer)
|
||||
message_id = await uow.message.send_message(
|
||||
user_id=user_id,
|
||||
chat_id=chat_id,
|
||||
message=message.message,
|
||||
image_url=message.image_url,
|
||||
answer_id=answer_message.id,
|
||||
answer_message=answer_message.message,
|
||||
answer_image_url=answer_message.answer_image_url,
|
||||
)
|
||||
else:
|
||||
message_id = await uow.message.send_message(
|
||||
user_id=user_id,
|
||||
chat_id=chat_id,
|
||||
message=message.message,
|
||||
image_url=message.image_url,
|
||||
)
|
||||
|
||||
new_message = await get_message_by_id(uow=uow, message_id=message_id)
|
||||
|
||||
return new_message
|
||||
|
||||
async def delete_message(uow: UnitOfWork, message_id: UUID) -> None:
|
||||
async with uow:
|
||||
await uow.message.delete_message(message_id=message_id)
|
||||
|
||||
async def edit_message(uow: UnitOfWork, message_id: UUID, new_message: str, new_image_url: str) -> None:
|
||||
async with uow:
|
||||
await uow.message.edit_message(
|
||||
message_id=message_id,
|
||||
new_message=new_message,
|
||||
new_image_url=new_image_url,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def send_message(
|
||||
cls,
|
||||
uow: UnitOfWork,
|
||||
user_id: int,
|
||||
chat_id: int,
|
||||
message: SSendMessage,
|
||||
) -> SMessage:
|
||||
async with uow:
|
||||
if message.answer:
|
||||
answer_message = await uow.message.get_message_by_id(message_id=message.answer)
|
||||
message_id = await uow.message.send_message(
|
||||
user_id=user_id,
|
||||
chat_id=chat_id,
|
||||
message=message.message,
|
||||
image_url=message.image_url,
|
||||
answer_id=answer_message.id,
|
||||
answer_message=answer_message.message,
|
||||
answer_image_url=answer_message.answer_image_url,
|
||||
)
|
||||
else:
|
||||
message_id = await uow.message.send_message(
|
||||
user_id=user_id,
|
||||
chat_id=chat_id,
|
||||
message=message.message,
|
||||
image_url=message.image_url,
|
||||
)
|
||||
|
||||
async def pin_message(uow: UnitOfWork, chat_id: int, user_id: int, message_id: UUID) -> SMessage:
|
||||
async with uow:
|
||||
await uow.chat.pin_message(chat_id=chat_id, message_id=message_id, user_id=user_id)
|
||||
await uow.commit()
|
||||
|
||||
pinned_message = await get_message_by_id(uow=uow, message_id=message_id)
|
||||
|
||||
return pinned_message
|
||||
|
||||
|
||||
async def unpin_message(uow: UnitOfWork, chat_id: int, message_id: UUID) -> None:
|
||||
async with uow:
|
||||
await uow.chat.unpin_message(chat_id=chat_id, message_id=message_id)
|
||||
await uow.commit()
|
||||
|
||||
|
||||
async def get_message_by_id(uow: UnitOfWork, message_id: UUID) -> SMessage:
|
||||
async with uow:
|
||||
raw_message = await uow.message.get_message_by_id(message_id=message_id)
|
||||
new_message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
|
||||
message = await _add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
|
||||
return message
|
||||
|
||||
return new_message
|
||||
|
||||
@staticmethod
|
||||
async def delete_message(uow: UnitOfWork, message_id: UUID) -> None:
|
||||
async with uow:
|
||||
await uow.message.delete_message(message_id=message_id)
|
||||
async def get_pinned_messages(uow: UnitOfWork, chat_id: int) -> SPinnedMessages:
|
||||
async with uow:
|
||||
pinned_messages_ids = await uow.chat.get_pinned_messages_ids(chat_id=chat_id)
|
||||
raw_messages = await uow.message.get_messages_by_ids(messages_ids=pinned_messages_ids)
|
||||
|
||||
@staticmethod
|
||||
async def edit_message(uow: UnitOfWork, message_id: UUID, new_message: str, new_image_url: str) -> None:
|
||||
async with uow:
|
||||
await uow.message.edit_message(
|
||||
message_id=message_id,
|
||||
new_message=new_message,
|
||||
new_image_url=new_image_url,
|
||||
)
|
||||
pinned_messages = await _add_avatar_image_and_username_to_message_list(uow=uow, messages=raw_messages)
|
||||
return SPinnedMessages.model_validate({"pinned_messages": pinned_messages.messages})
|
||||
|
||||
@classmethod
|
||||
async def pin_message(cls, uow: UnitOfWork, chat_id: int, user_id: int, message_id: UUID) -> SMessage:
|
||||
async with uow:
|
||||
await uow.chat.pin_message(chat_id=chat_id, message_id=message_id, user_id=user_id)
|
||||
await uow.commit()
|
||||
|
||||
raw_message = await uow.message.get_message_by_id(message_id=message_id)
|
||||
pinned_message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
|
||||
async def get_some_messages(
|
||||
uow: UnitOfWork,
|
||||
chat_id: int,
|
||||
message_number_from: int,
|
||||
messages_to_get: int,
|
||||
) -> SMessageList:
|
||||
async with uow:
|
||||
messages = await uow.message.get_some_messages(
|
||||
chat_id=chat_id,
|
||||
message_number_from=message_number_from,
|
||||
messages_to_get=messages_to_get,
|
||||
)
|
||||
|
||||
return pinned_message
|
||||
|
||||
@staticmethod
|
||||
async def unpin_message(uow: UnitOfWork, chat_id: int, message_id: UUID) -> None:
|
||||
async with uow:
|
||||
await uow.chat.unpin_message(chat_id=chat_id, message_id=message_id)
|
||||
await uow.commit()
|
||||
|
||||
@classmethod
|
||||
async def get_message_by_id(cls, uow: UnitOfWork, message_id: UUID) -> SMessage:
|
||||
async with uow:
|
||||
raw_message = await uow.message.get_message_by_id(message_id=message_id)
|
||||
message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
|
||||
return message
|
||||
|
||||
@classmethod
|
||||
async def get_pinned_messages(cls, uow: UnitOfWork, chat_id: int) -> SPinnedMessages:
|
||||
async with uow:
|
||||
pinned_messages_ids = await uow.chat.get_pinned_messages_ids(chat_id=chat_id)
|
||||
raw_messages = await uow.message.get_messages_by_ids(messages_ids=pinned_messages_ids)
|
||||
pinned_messages = await cls._add_avatar_image_and_username_to_message_list(uow=uow, messages=raw_messages)
|
||||
return SPinnedMessages.model_validate({"pinned_messages": pinned_messages.messages})
|
||||
|
||||
@classmethod
|
||||
async def get_some_messages(
|
||||
cls,
|
||||
uow: UnitOfWork,
|
||||
chat_id: int,
|
||||
message_number_from: int,
|
||||
messages_to_get: int,
|
||||
) -> SMessageList:
|
||||
async with uow:
|
||||
messages = await uow.message.get_some_messages(
|
||||
chat_id=chat_id,
|
||||
message_number_from=message_number_from,
|
||||
messages_to_get=messages_to_get,
|
||||
)
|
||||
messages = await cls._add_avatar_image_and_username_to_message_list(uow=uow, messages=messages)
|
||||
return messages
|
||||
messages = await _add_avatar_image_and_username_to_message_list(uow=uow, messages=messages)
|
||||
return messages
|
||||
|
|
|
@ -4,118 +4,110 @@ from pydantic import ValidationError
|
|||
|
||||
from app.config import settings
|
||||
from app.exceptions import BlackPhoenixException
|
||||
from app.services.redis_service import RedisService
|
||||
from app.tasks.tasks import generate_confirmation_code, send_confirmation_email, send_data_change_email
|
||||
from app.tasks import tasks
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.users.exceptions import PasswordsMismatchException, WrongCodeException
|
||||
from app.users.schemas import SUser, SUsers, SUserRegister, SConfirmationData, SUserAvatars, SUserChangeData
|
||||
from app.services.auth_service import AuthService
|
||||
from app.services import auth_service
|
||||
from app.services.redis_service import RedisService
|
||||
|
||||
|
||||
class UserService:
|
||||
@staticmethod
|
||||
async def find_user(uow: UnitOfWork, **find_by) -> SUser:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
user = await redis.get_value(key=f"user: {find_by}", model=SUser)
|
||||
return user
|
||||
except (ValidationError, BlackPhoenixException):
|
||||
async with uow:
|
||||
user = await uow.user.find_one(**find_by)
|
||||
async with RedisService() as redis:
|
||||
await redis.set_key(
|
||||
key=f"user: {find_by}",
|
||||
expire_time=timedelta(minutes=30),
|
||||
value=user.model_dump_json(),
|
||||
)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
async def find_all(uow: UnitOfWork, username: str) -> SUsers:
|
||||
async def find_user(uow: UnitOfWork, **find_by) -> SUser:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
user = await redis.get_value(key=f"user: {find_by}", model=SUser)
|
||||
return user
|
||||
except (ValidationError, BlackPhoenixException):
|
||||
async with uow:
|
||||
users = await uow.user.find_all(username=username)
|
||||
return users
|
||||
|
||||
@staticmethod
|
||||
async def add_user(uow: UnitOfWork, user_data: SUserRegister) -> SUser:
|
||||
if user_data.password != user_data.password2:
|
||||
raise PasswordsMismatchException
|
||||
|
||||
hashed_password = AuthService.get_password_hash(user_data.password)
|
||||
async with uow:
|
||||
user = await uow.user.add(
|
||||
email=user_data.email,
|
||||
hashed_password=hashed_password,
|
||||
username=user_data.username,
|
||||
date_of_birth=user_data.date_of_birth,
|
||||
)
|
||||
await uow.user.add_user_avatar(user_id=user.id, avatar=str(user.avatar_image))
|
||||
await uow.commit()
|
||||
user = await uow.user.find_one(**find_by)
|
||||
async with RedisService() as redis:
|
||||
await redis.set_key(
|
||||
key=f"user: {find_by}",
|
||||
expire_time=timedelta(minutes=30),
|
||||
value=user.model_dump_json(),
|
||||
)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
async def send_confirmation_email(user: SUser, mail_type: str, email: str | None = None) -> None:
|
||||
user_code = generate_confirmation_code()
|
||||
async def find_all(uow: UnitOfWork, username: str) -> SUsers:
|
||||
async with uow:
|
||||
users = await uow.user.find_all(username=username)
|
||||
return users
|
||||
|
||||
async def add_user(uow: UnitOfWork, user_data: SUserRegister) -> SUser:
|
||||
if user_data.password != user_data.password2:
|
||||
raise PasswordsMismatchException
|
||||
|
||||
hashed_password = auth_service.get_password_hash(user_data.password)
|
||||
async with uow:
|
||||
user = await uow.user.add(
|
||||
email=user_data.email,
|
||||
hashed_password=hashed_password,
|
||||
username=user_data.username,
|
||||
date_of_birth=user_data.date_of_birth,
|
||||
)
|
||||
await uow.user.add_user_avatar(user_id=user.id, avatar=str(user.avatar_image))
|
||||
await uow.commit()
|
||||
return user
|
||||
|
||||
async def send_confirmation_email(user: SUser, mail_type: str, email: str | None = None) -> None:
|
||||
user_code = tasks.generate_confirmation_code()
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
await redis.delete_key(key=f"user_verification_code: {user.id}")
|
||||
await redis.set_key(key=f"user_verification_code: {user.id}", expire_time=timedelta(minutes=5), value=user_code)
|
||||
|
||||
user_mail_data = SConfirmationData.model_validate(
|
||||
{
|
||||
"user_id": user.id,
|
||||
"username": user.username,
|
||||
"email_to": email or user.email,
|
||||
"confirmation_code": user_code,
|
||||
"type": mail_type,
|
||||
}
|
||||
)
|
||||
tasks.send_confirmation_email.delay(user_mail_data.model_dump())
|
||||
|
||||
async def verificate_user(uow: UnitOfWork, user: SUser, confirmation_code: str) -> None:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
await redis.delete_key(key=f"user_verification_code: {user.id}")
|
||||
await redis.set_key(key=f"user_verification_code: {user.id}", expire_time=timedelta(minutes=5), value=user_code)
|
||||
|
||||
user_mail_data = SConfirmationData.model_validate(
|
||||
{
|
||||
"user_id": user.id,
|
||||
"username": user.username,
|
||||
"email_to": email or user.email,
|
||||
"confirmation_code": user_code,
|
||||
"type": mail_type,
|
||||
}
|
||||
)
|
||||
send_confirmation_email.delay(user_mail_data.model_dump())
|
||||
|
||||
@staticmethod
|
||||
async def verificate_user(uow: UnitOfWork, user: SUser, confirmation_code: str) -> None:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
|
||||
except AttributeError:
|
||||
raise WrongCodeException
|
||||
if verification_code != confirmation_code:
|
||||
raise WrongCodeException
|
||||
async with uow:
|
||||
await uow.user.change_data(user_id=user.id, role=settings.VERIFICATED_USER)
|
||||
async with RedisService() as redis:
|
||||
await redis.delete_key(key=f"user: {dict(id=user.id)}")
|
||||
await uow.commit()
|
||||
|
||||
@staticmethod
|
||||
async def get_user_avatars_history(uow: UnitOfWork, user_id: int) -> SUserAvatars:
|
||||
async with uow:
|
||||
user_avatars = await uow.user.get_user_avatars(user_id=user_id)
|
||||
return user_avatars
|
||||
|
||||
@staticmethod
|
||||
async def change_data(uow: UnitOfWork, user: SUser, user_data: SUserChangeData) -> None:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
|
||||
except AttributeError:
|
||||
raise WrongCodeException
|
||||
if verification_code != user_data.verification_code:
|
||||
raise WrongCodeException
|
||||
hashed_password = (
|
||||
AuthService.get_password_hash(user_data.new_password) if user_data.new_password else user.hashed_password
|
||||
)
|
||||
async with uow:
|
||||
await uow.user.change_data(
|
||||
user_id=user.id,
|
||||
email=user_data.email,
|
||||
username=user_data.username,
|
||||
avatar_image=str(user_data.avatar_url or user.avatar_image),
|
||||
hashed_password=hashed_password,
|
||||
)
|
||||
(await uow.user.add_user_avatar(user_id=user.id, avatar=str(user_data.avatar_url))) if user_data.avatar_url else None # noqa
|
||||
await uow.commit()
|
||||
|
||||
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
|
||||
except AttributeError:
|
||||
raise WrongCodeException
|
||||
if verification_code != confirmation_code:
|
||||
raise WrongCodeException
|
||||
async with uow:
|
||||
await uow.user.change_data(user_id=user.id, role=settings.VERIFICATED_USER)
|
||||
async with RedisService() as redis:
|
||||
await redis.delete_key(key=f"user: {dict(id=user.id)}")
|
||||
await uow.commit()
|
||||
|
||||
send_data_change_email.delay(user_data.username, user_data.email)
|
||||
async def get_user_avatars_history(uow: UnitOfWork, user_id: int) -> SUserAvatars:
|
||||
async with uow:
|
||||
user_avatars = await uow.user.get_user_avatars(user_id=user_id)
|
||||
return user_avatars
|
||||
|
||||
async def change_data(uow: UnitOfWork, user: SUser, user_data: SUserChangeData) -> None:
|
||||
try:
|
||||
async with RedisService(is_raise=True) as redis:
|
||||
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
|
||||
except AttributeError:
|
||||
raise WrongCodeException
|
||||
if verification_code != user_data.verification_code:
|
||||
raise WrongCodeException
|
||||
hashed_password = (
|
||||
auth_service.get_password_hash(user_data.new_password) if user_data.new_password else user.hashed_password
|
||||
)
|
||||
async with uow:
|
||||
await uow.user.change_data(
|
||||
user_id=user.id,
|
||||
email=user_data.email,
|
||||
username=user_data.username,
|
||||
avatar_image=str(user_data.avatar_url or user.avatar_image),
|
||||
hashed_password=hashed_password,
|
||||
)
|
||||
(await uow.user.add_user_avatar(user_id=user.id, avatar=str(user_data.avatar_url))) if user_data.avatar_url else None # noqa
|
||||
await uow.commit()
|
||||
|
||||
async with RedisService() as redis:
|
||||
await redis.delete_key(key=f"user: {dict(id=user.id)}")
|
||||
|
||||
tasks.send_data_change_email.delay(user_data.username, user_data.email)
|
||||
|
|
|
@ -13,7 +13,7 @@ from app.tasks.email_templates import (
|
|||
create_data_change_confirmation_email,
|
||||
create_data_change_email,
|
||||
)
|
||||
from app.services.auth_service import AuthService
|
||||
from app.services import auth_service
|
||||
from app.users.schemas import SConfirmationData
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ def generate_confirmation_code(length=6) -> str:
|
|||
@celery.task
|
||||
def send_confirmation_email(user_data: dict) -> None:
|
||||
user_data = SConfirmationData.model_validate(user_data)
|
||||
invitation_token = AuthService.encode_confirmation_token(user_data.confirmation_code)
|
||||
invitation_token = auth_service.encode_confirmation_token(user_data.confirmation_code)
|
||||
|
||||
confirmation_link = urljoin(settings.INVITATION_LINK_HOST, f"/submitEmail#code={invitation_token}")
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@ from random import randrange
|
|||
|
||||
from fastapi import APIRouter, Depends, status
|
||||
|
||||
from app.services.user_service import UserService
|
||||
from app.services import user_service, auth_service
|
||||
from app.users.exceptions import UserAlreadyExistsException, PasswordAlreadyInUseException, UserNotFoundException
|
||||
from app.utils.unit_of_work import UnitOfWork
|
||||
from app.services.auth_service import AuthService
|
||||
from app.dependencies import get_current_user
|
||||
from app.users.schemas import (
|
||||
SUserLogin,
|
||||
|
@ -39,7 +38,7 @@ router = APIRouter(prefix="/users", tags=["Пользователи"])
|
|||
},
|
||||
)
|
||||
async def get_all_users(filter_by=Depends(SGetUsersFilter), uow=Depends(UnitOfWork)):
|
||||
users = await UserService.find_all(uow=uow, username=filter_by.username)
|
||||
users = await user_service.find_all(uow=uow, username=filter_by.username)
|
||||
return users
|
||||
|
||||
|
||||
|
@ -60,7 +59,7 @@ async def get_all_users(filter_by=Depends(SGetUsersFilter), uow=Depends(UnitOfWo
|
|||
)
|
||||
async def check_existing_user(user_filter: SUserFilter, uow=Depends(UnitOfWork)):
|
||||
try:
|
||||
await UserService.find_user(uow=uow, **user_filter.model_dump(exclude_none=True))
|
||||
await user_service.find_user(uow=uow, **user_filter.model_dump(exclude_none=True))
|
||||
raise UserAlreadyExistsException
|
||||
except UserNotFoundException:
|
||||
pass
|
||||
|
@ -103,10 +102,10 @@ async def check_existing_password(_: SUserPassword):
|
|||
},
|
||||
)
|
||||
async def register_user(user_data: SUserRegister, uow=Depends(UnitOfWork)):
|
||||
user = await UserService.add_user(uow=uow, user_data=user_data)
|
||||
await UserService.send_confirmation_email(user=user, mail_type="registration")
|
||||
user = await user_service.add_user(uow=uow, user_data=user_data)
|
||||
await user_service.send_confirmation_email(user=user, mail_type="registration")
|
||||
|
||||
access_token = AuthService.create_access_token({"sub": str(user.id)})
|
||||
access_token = auth_service.create_access_token({"sub": str(user.id)})
|
||||
return {"authorization": f"Bearer {access_token}"}
|
||||
|
||||
|
||||
|
@ -138,7 +137,7 @@ async def register_user(user_data: SUserRegister, uow=Depends(UnitOfWork)):
|
|||
},
|
||||
)
|
||||
async def resend_email_verification(user: SUser = Depends(get_current_user)):
|
||||
await UserService.send_confirmation_email(user=user, mail_type="registration")
|
||||
await user_service.send_confirmation_email(user=user, mail_type="registration")
|
||||
|
||||
|
||||
@router.post(
|
||||
|
@ -169,8 +168,8 @@ async def resend_email_verification(user: SUser = Depends(get_current_user)):
|
|||
},
|
||||
)
|
||||
async def email_verification(user_code: SUserCode, user: SUser = Depends(get_current_user), uow=Depends(UnitOfWork)):
|
||||
confirmation_code = AuthService.get_confirmation_code(user_code.user_code)
|
||||
await UserService.verificate_user(uow=uow, user=user, confirmation_code=confirmation_code)
|
||||
confirmation_code = auth_service.get_confirmation_code(user_code.user_code)
|
||||
await user_service.verificate_user(uow=uow, user=user, confirmation_code=confirmation_code)
|
||||
|
||||
|
||||
@router.post(
|
||||
|
@ -193,12 +192,12 @@ async def email_verification(user_code: SUserCode, user: SUser = Depends(get_cur
|
|||
},
|
||||
)
|
||||
async def login_user(user_data: SUserLogin, uow=Depends(UnitOfWork)):
|
||||
user = await AuthService.authenticate_user(
|
||||
user = await auth_service.authenticate_user(
|
||||
uow=uow,
|
||||
email_or_username=user_data.email_or_username,
|
||||
password=user_data.password,
|
||||
)
|
||||
access_token = AuthService.create_access_token({"sub": str(user.id)})
|
||||
access_token = auth_service.create_access_token({"sub": str(user.id)})
|
||||
return {"authorization": f"Bearer {access_token}"}
|
||||
|
||||
|
||||
|
@ -253,7 +252,7 @@ async def get_user(user: SUser = Depends(get_current_user)):
|
|||
},
|
||||
)
|
||||
async def get_user_avatars_history(user=Depends(get_current_user), uow=Depends(UnitOfWork)):
|
||||
user_avatars = await UserService.get_user_avatars_history(uow=uow, user_id=user.id)
|
||||
user_avatars = await user_service.get_user_avatars_history(uow=uow, user_id=user.id)
|
||||
return user_avatars
|
||||
|
||||
|
||||
|
@ -281,7 +280,7 @@ async def get_user_avatars_history(user=Depends(get_current_user), uow=Depends(U
|
|||
},
|
||||
)
|
||||
async def send_confirmation_code(user_data: SUserSendConfirmationCode, user: SUser = Depends(get_current_user)):
|
||||
await UserService.send_confirmation_email(user=user, mail_type="data_change_confirmation", email=user_data.email)
|
||||
await user_service.send_confirmation_email(user=user, mail_type="data_change_confirmation", email=user_data.email)
|
||||
|
||||
|
||||
@router.post(
|
||||
|
@ -316,4 +315,4 @@ async def change_user_data(
|
|||
user: SUser = Depends(get_current_user),
|
||||
uow=Depends(UnitOfWork),
|
||||
):
|
||||
await UserService.change_data(uow=uow, user=user, user_data=user_data)
|
||||
await user_service.change_data(uow=uow, user=user, user_data=user_data)
|
||||
|
|
|
@ -42,7 +42,7 @@ target-version = "py312"
|
|||
[lint]
|
||||
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
|
||||
select = ["F", "E", "W", "C"]
|
||||
ignore = ["W191", "W391", "C901"]
|
||||
ignore = ["W191", "W391", "C901", "C408"]
|
||||
|
||||
# Allow fix for all enabled rules (when `--fix`) is provided.
|
||||
fixable = ["ALL"]
|
||||
|
|
Loading…
Add table
Reference in a new issue