Переделка бд

This commit is contained in:
urec56 2024-06-07 20:37:45 +05:00
parent 51f32c0750
commit 56afc2649b
13 changed files with 133 additions and 157 deletions

33
app/chat/exceptions.py Normal file
View file

@ -0,0 +1,33 @@
from fastapi import status
from app.exceptions import BlackPhoenixException
class UseWSException(BlackPhoenixException):
status_code = status.HTTP_403_FORBIDDEN
detail = "Це для теста, не трожь сцука!!!"
class UserDontHavePermissionException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "У вас нет прав для этого действия"
class MessageNotFoundException(BlackPhoenixException):
status_code = status.HTTP_404_NOT_FOUND
detail = "Сообщение не найдено"
class UserCanNotReadThisChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер не может читать этот чат"
class UserAlreadyInChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер уже добавлен в чат"
class UserAlreadyPinnedChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер уже закрепил чат"

View file

@ -1,7 +1,11 @@
from fastapi import APIRouter, Depends, status
from app.config import settings
from app.exceptions import UserDontHavePermissionException, MessageNotFoundException, UserCanNotReadThisChatException
from app.chat.exceptions import (
UserDontHavePermissionException,
MessageNotFoundException,
UserCanNotReadThisChatException,
)
from app.chat.shemas import (
SMessage,
SLastMessages,
@ -11,7 +15,7 @@ from app.chat.shemas import (
SAllowedChats,
SMessageList,
SPinnedChats,
SPinnedMessages
SPinnedMessages,
)
from app.unit_of_work import UnitOfWork
from app.users.dependencies import check_verificated_user_with_exc

View file

@ -1,9 +1,9 @@
import logging
import websockets
from fastapi import WebSocket, WebSocketDisconnect, Depends
from app.exceptions import IncorrectDataException, UserDontHavePermissionException
from app.chat.exceptions import UseWSException
from app.exceptions import IncorrectDataException
from app.chat.exceptions import UserDontHavePermissionException
from app.services.message_service import MessageService
from app.unit_of_work import UnitOfWork
from app.utils.auth import AuthService
@ -97,10 +97,8 @@ class ConnectionManager:
@staticmethod
async def add_message_to_database(uow: UnitOfWork, user_id: int, chat_id: int, message: SSendMessage) -> SMessage:
new_message = await MessageService.send_message(
uow=uow, user_id=user_id, chat_id=chat_id, message=message.message, image_url=message.image_url
uow=uow, user_id=user_id, chat_id=chat_id, message=message, image_url=message.image_url
)
if message.answer:
new_message = await MessageService.add_answer(uow=uow, self_id=new_message.id, answer_id=message.answer)
return new_message
@staticmethod
@ -152,13 +150,13 @@ async def websocket_endpoint(
@router.post(
"/ws/{chat_id}"
"/ws/{chat_id}",
)
async def websocket_endpoint(
async def chat_ws(
chat_id: int,
token: str = Depends(get_token),
):
logging.critical("Это сообщение уровня INFO")
raise UseWSException # noqa
url = f"ws://localhost:8000/api/chat/ws/{chat_id}"
async with websockets.connect(url, extra_headers={"Authorization": f"Bearer {token}"}) as websocket:
print(await websocket.recv())

View file

@ -1,9 +1,11 @@
from sqlalchemy import insert, select, update, delete
import logging
from sqlalchemy import insert, select, update, delete, func
from sqlalchemy.exc import IntegrityError
from app.dao.base import BaseDAO
from app.database import engine # noqa
from app.exceptions import UserAlreadyInChatException, UserAlreadyPinnedChatException
from app.chat.exceptions import UserAlreadyInChatException, UserAlreadyPinnedChatException
from app.chat.shemas import SMessage
from app.models.users import Users
from app.models.message_answer import MessageAnswer
@ -37,38 +39,15 @@ class ChatDAO(BaseDAO):
except IntegrityError:
raise UserAlreadyInChatException
async def send_message(self, user_id: int, chat_id: int, message: str, image_url: str | None = None) -> SMessage:
inserted_image = (
async def send_message(self, user_id: int, chat_id: int, message: str, image_url: str | None = None) -> int:
stmt = (
insert(Message)
.values(chat_id=chat_id, user_id=user_id, message=message, image_url=image_url)
.returning(
Message.id, Message.message, Message.image_url, Message.chat_id, Message.user_id, Message.created_at
)
.cte("inserted_image")
.returning(Message.id)
)
query = (
select(
inserted_image.c.id,
inserted_image.c.message,
inserted_image.c.image_url,
inserted_image.c.chat_id,
inserted_image.c.user_id,
inserted_image.c.created_at,
Users.avatar_image,
Users.username,
MessageAnswer.self_id,
MessageAnswer.answer_id,
)
.select_from(inserted_image)
.join(Users, Users.id == inserted_image.c.user_id)
.join(MessageAnswer, MessageAnswer.self_id == inserted_image.c.id, isouter=True)
)
result = await self.session.execute(query)
await self.session.commit()
result = result.mappings().one()
return SMessage.model_validate(result, from_attributes=True)
result = await self.session.execute(stmt)
return result.scalar()
async def get_message_by_id(self, message_id: int):
query = (
@ -152,36 +131,37 @@ class ChatDAO(BaseDAO):
await self.session.commit()
return True
async def add_answer(self, self_id: int, answer_id: int) -> SMessage:
answer = (
insert(MessageAnswer)
.values(self_id=self_id, answer_id=answer_id)
.returning(MessageAnswer.self_id, MessageAnswer.answer_id)
.cte("answer")
)
async def add_answer(self, self_id: int, answer_id: int | None) -> SMessage:
if answer_id:
stmt = (
insert(MessageAnswer)
.values(self_id=self_id, answer_id=answer_id)
)
await self.session.execute(stmt)
query = (
select(
Message.id,
Message.message,
Message.image_url,
Message.chat_id,
Message.user_id,
Message.created_at,
Users.avatar_image,
Users.username,
answer.c.self_id,
answer.c.answer_id,
func.json_build_object(
"id", Message.id,
"message", Message.message,
"image_url", Message.image_url,
"chat_id", Message.chat_id,
"user_id", Message.user_id,
"created_at", Message.created_at,
"avatar_image", Users.avatar_image,
"username", Users.username,
"answer_id", MessageAnswer.answer_id,
)
.select_from(Message)
.join(Users, Users.id == Message.user_id)
.join(MessageAnswer, MessageAnswer.self_id == Message.id, isouter=True)
.where(Message.id == self_id)
)
.select_from(Message)
.join(Users, Users.id == Message.user_id)
.join(answer, answer.c.self_id == Message.id, isouter=True)
.where(Message.id == self_id)
)
result = await self.session.execute(query)
await self.session.commit()
result = result.mappings().one()
result = result.scalar_one()
logging.critical(result)
return SMessage.model_validate(result)
async def delete_chat(self, chat_id: int) -> bool:

View file

@ -4,7 +4,8 @@ from sqlalchemy.exc import MultipleResultsFound, IntegrityError
from app.dao.base import BaseDAO
from app.database import engine # noqa
from app.exceptions import IncorrectDataException, UserAlreadyExistsException
from app.exceptions import IncorrectDataException
from app.users.exceptions import UserAlreadyExistsException
from app.models.chat import Chats
from app.models.user_avatar import UserAvatar
from app.models.users import Users

View file

@ -9,16 +9,6 @@ class BlackPhoenixException(HTTPException):
super().__init__(status_code=self.status_code, detail=self.detail)
class UserAlreadyExistsException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Пользователь с таким ником или почтой уже существует"
class IncorrectAuthDataException(BlackPhoenixException):
status_code = status.HTTP_401_UNAUTHORIZED
detail = "Введены не верные данные"
class IncorrectTokenFormatException(BlackPhoenixException):
status_code = status.HTTP_401_UNAUTHORIZED
detail = "Некорректный формат токена"
@ -34,50 +24,11 @@ class TokenExpiredException(BlackPhoenixException):
detail = "Токен истёк"
class UserIsNotPresentException(BlackPhoenixException):
status_code = status.HTTP_401_UNAUTHORIZED
class UserDontHavePermissionException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "У вас нет прав для этого действия"
class MessageNotFoundException(BlackPhoenixException):
status_code = status.HTTP_404_NOT_FOUND
detail = "Сообщение не найдено"
class PasswordsMismatchException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Пароли не совпадают"
class UserCanNotReadThisChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер не может читать этот чат"
class WrongCodeException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Введён не верный код подтверждения"
class UserNotFoundException(BlackPhoenixException):
status_code = status.HTTP_404_NOT_FOUND
detail = "Юзер не найден"
class UserAlreadyInChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер уже добавлен в чат"
class UserAlreadyPinnedChatException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Юзер уже закрепил чат"
class UserMustConfirmEmailException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Сначала подтвердите почту"

View file

@ -1,9 +1,6 @@
import logging
from fastapi import FastAPI, Request
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from app.users.router import router as user_router
from app.chat.websocket import router as websocket_router
@ -29,8 +26,6 @@ headers = [
"Access-Control-Allow-Headers",
"Authorization",
"Accept",
"Access-Control-Allow-Origin",
"Sec-WebSocket-Protocol",
]
app.add_middleware(
@ -43,17 +38,3 @@ app.add_middleware(
app.mount("/static", StaticFiles(directory="app/static"), name="static")
class AddHeaderMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
logging.critical(f"Запрос \n{request.headers.get("Sec-Websocket-Protocol", "НИХУЯ")}")
logging.critical(f"Запрос {request.headers}")
logging.critical("Sec-Websocket-Protocol".lower() in request.headers)
response = await call_next(request)
response.headers["Sec-Websocket-Protocol"] = ""
logging.critical(f"Ответ \n {response.headers}")
return response
# app.add_middleware(AddHeaderMiddleware)

View file

@ -1,20 +1,19 @@
from app.chat.shemas import SMessage
from app.chat.shemas import SMessage, SSendMessage
from app.unit_of_work import UnitOfWork
class MessageService:
@staticmethod
async def send_message(
uow: UnitOfWork, user_id: int, chat_id: int, message: str, image_url: str | None = None
uow: UnitOfWork, user_id: int, chat_id: int, message: SSendMessage, image_url: str | None = None
) -> SMessage:
async with uow:
new_message = await uow.chat.send_message(user_id=user_id, chat_id=chat_id, message=message, image_url=image_url)
return new_message
message_id = await uow.chat.send_message(
user_id=user_id, chat_id=chat_id, message=message.message, image_url=image_url
)
new_message = await uow.chat.add_answer(self_id=message_id, answer_id=message.id)
await uow.commit()
@staticmethod
async def add_answer(uow: UnitOfWork, self_id: int, answer_id: int) -> SMessage:
async with uow:
new_message = await uow.chat.add_answer(self_id=self_id, answer_id=answer_id)
return new_message
@staticmethod

View file

@ -1,4 +1,3 @@
import logging
from typing import Annotated
from fastapi import Depends, Header
@ -10,7 +9,7 @@ from app.exceptions import (
IncorrectTokenFormatException,
TokenAbsentException,
TokenExpiredException,
UserIsNotPresentException,
UserNotFoundException,
UserMustConfirmEmailException,
)
from app.services.user_service import UserService
@ -36,11 +35,11 @@ async def get_current_user(token: str = Depends(get_token), uow=Depends(UnitOfWo
user_id: str = payload.get("sub")
if not user_id:
raise UserIsNotPresentException
raise UserNotFoundException
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
if not user:
raise UserIsNotPresentException
raise UserNotFoundException
return user
@ -67,11 +66,11 @@ async def get_current_user_ws(token: str = Depends(get_token_ws), uow=Depends(Un
user_id: str = payload.get("sub")
if not user_id:
raise UserIsNotPresentException
raise UserNotFoundException
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
if not user:
raise UserIsNotPresentException
raise UserNotFoundException
return user

25
app/users/exceptions.py Normal file
View file

@ -0,0 +1,25 @@
from fastapi import status
from app.exceptions import BlackPhoenixException
class UserAlreadyExistsException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Пользователь с таким ником или почтой уже существует"
class IncorrectAuthDataException(BlackPhoenixException):
status_code = status.HTTP_401_UNAUTHORIZED
detail = "Введены не верные данные"
class PasswordsMismatchException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Пароли не совпадают"
class WrongCodeException(BlackPhoenixException):
status_code = status.HTTP_409_CONFLICT
detail = "Введён не верный код подтверждения"

View file

@ -1,15 +1,21 @@
from fastapi import APIRouter, Depends, status
from app.config import settings
from app.exceptions import (
PasswordsMismatchException,
WrongCodeException,
from app.users.exceptions import (
UserAlreadyExistsException,
IncorrectAuthDataException,
PasswordsMismatchException,
WrongCodeException,
)
from app.services.redis_service import RedisService, get_redis_session
from app.unit_of_work import UnitOfWork
from app.utils.auth import get_password_hash, create_access_token, AuthService, verify_password, decode_confirmation_token
from app.utils.auth import (
get_password_hash,
create_access_token,
AuthService,
verify_password,
decode_confirmation_token
)
from app.users.dependencies import get_current_user
from app.users.schemas import (
SUserLogin,
@ -27,7 +33,8 @@ from app.users.schemas import (
)
from app.tasks.tasks import (
send_registration_confirmation_email,
send_data_change_confirmation_email, generate_confirmation_code
send_data_change_confirmation_email,
generate_confirmation_code
)
router = APIRouter(prefix="/users", tags=["Пользователи"])

View file

@ -7,11 +7,11 @@ from pydantic import EmailStr
from app.config import settings
from app.exceptions import (
UserDontHavePermissionException,
IncorrectAuthDataException,
UserNotFoundException,
UserMustConfirmEmailException,
)
from app.users.exceptions import IncorrectAuthDataException
from app.chat.exceptions import UserDontHavePermissionException
from app.unit_of_work import UnitOfWork
from app.users.schemas import SUser, SConfirmationData, SInvitationData

View file

@ -28,7 +28,6 @@ async def prepare_database():
return json.load(file)
users = open_mock_json("users")
users_verification_codes = open_mock_json("verification_codes")
chats = open_mock_json("chats")
users_x_chats = open_mock_json("x_chats")
messages = open_mock_json("messages")
@ -46,7 +45,6 @@ async def prepare_database():
set_verified_user = update(Users).values(role=1).where(Users.id == 3)
await session.execute(add_users)
await session.execute(add_users_verification_codes)
await session.execute(add_chats)
await session.execute(add_users_x_chats)
await session.execute(add_messages)