From 832a2ce9854dee35bac17ddf9897a7c23303a8d3 Mon Sep 17 00:00:00 2001 From: DmitryGantimurov Date: Tue, 8 Aug 2023 01:22:47 +0300 Subject: [PATCH] Auth works again; relationships between Trashbox and User added --- back/main.py | 46 +++++++++---------- back/models.py | 17 +++---- back/schemas.py | 20 ++++++-- back/utils.py | 19 +++++--- ...290a82b821_email_nickname_in_user_model.py | 34 ++++++++++++++ ...created_relationships_between_trashbox_.py | 28 +++++++++++ ...created_relationships_between_trashbox_.py | 28 +++++++++++ ...created_relationships_between_trashbox_.py | 36 +++++++++++++++ 8 files changed, 185 insertions(+), 43 deletions(-) create mode 100644 migrations/versions/58290a82b821_email_nickname_in_user_model.py create mode 100644 migrations/versions/96470e6327e0_created_relationships_between_trashbox_.py create mode 100644 migrations/versions/b806af0cc2cb_created_relationships_between_trashbox_.py create mode 100644 migrations/versions/ee035dd94fbb_created_relationships_between_trashbox_.py diff --git a/back/main.py b/back/main.py index e211fe3..1659486 100644 --- a/back/main.py +++ b/back/main.py @@ -77,31 +77,30 @@ def single_annoncement(user_id:int): # Занести объявление в базу данных @app.put("/api/announcement")#адрес объявлений def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form()], bestBy: Annotated[datetime.date, Form()], -address: Annotated[str, Form()], longtitude: Annotated[float, Form()], latitude: Annotated[float, Form()], -description: Annotated[str, Form()], src: UploadFile, metro: Annotated[str, Form()], -trashId: Annotated[int, Form()] = None): - # try: - userId = 1 # temporary - + address: Annotated[str, Form()], longtitude: Annotated[float, Form()], latitude: Annotated[float, Form()], + description: Annotated[str, Form()], metro: Annotated[str, Form()], current_user: Annotated[schemas.User, Depends(utils.get_current_active_user)], + src: Union[UploadFile, None] = None, trashId: Annotated[int, Form()] = None): + try: uploaded_name = "" + if src: + f = src.file + f.seek(0, os.SEEK_END) + if f.tell() > 0: + f.seek(0) + destination = pathlib.Path("./uploads/" + str(hash(f)) + pathlib.Path(src.filename).suffix.lower()) + with destination.open('wb') as buffer: + shutil.copyfileobj(f, buffer) - f = src.file - f.seek(0, os.SEEK_END) - if f.tell() > 0: - f.seek(0) - destination = pathlib.Path("./uploads/" + str(hash(src.file)) + pathlib.Path(src.filename).suffix.lower()) - with destination.open('wb') as buffer: - shutil.copyfileobj(src.file, buffer) + uploaded_name = "/uploads/"+destination.name - uploaded_name = "/uploads/"+destination.name - - temp_ancmt = models.Announcement(user_id=userId, name=name, category=category, best_by=bestBy, address=address, longtitude=longtitude, latitude=latitude, description=description, src=uploaded_name, metro=metro, trashId=trashId, booked_by=-1) + temp_ancmt = models.Announcement(user_id=current_user.id, name=name, category=category, best_by=bestBy, + address=address, longtitude=longtitude, latitude=latitude, description=description, metro=metro, trashId=trashId) database.add(temp_ancmt) # добавляем в бд database.commit() # сохраняем изменения database.refresh(temp_ancmt) # обновляем состояние объекта return {"Answer" : True} - # except: - # return {"Answer" : False} + except: + return {"Answer" : False} # Удалить объявления из базы @@ -130,12 +129,13 @@ def change_book_status(data: schemas.Book): # reginstration -# {"id":1, "email":"poopka@mail.ru", "password":"good", "name":"Vasya", "surname":"Poopkin"} @app.post("/api/signup") -def create_user(data = Body()): - if database.query(models.User).filter(models.User.email == data["email"]).first() == None: - new_user = models.User(email=data["email"], hashed_password=get_password_hash(data["password"]), - name=data["name"], surname=data["surname"]) +def create_user(nickname: Annotated[str, Form()], password: Annotated[str, Form()], name: Annotated[str, Form()]=None, + surname: Annotated[str, Form()]=None, avatar: Annotated[UploadFile, Form()]=None): + + if database.query(models.User).filter(models.User.nickname == nickname).first() == None: + new_user = models.User(nickname=nickname, hashed_password=utils.get_password_hash(password), + name=name, surname=surname) database.add(new_user) database.commit() database.refresh(new_user) # обновляем состояние объекта diff --git a/back/models.py b/back/models.py index 623f7ea..a5f2282 100644 --- a/back/models.py +++ b/back/models.py @@ -4,21 +4,11 @@ from .db import Base, engine from sqlalchemy.orm import relationship -# импортируем модуль для создания перечислений -import enum - -# # класс, необходимый для создания перечисления -# class State(enum.Enum): -# published = 1 -# taken = 2 -# obsolete = 3 - - class User(Base):#класс пользователя __tablename__ = "users" id = Column(Integer, primary_key=True, index=True, unique=True)#айди пользователя - email = Column(String)#электронная почта пользователя + nickname = Column(String) # никнейм пользователя hashed_password = Column(String) name = Column(String, nullable=True)#имя пользователя surname = Column(String)#фамилия пользователя @@ -28,6 +18,7 @@ class User(Base):#класс пользователя reg_date = Column(Date) # дата регистрации announcements = relationship("Announcement", back_populates="user") + trashboxes_chosen = relationship("Trashbox", back_populates="user") class Announcement(Base): #класс объявления __tablename__ = "announcements" @@ -55,11 +46,15 @@ class Trashbox(Base): #класс мусорных баков __tablename__ = "trashboxes" id = Column(Integer, primary_key=True, index=True)#айди + user_id = Column(Integer, ForeignKey("users.id")) # айди выбравшего мусорку name = Column(String, nullable=True)#имя пользователя address = Column(String) latitude = Column(Integer) longtitude = Column(Integer) category = Column(String) #категория продукта из объявления + date_of_chose = Column(Date) # Дата выбора мусорки пользователем + + user = relationship("User", back_populates="trashboxes_chosen") class Poems(Base):#класс поэзии diff --git a/back/schemas.py b/back/schemas.py index 25ebc85..7fa74ff 100644 --- a/back/schemas.py +++ b/back/schemas.py @@ -2,6 +2,7 @@ from pydantic import BaseModel from typing import Annotated, Union from datetime import date from typing import List +from fastapi import UploadFile, Form class Book(BaseModel): id: int @@ -21,15 +22,28 @@ class Announcement(BaseModel): longtitude: float latitude: float description: str + # src: Union[UploadFile, None] = None #изображение продукта в объявлении src: Union[str, None] = None #изображение продукта в объявлении metro: str #ближайщее метро от адреса нахождения продукта trashId: Union[int, None] = None - booked_by: int #статус бронирования (либо -1, либо айди бронирующего) + booked_by: Union[int, None] = 0 #статус бронирования (либо 0, либо айди бронирующего) class Config: orm_mode = True arbitrary_types_allowed=True + +class PutAnnInDB(BaseModel): + name: Annotated[str, Form()] + category: Annotated[str, Form()] + best_by: Annotated[date, Form()] + address: Annotated[str, Form()] + longtitude: Annotated[float, Form()] + latitude: Annotated[float, Form()] + description: Annotated[str, Form()] + src: Annotated[Union[UploadFile, None], Form()] = None #изображение продукта в объявлении + metro: Annotated[str, Form()] #ближайщее метро от адреса нахождения продукта + class Token(BaseModel): access_token: str @@ -42,9 +56,9 @@ class TokenData(BaseModel): class User(BaseModel): id: int - email: str + nickname: str name: Union[str, None] = None - surname: str + surname: Union[str, None] = None disabled: Union[bool, None] = False items: list[Announcement] = [] diff --git a/back/utils.py b/back/utils.py index 51dbac9..56ad795 100644 --- a/back/utils.py +++ b/back/utils.py @@ -17,7 +17,7 @@ SECRET_KEY = "SECRET" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/token") def get_db(): @@ -36,15 +36,22 @@ def get_password_hash(password): return pwd_context.hash(password) -def get_user(db: Annotated[Session, Depends(get_db)], user_id: int): +def get_user_by_nickname(db: Annotated[Session, Depends(get_db)], nickname: str): + user_with_required_id = db.query(models.User).filter(models.User.nickname == nickname).first() + if user_with_required_id: + return user_with_required_id + return None + + +def get_user_by_id(db: Annotated[Session, Depends(get_db)], user_id: int): user_with_required_id = db.query(models.User).filter(models.User.id == user_id).first() if user_with_required_id: return user_with_required_id return None -def authenticate_user(db: Annotated[Session, Depends(get_db)], email: str, password: str): - user = get_user(user_id = user_id) +def authenticate_user(db: Annotated[Session, Depends(get_db)], nickname: str, password: str): + user = get_user_by_nickname(db=db, nickname=nickname) if not user: return False if not verify_password(password, user.hashed_password): @@ -77,10 +84,10 @@ async def get_current_user(db: Annotated[Session, Depends(get_db)], token: Annot token_data = schemas.TokenData(user_id=user_id) except JWTError: raise credentials_exception - user = get_user(db, user_id=token_data.user_id) + user = get_user_by_id(db, user_id=token_data.user_id) if user is None: raise credentials_exception - return schemas.User(id=user.id, email=user.email, name=user.name, surname=user.surname, disabled=user.disabled, items=user.items) + return schemas.User(id=user.id, nickname=user.nickname, name=user.name, surname=user.surname, disabled=user.disabled, items=user.announcements) async def get_current_active_user( diff --git a/migrations/versions/58290a82b821_email_nickname_in_user_model.py b/migrations/versions/58290a82b821_email_nickname_in_user_model.py new file mode 100644 index 0000000..c36fa62 --- /dev/null +++ b/migrations/versions/58290a82b821_email_nickname_in_user_model.py @@ -0,0 +1,34 @@ +"""email->nickname in User model + +Revision ID: 58290a82b821 +Revises: 9c19b9658512 +Create Date: 2023-08-07 23:37:58.017279 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '58290a82b821' +down_revision = '9c19b9658512' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.add_column(sa.Column('nickname', sa.String(), nullable=True)) + batch_op.drop_column('email') + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('users', schema=None) as batch_op: + batch_op.add_column(sa.Column('email', sa.VARCHAR(), nullable=True)) + batch_op.drop_column('nickname') + + # ### end Alembic commands ### diff --git a/migrations/versions/96470e6327e0_created_relationships_between_trashbox_.py b/migrations/versions/96470e6327e0_created_relationships_between_trashbox_.py new file mode 100644 index 0000000..548dc1b --- /dev/null +++ b/migrations/versions/96470e6327e0_created_relationships_between_trashbox_.py @@ -0,0 +1,28 @@ +"""created relationships between Trashbox and User + +Revision ID: 96470e6327e0 +Revises: b806af0cc2cb +Create Date: 2023-08-08 00:06:18.745504 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '96470e6327e0' +down_revision = 'b806af0cc2cb' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### diff --git a/migrations/versions/b806af0cc2cb_created_relationships_between_trashbox_.py b/migrations/versions/b806af0cc2cb_created_relationships_between_trashbox_.py new file mode 100644 index 0000000..0113aa9 --- /dev/null +++ b/migrations/versions/b806af0cc2cb_created_relationships_between_trashbox_.py @@ -0,0 +1,28 @@ +"""created relationships between Trashbox and User + +Revision ID: b806af0cc2cb +Revises: 58290a82b821 +Create Date: 2023-08-08 00:05:55.175838 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b806af0cc2cb' +down_revision = '58290a82b821' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + pass + # ### end Alembic commands ### diff --git a/migrations/versions/ee035dd94fbb_created_relationships_between_trashbox_.py b/migrations/versions/ee035dd94fbb_created_relationships_between_trashbox_.py new file mode 100644 index 0000000..617186e --- /dev/null +++ b/migrations/versions/ee035dd94fbb_created_relationships_between_trashbox_.py @@ -0,0 +1,36 @@ +"""created relationships between Trashbox and User; (foreign key added to Trashbox table) + +Revision ID: ee035dd94fbb +Revises: 96470e6327e0 +Create Date: 2023-08-08 00:11:35.443724 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ee035dd94fbb' +down_revision = '96470e6327e0' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('trashboxes', schema=None) as batch_op: + batch_op.add_column(sa.Column('user_id', sa.Integer(), nullable=True)) + batch_op.add_column(sa.Column('date_of_chose', sa.Date(), nullable=True)) + # batch_op.create_foreign_key(None, 'users', ['user_id'], ['id']) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('trashboxes', schema=None) as batch_op: + # batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_column('date_of_chose') + batch_op.drop_column('user_id') + + # ### end Alembic commands ###