Почистил код
This commit is contained in:
parent
47ae518794
commit
f4448a5402
8 changed files with 99 additions and 111 deletions
|
@ -29,8 +29,8 @@ router = APIRouter(prefix="/chat", tags=["Чат"])
|
||||||
)
|
)
|
||||||
async def get_all_chats(user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)):
|
async def get_all_chats(user: SUser = Depends(check_verificated_user_with_exc), uow=Depends(UnitOfWork)):
|
||||||
async with uow:
|
async with uow:
|
||||||
result = await uow.user.get_user_allowed_chats(user.id)
|
allowed_chats = await uow.user.get_user_allowed_chats(user.id)
|
||||||
return {"allowed_chats": result}
|
return allowed_chats
|
||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
|
|
|
@ -38,7 +38,7 @@ class SChat(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class SAllowedChats(BaseModel):
|
class SAllowedChats(BaseModel):
|
||||||
allowed_chats: list[SChat | None]
|
allowed_chats: list[SChat] | None
|
||||||
|
|
||||||
|
|
||||||
class SPinnedChats(BaseModel):
|
class SPinnedChats(BaseModel):
|
||||||
|
|
|
@ -95,7 +95,7 @@ class ChatDAO(BaseDAO):
|
||||||
raise MessageNotFoundException
|
raise MessageNotFoundException
|
||||||
|
|
||||||
async def delete_message(self, message_id: int) -> None:
|
async def delete_message(self, message_id: int) -> None:
|
||||||
stmt = update(Message).where(Message.id == message_id).values(visibility=False)
|
stmt = update(Message).values(visibility=False).where(Message.id == message_id)
|
||||||
await self.session.execute(stmt)
|
await self.session.execute(stmt)
|
||||||
|
|
||||||
async def get_some_messages(self, chat_id: int, message_number_from: int, messages_to_get: int) -> SMessageList:
|
async def get_some_messages(self, chat_id: int, message_number_from: int, messages_to_get: int) -> SMessageList:
|
||||||
|
|
137
app/dao/user.py
137
app/dao/user.py
|
@ -1,10 +1,11 @@
|
||||||
from pydantic import HttpUrl
|
from pydantic import HttpUrl
|
||||||
from sqlalchemy import update, select, insert, func
|
from sqlalchemy import update, select, insert, func
|
||||||
from sqlalchemy.exc import MultipleResultsFound, IntegrityError
|
from sqlalchemy.exc import MultipleResultsFound, IntegrityError, NoResultFound
|
||||||
|
|
||||||
|
from app.chat.shemas import SAllowedChats
|
||||||
from app.dao.base import BaseDAO
|
from app.dao.base import BaseDAO
|
||||||
from app.database import engine # noqa
|
from app.database import engine # noqa
|
||||||
from app.exceptions import IncorrectDataException
|
from app.exceptions import IncorrectDataException, UserNotFoundException
|
||||||
from app.users.exceptions import UserAlreadyExistsException
|
from app.users.exceptions import UserAlreadyExistsException
|
||||||
from app.models.chat import Chat
|
from app.models.chat import Chat
|
||||||
from app.models.user_avatar import UserAvatar
|
from app.models.user_avatar import UserAvatar
|
||||||
|
@ -16,96 +17,86 @@ from app.users.schemas import SUser, SUserAvatars, SUsers
|
||||||
class UserDAO(BaseDAO):
|
class UserDAO(BaseDAO):
|
||||||
model = Users
|
model = Users
|
||||||
|
|
||||||
async def add(self, **data) -> int:
|
@staticmethod
|
||||||
|
def check_query_compile(query):
|
||||||
|
print(query.compile(engine, compile_kwargs={"literal_binds": True})) # Проверка SQL запроса
|
||||||
|
|
||||||
|
async def add(self, **data) -> SUser:
|
||||||
try:
|
try:
|
||||||
stmt = insert(self.model).values(**data).returning(Users.id)
|
stmt = insert(self.model).values(**data).returning(Users.__table__.columns)
|
||||||
result = await self.session.execute(stmt)
|
result = await self.session.execute(stmt)
|
||||||
return result.scalar()
|
result = result.mappings().one()
|
||||||
|
return SUser.model_validate(result)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise UserAlreadyExistsException
|
raise UserAlreadyExistsException
|
||||||
|
|
||||||
async def find_one_or_none(self, **filter_by) -> SUser | None:
|
async def find_one_or_none(self, **filter_by) -> SUser:
|
||||||
try:
|
try:
|
||||||
query = select(Users.__table__.columns).filter_by(**filter_by)
|
query = select(Users.__table__.columns).filter_by(**filter_by)
|
||||||
result = await self.session.execute(query)
|
result = await self.session.execute(query)
|
||||||
result = result.mappings().one_or_none()
|
result = result.mappings().one()
|
||||||
if result:
|
return SUser.model_validate(result)
|
||||||
return SUser.model_validate(result)
|
|
||||||
except MultipleResultsFound:
|
except MultipleResultsFound:
|
||||||
raise IncorrectDataException
|
raise IncorrectDataException
|
||||||
|
except NoResultFound:
|
||||||
|
raise UserNotFoundException
|
||||||
|
|
||||||
async def find_all(self) -> SUsers:
|
async def find_all(self) -> SUsers:
|
||||||
query = select(Users.__table__.columns).where(Users.role != 100)
|
|
||||||
result = await self.session.execute(query)
|
|
||||||
return SUsers.model_validate({"users": result.mappings().all()})
|
|
||||||
|
|
||||||
async def change_data(self, user_id: int, **data_to_change) -> str:
|
|
||||||
query = update(Users).where(Users.id == user_id).values(**data_to_change).returning(Users.username)
|
|
||||||
result = await self.session.execute(query)
|
|
||||||
return result.scalar()
|
|
||||||
|
|
||||||
async def get_user_role(self, user_id: int) -> int:
|
|
||||||
query = select(Users.role).where(Users.id == user_id)
|
|
||||||
result = await self.session.execute(query)
|
|
||||||
return result.scalar()
|
|
||||||
|
|
||||||
async def get_user_allowed_chats(self, user_id: int):
|
|
||||||
"""
|
|
||||||
WITH chats_with_descriptions AS (
|
|
||||||
SELECT *
|
|
||||||
FROM usersxchats
|
|
||||||
LEFT JOIN chats ON usersxchats.chat_id = chats.id
|
|
||||||
),
|
|
||||||
|
|
||||||
chats_with_avatars as (
|
|
||||||
SELECT *
|
|
||||||
FROM chats_with_descriptions
|
|
||||||
LEFT JOIN users ON chats_with_descriptions.user_id = users.id
|
|
||||||
)
|
|
||||||
|
|
||||||
SELECT chat_id, chat_for, chat_name, avatar_image
|
|
||||||
FROM chats_with_avatars
|
|
||||||
WHERE user_id = 1
|
|
||||||
"""
|
|
||||||
chats_with_descriptions = (
|
|
||||||
select(UserChat.__table__.columns, Chat.__table__.columns)
|
|
||||||
.select_from(UserChat)
|
|
||||||
.join(Chat, UserChat.chat_id == Chat.id)
|
|
||||||
).cte("chats_with_descriptions")
|
|
||||||
|
|
||||||
chats_with_avatars = (
|
|
||||||
select(
|
|
||||||
chats_with_descriptions.c.chat_id,
|
|
||||||
chats_with_descriptions.c.chat_for,
|
|
||||||
chats_with_descriptions.c.chat_name,
|
|
||||||
chats_with_descriptions.c.visibility,
|
|
||||||
Users.id,
|
|
||||||
Users.avatar_image,
|
|
||||||
)
|
|
||||||
.select_from(chats_with_descriptions)
|
|
||||||
.join(Users, Users.id == chats_with_descriptions.c.user_id)
|
|
||||||
.cte("chats_with_avatars")
|
|
||||||
)
|
|
||||||
query = (
|
query = (
|
||||||
select(
|
select(
|
||||||
chats_with_avatars.c.chat_id,
|
func.json_build_object(
|
||||||
chats_with_avatars.c.chat_for,
|
"users", func.json_agg(
|
||||||
chats_with_avatars.c.chat_name,
|
func.json_build_object(
|
||||||
chats_with_avatars.c.avatar_image,
|
"id", Users.id,
|
||||||
|
"username", Users.username,
|
||||||
|
"email", Users.email,
|
||||||
|
"black_phoenix", Users.black_phoenix,
|
||||||
|
"avatar_image", Users.avatar_image,
|
||||||
|
"date_of_birth", Users.date_of_birth,
|
||||||
|
"date_of_registration", Users.date_of_registration,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.select_from(chats_with_avatars)
|
.select_from(Users)
|
||||||
.where(chats_with_avatars.c.id == user_id, chats_with_avatars.c.visibility == True) # noqa: E712
|
.where(Users.role != 100)
|
||||||
|
)
|
||||||
|
result = await self.session.execute(query)
|
||||||
|
result = result.scalar_one()
|
||||||
|
return SUsers.model_validate(result)
|
||||||
|
|
||||||
|
async def change_data(self, user_id: int, **data_to_change) -> None:
|
||||||
|
stmt = update(Users).where(Users.id == user_id).values(**data_to_change)
|
||||||
|
await self.session.execute(stmt)
|
||||||
|
|
||||||
|
async def get_user_allowed_chats(self, user_id: int) -> SAllowedChats:
|
||||||
|
|
||||||
|
query = (
|
||||||
|
select(
|
||||||
|
func.json_build_object(
|
||||||
|
"allowed_chats", func.json_agg(
|
||||||
|
func.json_build_object(
|
||||||
|
"chat_id", Chat.id,
|
||||||
|
"chat_for", Chat.chat_for,
|
||||||
|
"chat_name", Chat.chat_name,
|
||||||
|
"avatar_image", Users.avatar_image,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.select_from(UserChat)
|
||||||
|
.join(Chat, Chat.id == UserChat.chat_id)
|
||||||
|
.join(Users, Users.id == UserChat.user_id)
|
||||||
|
.where(UserChat.user_id == user_id, Chat.visibility == True) # noqa: E712
|
||||||
)
|
)
|
||||||
|
|
||||||
result = await self.session.execute(query)
|
result = await self.session.execute(query)
|
||||||
result = result.mappings().all()
|
result = result.scalar_one()
|
||||||
return result
|
return SAllowedChats.model_validate(result)
|
||||||
|
|
||||||
async def add_user_avatar(self, user_id: int, avatar: HttpUrl) -> bool:
|
async def add_user_avatar(self, user_id: int, avatar: HttpUrl) -> None:
|
||||||
query = insert(UserAvatar).values(user_id=user_id, avatar_image=avatar)
|
stmt = insert(UserAvatar).values(user_id=user_id, avatar_image=avatar)
|
||||||
await self.session.execute(query)
|
await self.session.execute(stmt)
|
||||||
await self.session.commit()
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def get_user_avatars(self, user_id: int) -> SUserAvatars:
|
async def get_user_avatars(self, user_id: int) -> SUserAvatars:
|
||||||
query = select(
|
query = select(
|
||||||
|
|
|
@ -38,8 +38,6 @@ async def get_current_user(token: str = Depends(get_token), uow=Depends(UnitOfWo
|
||||||
raise UserNotFoundException
|
raise UserNotFoundException
|
||||||
|
|
||||||
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
|
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
|
||||||
if not user:
|
|
||||||
raise UserNotFoundException
|
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@ -69,8 +67,6 @@ async def get_current_user_ws(token: str = Depends(get_token_ws), uow=Depends(Un
|
||||||
raise UserNotFoundException
|
raise UserNotFoundException
|
||||||
|
|
||||||
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
|
user = await UserService.find_one_or_none(uow=uow, user_id=int(user_id))
|
||||||
if not user:
|
|
||||||
raise UserNotFoundException
|
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from fastapi import APIRouter, Depends, status
|
from fastapi import APIRouter, Depends, status
|
||||||
|
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
|
from app.exceptions import UserNotFoundException
|
||||||
from app.users.exceptions import (
|
from app.users.exceptions import (
|
||||||
UserAlreadyExistsException,
|
UserAlreadyExistsException,
|
||||||
IncorrectAuthDataException,
|
IncorrectAuthDataException,
|
||||||
|
@ -58,9 +59,11 @@ async def get_all_users(uow=Depends(UnitOfWork)):
|
||||||
)
|
)
|
||||||
async def check_existing_user(user_filter: SUserFilter, uow=Depends(UnitOfWork)):
|
async def check_existing_user(user_filter: SUserFilter, uow=Depends(UnitOfWork)):
|
||||||
async with uow:
|
async with uow:
|
||||||
user = await uow.user.find_one_or_none(**user_filter.model_dump(exclude_none=True))
|
try:
|
||||||
if user:
|
await uow.user.find_one_or_none(**user_filter.model_dump(exclude_none=True))
|
||||||
raise UserAlreadyExistsException
|
raise UserAlreadyExistsException
|
||||||
|
except UserNotFoundException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@router.post(
|
@router.post(
|
||||||
|
@ -74,22 +77,23 @@ async def register_user(user_data: SUserRegister, uow=Depends(UnitOfWork)):
|
||||||
|
|
||||||
hashed_password = get_password_hash(user_data.password)
|
hashed_password = get_password_hash(user_data.password)
|
||||||
async with uow:
|
async with uow:
|
||||||
user_id = await uow.user.add(
|
user = await uow.user.add(
|
||||||
email=user_data.email,
|
email=user_data.email,
|
||||||
hashed_password=hashed_password,
|
hashed_password=hashed_password,
|
||||||
username=user_data.username,
|
username=user_data.username,
|
||||||
date_of_birth=user_data.date_of_birth,
|
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()
|
await uow.commit()
|
||||||
|
|
||||||
user_code = generate_confirmation_code()
|
user_code = generate_confirmation_code()
|
||||||
user_mail_data = SConfirmationData.model_validate(
|
user_mail_data = SConfirmationData.model_validate(
|
||||||
{"user_id": user_id, "username": user_data.username, "email_to": user_data.email, "confirmation_code": user_code}
|
{"user_id": user.id, "username": user_data.username, "email_to": user_data.email, "confirmation_code": user_code}
|
||||||
)
|
)
|
||||||
send_registration_confirmation_email.delay(user_mail_data.model_dump())
|
send_registration_confirmation_email.delay(user_mail_data.model_dump())
|
||||||
redis_session = get_redis_session()
|
redis_session = get_redis_session()
|
||||||
await RedisService.set_verification_code(redis=redis_session, user_id=user_id, verification_code=user_code)
|
await RedisService.set_verification_code(redis=redis_session, user_id=user.id, verification_code=user_code)
|
||||||
access_token = create_access_token({"sub": str(user_id)})
|
access_token = create_access_token({"sub": str(user.id)})
|
||||||
return {"authorization": f"Bearer {access_token}"}
|
return {"authorization": f"Bearer {access_token}"}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ class SUserRegister(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class SUserResponse(BaseModel):
|
class SUserResponse(BaseModel):
|
||||||
email: EmailStr
|
|
||||||
id: int
|
id: int
|
||||||
username: str
|
username: str
|
||||||
|
email: EmailStr
|
||||||
black_phoenix: bool
|
black_phoenix: bool
|
||||||
avatar_image: HttpUrl
|
avatar_image: HttpUrl
|
||||||
date_of_birth: date
|
date_of_birth: date
|
||||||
|
@ -45,7 +45,7 @@ class SUserResponse(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class SUsers(BaseModel):
|
class SUsers(BaseModel):
|
||||||
users: list[SUserResponse]
|
users: list[SUserResponse] | None
|
||||||
|
|
||||||
|
|
||||||
class SUser(BaseModel):
|
class SUser(BaseModel):
|
||||||
|
|
|
@ -61,19 +61,25 @@ def decode_confirmation_token(invitation_token: str) -> SConfirmationData:
|
||||||
class AuthService:
|
class AuthService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def authenticate_user_by_email(uow: UnitOfWork, email: EmailStr, password: str) -> SUser | None:
|
async def authenticate_user_by_email(uow: UnitOfWork, email: EmailStr, password: str) -> SUser | None:
|
||||||
async with uow:
|
try:
|
||||||
user = await uow.user.find_one_or_none(email=email)
|
async with uow:
|
||||||
if not user or not verify_password(password, user.hashed_password):
|
user = await uow.user.find_one_or_none(email=email)
|
||||||
return None
|
if not verify_password(password, user.hashed_password):
|
||||||
return user
|
return
|
||||||
|
return user
|
||||||
|
except UserNotFoundException:
|
||||||
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def authenticate_user_by_username(uow: UnitOfWork, username: str, password: str) -> SUser | None:
|
async def authenticate_user_by_username(uow: UnitOfWork, username: str, password: str) -> SUser | None:
|
||||||
async with uow:
|
try:
|
||||||
user = await uow.user.find_one_or_none(username=username)
|
async with uow:
|
||||||
if not user or not verify_password(password, user.hashed_password):
|
user = await uow.user.find_one_or_none(username=username)
|
||||||
return None
|
if not verify_password(password, user.hashed_password):
|
||||||
return user
|
return
|
||||||
|
return user
|
||||||
|
except UserNotFoundException:
|
||||||
|
return
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def authenticate_user(cls, uow: UnitOfWork, email_or_username: str, password: str) -> SUser:
|
async def authenticate_user(cls, uow: UnitOfWork, email_or_username: str, password: str) -> SUser:
|
||||||
|
@ -88,20 +94,18 @@ class AuthService:
|
||||||
async def check_verificated_user(uow: UnitOfWork, user_id: int) -> bool:
|
async def check_verificated_user(uow: UnitOfWork, user_id: int) -> bool:
|
||||||
async with uow:
|
async with uow:
|
||||||
user = await uow.user.find_one_or_none(id=user_id)
|
user = await uow.user.find_one_or_none(id=user_id)
|
||||||
if not user:
|
|
||||||
raise UserNotFoundException
|
|
||||||
return user.role >= settings.VERIFICATED_USER
|
return user.role >= settings.VERIFICATED_USER
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_verificated_user_with_exc(cls, uow: UnitOfWork, user_id: int):
|
async def check_verificated_user_with_exc(cls, uow: UnitOfWork, user_id: int) -> None:
|
||||||
if not await cls.check_verificated_user(uow=uow, user_id=user_id):
|
if not await cls.check_verificated_user(uow=uow, user_id=user_id):
|
||||||
raise UserMustConfirmEmailException
|
raise UserMustConfirmEmailException
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_user_allowed_chats_id(uow: UnitOfWork, user_id: int) -> list[int]:
|
async def get_user_allowed_chats_id(uow: UnitOfWork, user_id: int) -> set[int]:
|
||||||
async with uow:
|
async with uow:
|
||||||
user_allowed_chats = await uow.user.get_user_allowed_chats(user_id)
|
user_allowed_chats = await uow.user.get_user_allowed_chats(user_id)
|
||||||
user_allowed_chats_id = [chat["chat_id"] for chat in user_allowed_chats]
|
user_allowed_chats_id = {chat["chat_id"] for chat in user_allowed_chats.allowed_chats}
|
||||||
return user_allowed_chats_id
|
return user_allowed_chats_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -111,10 +115,3 @@ class AuthService:
|
||||||
raise UserDontHavePermissionException
|
raise UserDontHavePermissionException
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def validate_user_admin(uow: UnitOfWork, user_id: int) -> bool:
|
|
||||||
async with uow:
|
|
||||||
user_role = await uow.user.get_user_role(user_id=user_id)
|
|
||||||
if user_role == settings.ADMIN_USER:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue