rating routes added

This commit is contained in:
DmitryGantimurov 2023-08-06 23:59:33 +03:00
parent cc414e38bd
commit 5fcee1157e
10 changed files with 223 additions and 59 deletions

View File

@ -1,8 +1,8 @@
from typing import AsyncGenerator
from sqlalchemy import create_engine, select
from sqlalchemy import create_engine, select, MetaData
# from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.orm import sessionmaker, Session, DeclarativeBase
from sqlalchemy.ext.declarative import declarative_base
from fastapi import Depends
@ -18,4 +18,18 @@ engine = create_engine(
SessionLocal = sessionmaker(bind=engine, autoflush=True, autocommit=False)
database = SessionLocal()
Base = declarative_base()
# Base = declarative_base()
# add your model's MetaData object here
# for 'autogenerate' support
# in your application's model:
class Base(DeclarativeBase):
metadata = MetaData(naming_convention={
"ix": "ix_%(column_0_label)s",
"uq": "uq_%(table_name)s_%(column_0_name)s",
"ck": "ck_%(table_name)s_`%(constraint_name)s`",
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
"pk": "pk_%(table_name)s"
})

View File

@ -2,4 +2,5 @@ from sqlalchemy import Table, MetaData
from .db import engine
tbl = Table('UserDatabase', MetaData(), autoload_with=engine)
tbl.drop(engine, checkfirst=False)
tbl.drop(engine, checkfirst=False)
a = input()

View File

@ -19,7 +19,7 @@ import shutil
import os
from .db import Base, engine, SessionLocal, database
from .service import add_poems_to_db, generate_poem
from .service import add_poems_to_db, generate_poem, check_obsolete
from . import schemas, models, utils
Base.metadata.create_all(bind=engine)
@ -36,32 +36,37 @@ app.mount("/uploads", StaticFiles(directory = "./uploads"))
# # Записываем стихи в базу данных, если их еще нет (запускать только если стихов в базе нет).
# add_poems_to_db(database)
@app.get("/api/announcements")#адрес объявлений
def annoncements_list(owner_id: int = None, metro: str = None, category: str = None, booked_by: int = 0):
@app.get("/api/announcements", response_model=List[schemas.Announcement]) #адрес объявлений
def annoncements_list(params_to_sort: schemas.SortAnnouncements):
# Считываем данные из Body и отображаем их на странице.
# В последствии будем вставлять данные в html-форму
a = database.query(models.Announcement)
b = database.query(models.Announcement)
c = database.query(models.Announcement)
d = database.query(models.Announcement)
e = database.query(models.Announcement)
# Фильтруем по сроку годности
not_expired = check_obsolete(current_date=datetime.date.today())
# Фильтруем по другим параметрам и делаем пересечение с not_expired
result = not_expired.intersect(get_query_results(params_to_sort))
if owner_id != None:
b = a.filter(models.Announcement.owner_id == owner_id)
if metro != None:
c = a.filter(models.Announcement.metro == metro)
# a = database.query(models.Announcement)
# b = database.query(models.Announcement)
# c = database.query(models.Announcement)
# d = database.query(models.Announcement)
# e = database.query(models.Announcement)
if category != None:
d = a.filter(models.Announcement.category == category)
# if owner_id != None:
# b = a.filter(models.Announcement.owner_id == owner_id)
if not any([category, owner_id, metro]) and booked_by == -1:
result = a.all()
# if metro != None:
# c = a.filter(models.Announcement.metro == metro)
# if category != None:
# d = a.filter(models.Announcement.category == category)
# if not any([category, owner_id, metro]) and booked_by == 0:
# result = a.all()
else:
result = b.intersect(c, d, e).all()
# else:
# result = b.intersect(c, d, e).all()
return {"Success" : True, "list_of_announcements": result, "poem": generate_poem(database)}
@ -179,6 +184,25 @@ async def read_own_items(
return [{"Current user name": current_user.name, "Current user surname": current_user.surname}]
# начисляем баллы пользователю
@app.post("/api/user/rating")
def add_points(data: schemas.AddPoints):
user = utils.get_user(data.user_id)
if not user:
raise HTTPException(status_code=404, detail="Item not found")
user.rating += data.rate
return {"Success": True}
# получаем данные о баллах пользователя
@app.get("/api/user/rating")
def add_points(user_id: int):
user = utils.get_user(user_id)
if not user:
raise HTTPException(status_code=404, detail="Item not found")
return {"rating": user.rating}
@app.get("/api/trashbox", response_model=List[schemas.TrashboxResponse])
def get_trashboxes(lat:float, lng:float):#крутая функция для работы с api
BASE_URL='https://geointelect2.gate.petersburg.ru'#адрес сайта и мой токин
@ -214,3 +238,8 @@ def get_trashboxes(lat:float, lng:float):#крутая функция для р
@app.get("/{rest_of_path:path}")
async def react_app(req: Request, rest_of_path: str):
return templates.TemplateResponse('index.html', { 'request': req })
@app.post("api/announcement/dispose")
def dispose(despose_data: schemas.DisposeData, current_user: Annotated[schemas.User, Depends(utils.get_current_user)]):
current_user.rating += 60

View File

@ -1,12 +1,17 @@
from sqlalchemy import Column, Integer, String, Boolean, Float, DateTime, Date, ForeignKey
from sqlalchemy import Column, Integer, String, Boolean, Float, DateTime, Date, ForeignKey, Enum, UniqueConstraint
from fastapi import Depends
from .db import Base, engine
from sqlalchemy.orm import relationship
# class User(SQLAlchemyBaseUserTableUUID, Base):
# name = Column(String, nullable=True)#имя пользователя
# импортируем модуль для создания перечислений
import enum
# # класс, необходимый для создания перечисления
# class State(enum.Enum):
# published = 1
# taken = 2
# obsolete = 3
class User(Base):#класс пользователя
@ -18,30 +23,34 @@ class User(Base):#класс пользователя
name = Column(String, nullable=True)#имя пользователя
surname = Column(String)#фамилия пользователя
disabled = Column(Boolean, default=False)
rating = Column(Integer, default=0) #баллы пользователя
reg_date = Column(Date) # дата регистрации
items = relationship("Announcement", back_populates="owner")
items = relationship("Announcement", back_populates="users")
class Announcement(Base): #класс объявления
__tablename__ = "announcements"
id = Column(Integer, primary_key=True, index=True)#айди объявления
owner_id = Column(Integer, ForeignKey("users.id"))#айди создателя объявления
id = Column(Integer, primary_key=True, index=True) # айди объявления
user_id = Column(Integer, ForeignKey("users.id", name="fk_users_id")) # айди создателя объявления
name = Column(String) # название объявления
category = Column(String)#категория продукта из объявления
best_by = Column(Date)#срок годности продукта из объявления
category = Column(String) #категория продукта из объявления
best_by = Column(Date) #срок годности продукта из объявления
address = Column(String)
longtitude = Column(Integer)
latitude = Column(Integer)
description = Column(String)#описание продукта в объявлении
description = Column(String) #описание продукта в объявлении
src = Column(String, nullable=True) #изображение продукта в объявлении
metro = Column(String)#ближайщее метро от адреса нахождения продукта
metro = Column(String) #ближайщее метро от адреса нахождения продукта
trashId = Column(Integer, nullable=True)
booked_by = Column(Integer)#статус бронирования (либо -1, либо айди бронирующего)
booked_by = Column(Integer) #статус бронирования (либо -1, либо айди бронирующего)
# state = Column(Enum(State), default=State.published) # состояние объявления (опубликовано, забронировано, устарело)
obsolete = Column(Boolean, default=False) # состояние объявления (по-умолчанию считаем его актуальным)
owner = relationship("User", back_populates="items")
class Trashbox(Base):#класс мусорных баков
class Trashbox(Base): #класс мусорных баков
__tablename__ = "trashboxes"
id = Column(Integer, primary_key=True, index=True)#айди
@ -49,7 +58,7 @@ class Trashbox(Base):#класс мусорных баков
address = Column(String)
latitude = Column(Integer)
longtitude = Column(Integer)
category = Column(String)#категория продукта из объявления
category = Column(String) #категория продукта из объявления
class Poems(Base):#класс поэзии

View File

@ -71,3 +71,21 @@ class TrashboxRequest(TrashboxBase):
class DisposeRequest(BaseModel):
ann_id: int
trashbox: TrashboxRequest
class SortAnnouncements(BaseModel):
expired: Union[int, None] = False
user_id: Union[int, None] = None
metro: Union[str, None] = None
category: Union[str, None] = None
# booked_by: Union[int, None] = None
class DisposeData(BaseModel):
ann_id: int # id объявления
trash_id: int # id мусорки
trash_category: str # категория мусора
# схема для начисления баллов
class AddPoints(BaseModel):
user_id: int
rate: int

View File

@ -1,6 +1,9 @@
from sqlalchemy.orm import Session
from .models import Poems
from typing import Annotated, Union
from fastapi import Depends
from . import models, schemas, utils
import random
import datetime
# Загружаем стихи
@ -31,20 +34,34 @@ def add_poems_to_db(db: Session):
def generate_poem(db: Session):
# генерируем 1 случайное id и выбираем объект бд с этим id
rand_id = random.randint(1, 102)
poem = db.query(Poems).filter(Poems.id == rand_id).first()
poem = db.query(models.Poems).filter(models.Poems.id == rand_id).first()
# возвращаем название и текст стихотворения
return {"name": poem.poem_name, "text": poem.poem_text, "author":""} # добавить поле author в Poems
# Функция, создающая сессию БД при каждом запросе к нашему API.
# Срабатывает до запуска остальных функций.
# Всегда закрывает сессию при окончании работы с ней
# @app.middleware("http")
# async def db_session_middleware(request: Request, call_next):
# response = Response("Internal server error", status_code=500)
# try:
# request.state.db = SessionLocal()
# response = await call_next(request)
# finally:
# request.state.db.close()
# return response
def get_query_results(db: Annotated[Session, Depends(utils.get_db)], schema: schemas.SortAnnouncements):
"""Функция для последовательного применения различных фильтров (через схему SortAnnouncements)"""
res = db.query(models.Announcement)
fields = schema.__dict__ # параметры передоваемой схемы SortAnnouncements (ключи и значения)
for name, filt in fields.items():
if filt is not None:
d = {name: filt}
res = res.filter_by(**d)
return res.all()
def check_obsolete(db: Annotated[Session, Depends(utils.get_db)], current_date: datetime.date):
"""
Возвращаем список объектов базы данных типа Announcement
, удовлетворяющих условию obsolete == True
"""
list_to_return = []
not_obsolete = database.query(models.Announcement).filter(models.Announcement.obsolete == True).all()
for ann in not_obsolete:
if ann.best_by < current_date:
ann.obsolete = False
else:
list_to_return.append(ann)
return list_to_return

View File

@ -36,15 +36,15 @@ def get_password_hash(password):
return pwd_context.hash(password)
def get_user(db: Session, user_id: int):
def get_user(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: Session, email: str, password: str):
user = get_user(db, user_id)
def authenticate_user(db: Annotated[Session, Depends(get_db)], email: str, password: str):
user = get_user(user_id = user_id)
if not user:
return False
if not verify_password(password, user.hashed_password):
@ -81,7 +81,6 @@ async def get_current_user(db: Annotated[Session, Depends(get_db)], token: Annot
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 user
async def get_current_active_user(

View File

@ -17,12 +17,7 @@ config = context.config
if config.config_file_name is not None:
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = base.Base.metadata
# target_metadata = None
# other values from the config, defined by the needs of env.py,
# can be acquired:

View File

@ -0,0 +1,48 @@
"""points added to user model; owner_id -> user_id; added state(announcement table)
Revision ID: 4e4d30fd58fc
Revises: 00529d20660b
Create Date: 2023-08-05 09:38:03.284306
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4e4d30fd58fc'
down_revision = '00529d20660b'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('announcements', schema=None) as batch_op:
batch_op.add_column(sa.Column('user_id', sa.Integer(), nullable=True))
batch_op.add_column(sa.Column('state', sa.Enum('published', 'taken', 'obsolete', name='state'), nullable=True))
# batch_op.drop_constraint(None, type_='foreignkey')
batch_op.create_foreign_key('fk_users_id', 'users', ['user_id'], ['id'])
batch_op.drop_column('owner_id')
with op.batch_alter_table('users', schema=None) as batch_op:
batch_op.add_column(sa.Column('rating', sa.Integer(), nullable=True))
batch_op.add_column(sa.Column('reg_date', sa.Date(), nullable=True))
# ### 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.drop_column('reg_date')
batch_op.drop_column('rating')
with op.batch_alter_table('announcements', schema=None) as batch_op:
batch_op.add_column(sa.Column('owner_id', sa.INTEGER(), nullable=True))
# batch_op.drop_constraint('fk_users_id', type_='foreignkey')
batch_op.create_foreign_key(None, 'users', ['owner_id'], ['id'])
batch_op.drop_column('state')
batch_op.drop_column('user_id')
# ### end Alembic commands ###

View File

@ -0,0 +1,34 @@
"""state(enum) -> obsolete(Boolean)
Revision ID: faecbd04e5eb
Revises: 4e4d30fd58fc
Create Date: 2023-08-05 23:57:31.784676
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'faecbd04e5eb'
down_revision = '4e4d30fd58fc'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('announcements', schema=None) as batch_op:
batch_op.add_column(sa.Column('obsolete', sa.Boolean(), nullable=True))
batch_op.drop_column('state')
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('announcements', schema=None) as batch_op:
batch_op.add_column(sa.Column('state', sa.VARCHAR(length=9), nullable=True))
batch_op.drop_column('obsolete')
# ### end Alembic commands ###