diff --git a/app/migrations/versions/63ca59918596_добавил_таблицу_аватарок.py b/app/migrations/versions/63ca59918596_добавил_таблицу_аватарок.py new file mode 100644 index 0000000..b2106e3 --- /dev/null +++ b/app/migrations/versions/63ca59918596_добавил_таблицу_аватарок.py @@ -0,0 +1,36 @@ +"""Добавил таблицу аватарок + +Revision ID: 63ca59918596 +Revises: 28850415d498 +Create Date: 2024-03-15 20:21:08.312243 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '63ca59918596' +down_revision: Union[str, None] = '28850415d498' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('usersavatars', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('user_id', sa.Integer(), nullable=False), + sa.Column('avatar', sa.String(), nullable=False), + sa.ForeignKeyConstraint(['user_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('usersavatars') + # ### end Alembic commands ### diff --git a/app/migrations/versions/6df47399c087_изменил_таблицу_аватарок.py b/app/migrations/versions/6df47399c087_изменил_таблицу_аватарок.py new file mode 100644 index 0000000..62be613 --- /dev/null +++ b/app/migrations/versions/6df47399c087_изменил_таблицу_аватарок.py @@ -0,0 +1,32 @@ +"""Изменил таблицу аватарок + +Revision ID: 6df47399c087 +Revises: 63ca59918596 +Create Date: 2024-03-15 20:41:06.180659 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '6df47399c087' +down_revision: Union[str, None] = '63ca59918596' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('usersavatars', sa.Column('avatar_image', sa.String(), nullable=False)) + op.drop_column('usersavatars', 'avatar') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('usersavatars', sa.Column('avatar', sa.VARCHAR(), autoincrement=False, nullable=False)) + op.drop_column('usersavatars', 'avatar_image') + # ### end Alembic commands ### diff --git a/app/users/dao.py b/app/users/dao.py index ba283c7..c8a6c65 100644 --- a/app/users/dao.py +++ b/app/users/dao.py @@ -1,9 +1,11 @@ -from sqlalchemy import update, select, insert, and_, func, text +from typing import Mapping + +from sqlalchemy import update, select, insert, and_, func, text, delete from app.dao.base import BaseDAO -from app.database import async_session_maker, engine # noqa +from app.database import async_session_maker, engine # noqa from app.users.chat.models import UsersXChats, Chats -from app.users.models import Users, UsersVerificationCodes +from app.users.models import Users, UsersVerificationCodes, UsersAvatars class UserDAO(BaseDAO): @@ -16,7 +18,6 @@ class UserDAO(BaseDAO): result = await session.execute(query) return result.mappings().all() - @staticmethod async def change_data(user_id: int, **data_to_change) -> str: query = update(Users).where(Users.id == user_id).values(**data_to_change) @@ -95,6 +96,30 @@ class UserDAO(BaseDAO): result = await session.execute(query) return result.scalar() + @staticmethod + async def add_user_avatar(user_id: int, avatar: str) -> bool: + query = insert(UsersAvatars).values(user_id=user_id, avatar_image=avatar) + async with async_session_maker() as session: + await session.execute(query) + await session.commit() + return True + + @staticmethod + async def get_user_avatars(user_id: int) -> list[Mapping[str, str | int]]: + query = select(UsersAvatars.avatar_image, UsersAvatars.id).where(UsersAvatars.user_id == user_id) + async with async_session_maker() as session: + result = await session.execute(query) + result = result.mappings().all() + return result + + @staticmethod + async def delete_user_avatar(avatar_id: int, user_id: int) -> bool: + query = delete(UsersAvatars).where(and_(UsersAvatars.id == avatar_id, UsersAvatars.user_id == user_id)) + async with async_session_maker() as session: + await session.execute(query) + await session.commit() + return True + class UserCodesDAO(BaseDAO): model = UsersVerificationCodes diff --git a/app/users/models.py b/app/users/models.py index 835727d..bdcdd91 100644 --- a/app/users/models.py +++ b/app/users/models.py @@ -30,6 +30,7 @@ class Users(Base): verificationcode = relationship("UsersVerificationCodes", back_populates="user") pinned_messages = relationship("PinnedMessages", back_populates="user") pinned_chats = relationship("PinnedChats", back_populates="user") + avatars = relationship("UsersAvatars", back_populates="user") def __str__(self): return f"Юзер {self.username}" @@ -48,3 +49,13 @@ class UsersVerificationCodes(Base): def __str__(self): return f"Код {self.code} для юзера {self.user_id}. {self.description}" + + +class UsersAvatars(Base): + __tablename__ = "usersavatars" + + id: Mapped[int] = mapped_column(primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("users.id")) + avatar_image: Mapped[str] + + user = relationship("Users", back_populates="avatars") \ No newline at end of file diff --git a/app/users/router.py b/app/users/router.py index a4b697b..c475658 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -13,7 +13,7 @@ from app.users.dependencies import get_current_user from app.users.models import Users from app.users.schemas import SUserLogin, SUserRegister, SUser, SUserPassword, SUserRename, SUserAvatar, \ SUserPasswordRecover, SUserCode, SUserPasswordChange, SRecoverEmailSent, SUserToken, SEmailVerification, SUserName, \ - SNewAvatar, SConfirmPasswordRecovery, SPasswordRecovered + SNewAvatar, SConfirmPasswordRecovery, SPasswordRecovered, SUserAvatars from app.tasks.tasks import send_registration_confirmation_email, send_password_change_email, \ send_password_recover_email @@ -106,7 +106,7 @@ async def change_avatar(user_data: SUserAvatar, current_user: Users = Depends(ge raise IncorrectPasswordException if await UserDAO.change_data( current_user.id, avatar_image=user_data.new_avatar_image, avatar_hex=user_data.avatar_hex - ): + ) and await UserDAO.add_user_avatar(user_id=current_user.id, avatar=user_data.new_avatar_image): return {'new_avatar_image': user_data.new_avatar_image, 'avatar_hex': user_data.avatar_hex} raise SomethingWentWrongException @@ -160,3 +160,13 @@ async def password_recovery(passwords: SUserPasswordChange): raise UserNotFoundException send_password_change_email.delay(user.username, user.email, MODE=settings.MODE) return {"username": username} + + +@router.get("/avatars", response_model=list[SUserAvatars]) +async def get_user_avatars_history(user: Users = Depends(get_current_user)): + return await UserDAO.get_user_avatars(user_id=user.id) + + +@router.delete("/avatars", response_model=bool) +async def delete_form_user_avatars_history(avatar_id: int, user: Users = Depends(get_current_user)): + return await UserDAO.delete_user_avatar(avatar_id=avatar_id, user_id=user.id) diff --git a/app/users/schemas.py b/app/users/schemas.py index 4003870..2ba25fe 100644 --- a/app/users/schemas.py +++ b/app/users/schemas.py @@ -116,3 +116,10 @@ class SCreateInvitationLink(BaseModel): class SUserAddedToChat(BaseModel): user_added_to_chat: bool + + +class SUserAvatars(BaseModel): + id: int + avatar_image: str + +