diff --git a/back/add_poems_and_filters.py b/back/add_poems_and_filters.py index c29d6c3..9c90f7b 100644 --- a/back/add_poems_and_filters.py +++ b/back/add_poems_and_filters.py @@ -46,7 +46,7 @@ async def add_poems_to_db(async_db: AsyncSession): # close the file f1.close() -async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[Session, Depends(auth_utils.get_session)]): +async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: AsyncSession): """Функция для последовательного применения различных фильтров (через схему SortAnnouncements)""" res = await db.execute(select(orm_models.Announcement)).scalars().all() fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения) @@ -61,7 +61,7 @@ async def filter_ann(schema: pydantic_schemas.SortAnnouncements, db: Annotated[S await res.all() -async def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)], current_date: datetime.date): +async def check_obsolete(db: AsyncSession, current_date: datetime.date): """ Функция участвует в процессе обновления поля obsolete у всех объявлений раз в сутки """ @@ -72,7 +72,7 @@ async def check_obsolete(db: Annotated[Session, Depends(auth_utils.get_session)] # если просрочено if ann.best_by < current_date: ann.obsolete = True - db.commit() - db.refresh(ann) # обновляем состояние объекта + await db.commit() + await db.refresh(ann) # обновляем состояние объекта diff --git a/back/api.py b/back/api.py index e3440e8..6ee2dcf 100644 --- a/back/api.py +++ b/back/api.py @@ -51,7 +51,7 @@ async def announcements_list(db: Annotated[Session, Depends(auth_utils.get_sessi # получаем результат result = await add_poems_and_filters.filter_ann(db=db, schema=params_to_sort) - await result + return result # получаем данные одного объявления @@ -60,11 +60,11 @@ async def single_announcement(ann_id:int, db: Annotated[Session, Depends(auth_ut # Считываем данные из Body и отображаем их на странице. # В последствии будем вставлять данные в html-форму try: - announcement = db.get(orm_models.Announcement, ann_id) + announcement = await db.get(orm_models.Announcement, ann_id) #announcement = await db.execute(select(orm_models.Announcement)).scalars().all() - await announcement + return announcement except: - await {"Answer" : False} #если неуданый доступ, то сообщаем об этом + return {"Answer" : False} #если неуданый доступ, то сообщаем об этом # Занести объявление в базу данных @@ -84,7 +84,7 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( 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: + async with destination.open('wb') as buffer: shutil.copyfileobj(f, buffer) # изменяем название директории загруженного файла @@ -94,12 +94,12 @@ async def put_in_db(name: Annotated[str, Form()], category: Annotated[str, Form( temp_ancmt = orm_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, src=uploaded_name, booked_by=0) - db.add(temp_ancmt) # добавляем в бд - db.commit() # сохраняем изменения - db.refresh(temp_ancmt) # обновляем состояние объекта - await {"Answer" : True} + await db.add(temp_ancmt) # добавляем в бд + await db.commit() # сохраняем изменения + await db.refresh(temp_ancmt) # обновляем состояние объекта + return {"Answer" : True} except: - await {"Answer" : False} + return {"Answer" : False} # Удалить объявления из базы @@ -108,12 +108,13 @@ async def delete_from_db(announcement: pydantic_schemas.DelAnnouncement, db: Ann try: # находим объект с заданным id в бд #to_delete = db.query(orm_models.Announcement).filter(orm_models.Announcement.id==announcement.id).first() - to_delete = await db.execute(select(orm_models.Announcement)).scalars().filter(orm_models.Announcement.id==announcement.id).first() - db.delete(to_delete) # удаление из БД - db.commit() # сохраняем изменения - await {"Answer" : True} + query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id==announcement.id)) + to_delete = query.scalars().first() + await db.delete(to_delete) # удаление из БД + await db.commit() # сохраняем изменения + return {"Answer" : True} except: - await {"Answer" : False} + return {"Answer" : False} # Забронировать объявление @@ -122,7 +123,8 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим объявление по данному id #announcement_to_change = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.id).first() - announcement_to_change = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.id)).scalars().first() + query = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.id)) + announcement_to_change = query.scalars().first() # Проверяем, что объявление с данным id существует if not announcement_to_change: raise HTTPException(status_code=404, detail="Item not found") @@ -133,9 +135,9 @@ async def change_book_status(data: pydantic_schemas.Book, current_user: Annotate # Инкрементируем поле booked_by на 1 announcement_to_change.booked_by += 1 # фиксируем изменения в бд - db.commit() - db.refresh(announcement_to_change) - await {"Success": True} + await db.commit() + await db.refresh(announcement_to_change) + return {"Success": True} # reginstration @@ -145,16 +147,18 @@ async def create_user(nickname: Annotated[str, Form()], password: Annotated[str, # проверяем, что юзера с введенным никнеймом не существует в бд #if db.query(orm_models.User).filter(orm_models.User.nickname == nickname).first() == None: - if await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)).scalars().first() == None: + query_user = await db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) + user_with_entered_nick = query_user.scalars().first() + if user_with_entered_nick == None: # создаем нового юзера new_user = orm_models.User(nickname=nickname, hashed_password=auth_utils.get_password_hash(password), name=name, surname=surname, reg_date=datetime.date.today()) # добавляем в бд - db.add(new_user) - db.commit() - db.refresh(new_user) # обновляем состояние объекта - await {"Success": True} - await {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} + await db.add(new_user) + await db.commit() + await db.refresh(new_user) # обновляем состояние объекта + return {"Success": True} + return {"Success": False, "Message": "Пользователь с таким email уже зарегестрирован"} # функция для генерации токена после успешного входа пользователя @@ -163,7 +167,7 @@ async def login_for_access_token( form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[Session, Depends(auth_utils.get_session)] ): # пробуем найти юзера в бд по введенным паролю и никнейму - user = auth_utils.authenticate_user(db, form_data.username, form_data.password) + user = await auth_utils.authenticate_user(db, form_data.username, form_data.password) # если не нашли - кидаем ошибку if not user: raise HTTPException( @@ -172,18 +176,18 @@ async def login_for_access_token( headers={"WWW-Authenticate": "Bearer"}, ) # задаем временной интервал, в течение которого токен можно использовать - access_token_expires = auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = await auth_utils.timedelta(minutes=auth_utils.ACCESS_TOKEN_EXPIRE_MINUTES) # создаем токен - access_token = auth_utils.create_access_token( + access_token = await auth_utils.create_access_token( data={"user_id": user.id}, expires_delta=access_token_expires ) - await {"access_token":access_token} + return {"access_token":access_token} # получаем данные успешно вошедшего пользователя @app.get("/api/users/me", response_model=pydantic_schemas.User) # async def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_active_user)]): - await current_user + return current_user # изменяем рейтинг пользователя @@ -191,23 +195,23 @@ async def read_users_me(current_user: Annotated[pydantic_schemas.User, Depends(a async def add_points(data: pydantic_schemas.AddRating, current_user: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], db: Annotated[Session, Depends(auth_utils.get_session)]): # проверяем, if current_user.id != data.user_id: - user = auth_utils.get_user_by_id(db, data.user_id) + user = await auth_utils.get_user_by_id(db, data.user_id) if not user: raise HTTPException(status_code=404, detail="Item not found") user.rating = (user.rating*user.num_of_ratings + data.rate)/(user.num_of_ratings + 1) user.num_of_ratings += 1 - db.commit() - db.refresh(user) # обновляем состояние объекта - await {"Success": True} + await db.commit() + await db.refresh(user) # обновляем состояние объекта + return {"Success": True} # получаем рейтинг пользователя @app.get("/api/user/rating") async def add_points(user_id: int, db: Annotated[Session, Depends(auth_utils.get_session)]): - user = auth_utils.get_user_by_id(db, user_id=user_id) + user = await auth_utils.get_user_by_id(db, user_id=user_id) if not user: raise HTTPException(status_code=404, detail="Item not found") - await {"rating": user.rating} + return {"rating": user.rating} # Отправляем стихи @@ -222,10 +226,11 @@ async def poems_to_front(db: Annotated[Session, Depends(auth_utils.get_session)] #num_of_poems = db.query(orm_models.Poems).count() # определяем кол-во стихов в бд rand_id = random.randint(1, num_of_poems) # генерируем номер стихотворения #poem = db.query(orm_models.Poems).filter(orm_models.Poems.id == rand_id).first() # находим стих в бд - poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)).scalars().first() # находим стих в бд + query_poem = await db.execute(select(orm_models.Poems).where(orm_models.Poems.id == rand_id)) # находим стих в бд + poem = query_poem.scalars().first() if not poem: raise HTTPException(status_code=404, detail="Poem not found") - await poem + return poem @app.get("/api/trashbox", response_model=List[pydantic_schemas.TrashboxResponse]) @@ -260,7 +265,7 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к list_of_category = ["Металл", "Бумага", "Стекло", "Иное", "Тетра Пак", "Батарейки", "Крышечки", "Шины", "Опасные отходы", "Лампочки", "Пластик"] # Получение ответа от стороннего апи - response = requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) + response = await requests.post(f"{BASE_URL}/nearest_recycling/get", headers=head, data=my_data, timeout=10) infos = response.json() # Чтение ответа trashboxes = [] @@ -278,8 +283,8 @@ async def get_trashboxes(data: pydantic_schemas.TrashboxRequest = Depends()):#к for a in list_of_category: if a in temp_dict["Categories"] and temp_dict not in trashboxes: trashboxes.append(temp_dict) - uniq_trashboxes = [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])] - await uniq_trashboxes + uniq_trashboxes = await [pydantic_schemas.TrashboxResponse(**ast.literal_eval(el1)) for el1 in set([str(el2) for el2 in trashboxes])] + return uniq_trashboxes @app.get("/{rest_of_path:path}") @@ -291,7 +296,7 @@ async def react_app(req: Request, rest_of_path: str): async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: Annotated[pydantic_schemas.User, Depends(auth_utils.get_current_user)], db: Annotated[Session, Depends(auth_utils.get_session)]): # Находим в бд текущего юзера - current_user = auth_utils.get_user_by_id(db, current_user_schema.id) + current_user = await auth_utils.get_user_by_id(db, current_user_schema.id) # Начисляем баллы пользователю за утилизацию current_user.points += 60 # В полученном json переходим к данным мусорки @@ -300,16 +305,17 @@ async def dispose(data: pydantic_schemas.DisposeRequest, current_user_schema: An new_trashox = orm_models.Trashbox(user_id=current_user.id, date_of_choice=datetime.date.today(), name=data_trashbox.Name, latitude=data_trashbox.Lat, longtitude=data_trashbox.Lng, address=data_trashbox.Address, category=data_trashbox.Category) # добавляем в бд - db.add(new_trashox) + await db.add(new_trashox) # в соответствии с логикой api, после утилизации объявление пользователя удаляется # находим объявление с айди data.ann_id - #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # находим стих в бд - ann_to_del = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.ann_id)).scalars().first() # находим стих в бд + #ann_to_del = db.query(orm_models.Announcement).filter(orm_models.Announcement.id == data.ann_id).first() # + query_ann = await db.execute(select(orm_models.Announcement).where(orm_models.Announcement.id == data.ann_id)) # находим объявление в бд + ann_to_del = query_ann.scalars().first() if not ann_to_del: raise HTTPException(status_code=404, detail="Announcement not found") # удаляем объявление из бд - db.delete(ann_to_del) - db.commit() - db.refresh(new_trashox) # обновляем состояние объекта - await {"Success": True} + await db.delete(ann_to_del) + await db.commit() + await db.refresh(new_trashox) # обновляем состояние объекта + return {"Success": True} diff --git a/back/auth_utils.py b/back/auth_utils.py index bf5d95e..e7678f8 100644 --- a/back/auth_utils.py +++ b/back/auth_utils.py @@ -36,21 +36,23 @@ async def get_password_hash(password): async def get_user_by_nickname(db: Annotated[AsyncSession, Depends(get_session)], nickname: str): - user_with_required_id = db.select(orm_models.User).where(orm_models.User.nickname == nickname).first() - if user_with_required_id: - return user_with_required_id + query = db.execute(select(orm_models.User).where(orm_models.User.nickname == nickname)) + user_with_required_nickname = query.scalars().first() + if user_with_required_nickname: + return user_with_required_nickname return None async def get_user_by_id(db: Annotated[AsyncSession, Depends(get_session)], user_id: int): - user_with_required_id = db.select(orm_models.User).where(orm_models.User.id == user_id).first() + query = db.execute(select(orm_models.User).where(orm_models.User.id == user_id)) + user_with_required_id = query.scalars().first() if user_with_required_id: return user_with_required_id return None async def authenticate_user(db: Annotated[AsyncSession, Depends(get_session)], nickname: str, password: str): - user = get_user_by_nickname(db=db, nickname=nickname) + user = await get_user_by_nickname(db=db, nickname=nickname) if not user: return False if not verify_password(password, user.hashed_password): @@ -65,7 +67,7 @@ async def create_access_token(data: dict, expires_delta: Union[timedelta, None] else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + encoded_jwt = await jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt @@ -76,14 +78,14 @@ async def get_current_user(db: Annotated[AsyncSession, Depends(get_session)], to headers={"WWW-Authenticate": "Bearer"}, ) try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - user_id: int = payload.get("user_id") + payload = await jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + user_id: int = await payload.get("user_id") if user_id is None: raise credentials_exception token_data = pydantic_schemas.TokenData(user_id=user_id) except JWTError: raise credentials_exception - user = get_user_by_id(db, user_id=token_data.user_id) + user = await get_user_by_id(db, user_id=token_data.user_id) if user is None: raise credentials_exception return pydantic_schemas.User(id=user.id, nickname=user.nickname, name=user.name, surname=user.surname, diff --git a/back/db.py b/back/db.py index 5840936..c76508f 100644 --- a/back/db.py +++ b/back/db.py @@ -4,12 +4,13 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base -SQLALCHEMY_DATABASE_URL = "sqlite+aiosqlite:///./sql_app.db" +SQLALCHEMY_DATABASE_URL = "postgresql+asyncpg://postgres:D560c34V112Ak@localhost/porridger" engine = create_async_engine(SQLALCHEMY_DATABASE_URL, echo=True) SessionLocal = sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False) -async_session = async_scoped_session(SessionLocal, scopefunc=current_task) +async_session = SessionLocal() +# async_session = async_scoped_session(SessionLocal, scopefunc=current_task) Base = declarative_base() diff --git a/back/scheduler.py b/back/scheduler.py index 0ec340d..cd44620 100644 --- a/back/scheduler.py +++ b/back/scheduler.py @@ -2,7 +2,7 @@ from . import add_poems_and_filters from rocketry import Rocketry from rocketry.conds import daily import datetime -from .db import database +from .db import async_session app = Rocketry(execution="async") @@ -10,5 +10,5 @@ app = Rocketry(execution="async") @app.task('minutely') async def daily_check(): # Фильтруем по сроку годности - add_poems_and_filters.check_obsolete(database, current_date=datetime.date.today()) + await add_poems_and_filters.check_obsolete(async_session, current_date=datetime.date.today())