diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index 6098811..778be7b 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -57,39 +57,6 @@ async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSessio filter_query = await db.execute(select(orm_models.Announcement).where(literal_column(f"announcements.{name}") == filt_val)) filtered = set(filter_query.scalars().all()) res = res.intersection(filtered) - # # отфильтровываем подходящие объявления - # res = await db.execute( - # select(orm_models.Announcement).where( - # ((schema.obsolete == None) | ((schema.obsolete != None) & (orm_models.Announcement.obsolete == schema.obsolete))) - # & ((schema.user_id == None) | ((schema.user_id != None) & (orm_models.Announcement.user_id == schema.user_id))) - # & ((schema.metro == None) | ((schema.metro != None) & (orm_models.Announcement.metro == schema.metro))) - # & ((schema.category == None) | ((schema.category != None) & (orm_models.Announcement.category == schema.category))) - # ) - # ) - - - # .where(schema.user_id != None and orm_models.Announcement.user_id == schema.user_id) - # .where(schema.metro != None and orm_models.Announcement.metro == schema.metro) - # .where(schema.category != None and orm_models.Announcement.category == schema.category) - # statement = text("SELECT * FROM announcements " - # "WHERE announcements.obsolete = :obsolete " - # "INTERSECT" - # "SELECT * FROM announcements " - # "WHERE announcements.user_id == :user_id " - # "INTERSECT" - # "SELECT * FROM announcements " - # "WHERE announcements.metro == :metro " - # "INTERSECT" - # "SELECT * FROM announcements " - # "WHERE announcements.category == :category") - - # res = await db.execute(statement, - # {"obsolete": schema.obsolete, - # "user_id": schema.user_id, - # "metro": schema.metro, - # "category": schema.category} - # ) - # возвращаем все подходящие объявления return res diff --git a/back/api.py b/back/api.py index 7a3a47e..00c9887 100644 --- a/back/api.py +++ b/back/api.py @@ -43,33 +43,66 @@ if not os.path.exists("./uploads"): # создаем эндпоинт для хранения файлов пользователя app.mount("/uploads", StaticFiles(directory = "./uploads")) + # эндпоинт для возвращения согласия в pdf @app.get("/privacy_policy.pdf") async def privacy_policy(): return FileResponse("./privacy_policy.pdf") + # получение списка объявлений -@app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement])#адрес объявлений -async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_session)], obsolete: Union[bool, None] = False, user_id: Union[int, None] = None, - metro: Union[str, None] = None,category: Union[str, None] = None): +@app.get("/api/announcements", response_model=List[pydantic_schemas.Announcement]) +async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_session)], + current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)], + obsolete: Union[bool, None] = False, user_id: Union[int, None] = None, metro: Union[str, None] = None, + category: Union[str, None] = None): # параметры для сортировки (схема pydantic schemas.SortAnnouncements) params_to_sort = pydantic_schemas.SortAnnouncements(obsolete=obsolete, user_id=user_id, metro=metro, category=category) - # получаем результат + # получаем результат (значения с определенными полями obsolete, user_id, metro, category). + # user_id - id пользователя, которому принадлежат объявления result = await add_poems_and_filters.filter_ann(db=db, schema=params_to_sort) - return result + # для каждого отфильтрованного объявления проверяем, забронировано ли оно текущим пользователем и в зависимости + # от этого флаг booked_by_current_user устанавливаем в 0 или в 1 + check_if_booked = [pydantic_schemas.Announcement.from_orm(elem) for elem in result] + for an in check_if_booked: + # ищем пару с заданными id объявления и id текущего пользователя + query = await db.execute(select(orm_models.AnnouncementUser).where( + orm_models.AnnouncementUser.announcement_id == an.id).where( + orm_models.AnnouncementUser.booking_user_id == current_user.id)) + pair_found = query.scalars().first() + + if pair_found: + an.booked_by_current_user = True + else: + an.booked_by_current_user = False + + return check_if_booked # получаем данные одного объявления @app.get("/api/announcement", response_model=pydantic_schemas.AnnResponce) -async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_session)]): # передаем индекс обявления +async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_utils.get_session)], + current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)]): # Считываем данные из Body и отображаем их на странице. # В последствии будем вставлять данные в html-форму announcement = await db.get(orm_models.Announcement, ann_id) #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() if not announcement: raise HTTPException(status_code=404, detail="Item not found") - return announcement + + # создаем форму pydantic_schemas.AnnResponce из ORM-объекта announcement + announcement_model = pydantic_schemas.AnnResponce.from_orm(announcement) + + # ищем пару с заданными id объявления и id текущего пользователя + query = await db.execute(select(orm_models.AnnouncementUser).where( + orm_models.AnnouncementUser.announcement_id == announcement.id).where( + orm_models.AnnouncementUser.booking_user_id == current_user.id)) + pair_found = query.scalars().first() + # если такая пара найдена, записываем в поле booked_by_current_user True + if pair_found: + announcement_model.booked_by_current_user = True + return announcement_model # Занести объявление в базу данных @@ -153,7 +186,7 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate new_pair = orm_models.AnnouncementUser(announcement_to_change.id, current_user.id) # Инкрементируем поле booked_counter на 1 announcement_to_change.booked_counter += 1 - # вставляем индекс забронировавшего пользователя в поле booked_by + # добавляем запись в таблицу announcementuser db.add(new_pair) # фиксируем изменения в бд diff --git a/back/orm_models.py b/back/orm_models.py index 68ec5bd..93abc8f 100644 --- a/back/orm_models.py +++ b/back/orm_models.py @@ -37,17 +37,11 @@ class Announcement(Base): #класс объявления src = Column(String, nullable=True) #изображение продукта в объявлении metro = Column(String) #ближайщее метро от адреса нахождения продукта trashId = Column(Integer, nullable=True) - booked_by = Column(Integer, nullable=True) # id пользователя, забронировавшего объявление booked_counter = Column(Integer, nullable=True) #количество забронировавших (0 - никто не забронировал) obsolete = Column(Boolean, default=False) # состояние объявления (по-умолчанию считаем его актуальным) user = relationship("User", secondary="announcementuser", back_populates="announcements") -# Класс пары, хранящей id объявления и id забронировавшего юзера -@dataclasses.dataclass -class UserAnouncementPair: - announcement_id: int - booking_user_id: int class AnnouncementUser(Base): __tablename__ = "announcementuser" @@ -61,11 +55,17 @@ class AnnouncementUser(Base): -# class Ratings(Base): -# __tablename__ = "ratings" +class Ratings(Base): + __tablename__ = "ratings" -# rated_user_id = Column(Integer, primary_key=True) # id пользователя, оставившего оценку -# rating_value = Column(Integer, primary_key=True) # оценка + def __init__(self, rated_user_id, user_giving_rating_id, rating_val): + self.rated_user_id = rated_user_id + self.user_giving_rating_id = user_giving_rating_id + self.rating_value = rating_val + + rated_user_id = Column(Integer, ForeignKey("users.id"), primary_key=True) # id пользователя, оставившего оценку + user_giving_rating_id = Column(Integer, ForeignKey("users.id"), primary_key=True) # id оцениваемого пользователя + rating_value = Column(Integer, primary_key=True) # оценка class Trashbox(Base): #класс мусорных баков diff --git a/back/pydantic_schemas.py b/back/pydantic_schemas.py index 0562cf1..a2ad6f7 100644 --- a/back/pydantic_schemas.py +++ b/back/pydantic_schemas.py @@ -1,8 +1,7 @@ from pydantic import BaseModel -from typing import Annotated, Union +from typing import Union from datetime import date from typing import List -from fastapi import UploadFile, Form class Book(BaseModel): id: int @@ -28,7 +27,7 @@ class Announcement(BaseModel): src: Union[str, None] = None #изображение продукта в объявлении metro: str #ближайщее метро от адреса нахождения продукта trashId: Union[int, None] = None - booked_by: Union[int, None] = 0 #статус бронирования (либо 0, либо айди бронирующего) + booked_by_current_user: Union[bool, None] = False obsolete: bool class Config: @@ -50,7 +49,7 @@ class AnnResponce(BaseModel): src: Union[str, None] = None #изображение продукта в объявлении metro: str #ближайщее метро от адреса нахождения продукта trashId: Union[int, None] = None - booked_by: Union[int, None] = 0 #статус бронирования (либо 0, либо айди бронирующего) + booked_by_current_user: Union[bool, None] = False class Config: orm_mode = True diff --git a/migrations/versions/a309e6ee6307_many_to_many_relationship_rating_added.py b/migrations/versions/a309e6ee6307_many_to_many_relationship_rating_added.py new file mode 100644 index 0000000..67a8e14 --- /dev/null +++ b/migrations/versions/a309e6ee6307_many_to_many_relationship_rating_added.py @@ -0,0 +1,37 @@ +"""Many to many relationship Rating added + +Revision ID: a309e6ee6307 +Revises: cf0525fd49a8 +Create Date: 2024-08-28 22:08:08.399530 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'a309e6ee6307' +down_revision: Union[str, None] = 'cf0525fd49a8' +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('ratings', + sa.Column('rated_user_id', sa.Integer(), nullable=False), + sa.Column('user_giving_rating_id', sa.Integer(), nullable=False), + sa.Column('rating_value', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['rated_user_id'], ['users.id'], ), + sa.ForeignKeyConstraint(['user_giving_rating_id'], ['users.id'], ), + sa.PrimaryKeyConstraint('rated_user_id', 'user_giving_rating_id', 'rating_value') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('ratings') + # ### end Alembic commands ### diff --git a/migrations/versions/cf0525fd49a8_booked_by_column_removed_in_.py b/migrations/versions/cf0525fd49a8_booked_by_column_removed_in_.py new file mode 100644 index 0000000..31a5047 --- /dev/null +++ b/migrations/versions/cf0525fd49a8_booked_by_column_removed_in_.py @@ -0,0 +1,30 @@ +"""booked_by column removed in Announcements table + +Revision ID: cf0525fd49a8 +Revises: 19dbd9793f11 +Create Date: 2024-08-28 21:59:23.787732 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'cf0525fd49a8' +down_revision: Union[str, None] = '19dbd9793f11' +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.drop_column('announcements', 'booked_by') + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('announcements', sa.Column('booked_by', sa.INTEGER(), autoincrement=False, nullable=True)) + # ### end Alembic commands ###