From 0085f10b90dc2cbafbd5cc515f1aeb6b95d2fbc7 Mon Sep 17 00:00:00 2001 From: Antoine Gaudron-desjardins <antoine.gaudrondesjardins@student-cs.fr> Date: Thu, 7 Jul 2022 18:57:51 +0200 Subject: [PATCH] restructure backend --- backend/db/crud.py | 74 +++++++++++++++++++++++++++++-------- backend/db/database.py | 8 ++++ backend/db/models.py | 24 +++++++++++- backend/db/schemas.py | 40 +++++++++++++++++--- backend/main.py | 40 ++++---------------- backend/requirements.txt | 3 +- backend/routers/__init__.py | 0 backend/routers/comments.py | 24 ++++++++++++ backend/routers/news.py | 24 ++++++++++++ backend/routers/stats.py | 21 +++++++++++ 10 files changed, 204 insertions(+), 54 deletions(-) create mode 100644 backend/routers/__init__.py create mode 100644 backend/routers/comments.py create mode 100644 backend/routers/news.py create mode 100644 backend/routers/stats.py diff --git a/backend/db/crud.py b/backend/db/crud.py index fe13875..c460f2e 100644 --- a/backend/db/crud.py +++ b/backend/db/crud.py @@ -2,27 +2,14 @@ Module to interact with the database """ from datetime import date, datetime, time, timedelta -from numpy import average from sqlalchemy.orm import Session from sqlalchemy.sql import func +import pytz from db import models, schemas -def get_records(place: str, db: Session): - """ Get all the records for the given place """ - records = db.query(models.Records).filter(models.Records.place == place).order_by(models.Records.date.desc()).all() - return records - - -def create_record(new_record: schemas.RecordBase, db: Session): - """ Add a new record to the database """ - db_record = models.Records(**new_record.dict()) - db.add(db_record) - db.commit() - db.refresh(db_record) - return db_record - +## Define CRUD operation to collect the statistics def get_waiting_time(place: str, db: Session): """ Get the last estimated waiting time for the given place """ @@ -72,3 +59,60 @@ def get_stats(place: str, weekday: int, min_time_hour: int, min_time_mn: int, ma start_time, end_time = end_time, shift_time(end_time, interval) return stats + + +## Define CRUD operation for the comments + +def get_comments(place: str, page: int, db: Session): + """ Get the 10 last comments for the given place """ + if page == 0: + comments = db.query(models.Comments).order_by(models.Comments.date.desc(), models.Comments.id.desc()).all() + else: + comments = db.query(models.Comments).filter(models.Comments.place == place).order_by(models.Comments.date.desc(), models.Comments.id.desc()).slice((page-1)*10, page*10).all() + return comments + + +def create_comment(place: str, new_comments: schemas.CommentBase, db: Session): + """ Add a new comment to the database """ + date = datetime.now(tz=pytz.timezone("Europe/Paris")) + db_comment = models.Comments(**new_comments.dict(), date=date, place=place) + db.add(db_comment) + db.commit() + db.refresh(db_comment) + return db_comment + + +def delete_comment(id: int, db: Session): + """ Delete the comment with the matching id """ + if id == 0: + db.query(models.Comments).delete() + else: + db.query(models.Comments).filter(models.Comments.id == id).delete() + db.commit() + + +## Define CRUD operation for the news + +def get_news(place: str, db: Session): + """ Get the news for the given place """ + news = db.query(models.News).filter(models.News.place == place).order_by(models.News.date.desc()).all() + return news + + +def create_news(new_news: schemas.NewsBase, db: Session): + """ Add a news to the database """ + date = datetime.now(tz=pytz.timezone("Europe/Paris")) + db_news = models.News(**new_news.dict(), published_at=date) + db.add(db_news) + db.commit() + db.refresh(db_news) + return db_news + + +def delete_news(id: int, db: Session): + """ Delete the news with the matching id """ + if id == 0: + db.query(models.News).delete() + else: + db.query(models.News).filter(models.News.id == id).delete() + db.commit() \ No newline at end of file diff --git a/backend/db/database.py b/backend/db/database.py index 4ea6517..eed306e 100644 --- a/backend/db/database.py +++ b/backend/db/database.py @@ -21,3 +21,11 @@ engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() + +def get_db(): + """Create a database session.""" + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/backend/db/models.py b/backend/db/models.py index 4971ef3..898bf95 100644 --- a/backend/db/models.py +++ b/backend/db/models.py @@ -1,7 +1,7 @@ """ Models of the database for magasin app """ -from sqlalchemy import Column, Integer, DateTime, Float, Interval, String +from sqlalchemy import Column, Integer, DateTime, Float, Interval, String, Text from db.database import Base @@ -15,3 +15,25 @@ class Records(Base): date = Column(DateTime) density = Column(Float) waiting_time = Column(Interval) + + +class Comments(Base): + """Comments sql table model""" + __tablename__ = "comments" + + id = Column(Integer, primary_key=True, index=True) + comment = Column(Text) + date = Column(DateTime) + place = Column(String(10)) + + +class News(Base): + """Records sql table model""" + __tablename__ = "News sql table model" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String(50)) + content = Column(Text) + published_at = Column(DateTime) + end_date = Column(DateTime) + place = Column(String(10)) diff --git a/backend/db/schemas.py b/backend/db/schemas.py index 5f10ba9..edb7b33 100644 --- a/backend/db/schemas.py +++ b/backend/db/schemas.py @@ -8,17 +8,47 @@ from pydantic import BaseModel, Field class RecordBase(BaseModel): """Records base schema""" - place: str = Field(..., - title="Name of the RU corresponding the given record") + place: str = Field(..., title="Name of the RU corresponding the given record") date: datetime = Field(..., title="Date of the record") density: float = Field(..., title="Estimated density of people") - waiting_time: Optional[timedelta] = Field( - title="Estimated waiting time for people coming at this date") + waiting_time: Optional[timedelta] = Field(title="Estimated waiting time for people coming at this date") class Record(RecordBase): - """Database records schema""" + """Database records base schema""" id: int class Config: orm_mode = True + + +class CommentBase(BaseModel): + """Comments base schema""" + comment: str = Field(..., title="Content of the comment posted") + + +class Comment(CommentBase): + """Database comments base schema""" + id: int + date: datetime = Field(..., title="Publication date of the comment") + place: str = Field(..., title="Name of the RU corresponding the comment") + + class Config: + orm_mode = True + + +class NewsBase(BaseModel): + """News sql table model""" + title: str = Field(..., title="Title of the news") + content: str = Field(..., title="Content of the news") + end_date: datetime = Field(..., title="End date to display the news") + place: str = Field(..., title="Name of the RU corresponding the news") + + +class News(NewsBase): + """Database news base schema""" + id: int + published_at: datetime = Field(..., title="Publication date of the news") + + class Config: + orm_mode = True \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index fc29c12..21db8ec 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,19 +1,16 @@ -from datetime import datetime, time, timedelta -from typing import List -from fastapi import Body, Depends, FastAPI +from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from sqlalchemy.orm import Session from dotenv import load_dotenv import os -from db import crud, schemas, database, models +from db import database, models +from routers import stats, comments, news +app = FastAPI(docs_url="/api/docs", openapi_url="/api/openapi.json") # load environment variables load_dotenv() -app = FastAPI(docs_url="/api/docs", openapi_url="/api/openapi.json") - origins = [ os.getenv('WEB_ROOT'), ] @@ -27,40 +24,19 @@ app.add_middleware( ) -def get_db(): - """Create a database session.""" - db = database.SessionLocal() - try: - yield db - finally: - db.close() - - @app.on_event("startup") def on_startup(): # Database creation models.Base.metadata.create_all(bind=database.engine) -@app.get('/api/{place}', response_model=List[schemas.Record]) -async def eatfast(place: str, db: Session = Depends(get_db)): - return crud.get_records(place, db) - - -@app.post('/api/create', response_model=schemas.Record) -async def post(record: schemas.RecordBase = Body(...), db: Session = Depends(get_db)): - return crud.create_record(record, db) - +# Integration of routers +app.include_router(stats.router) +app.include_router(comments.router) +app.include_router(news.router) -@app.get('/api/{place}/waiting_time', response_model=timedelta) -async def waiting_time(place: str, db: Session = Depends(get_db)): - return crud.get_waiting_time(place, db) -@app.get('/api/{place}/stats/{day}/{min_time_hour}/{min_time_mn}/{max_time_hour}/{max_time_mn}/{interval}', response_model=list) -async def stats(place: str, day: int, min_time_hour: int, min_time_mn: int, - max_time_hour: int, max_time_mn: int, interval: timedelta, db: Session = Depends(get_db)): - return crud.get_stats(place, day, min_time_hour, min_time_mn, max_time_hour, max_time_mn, interval, db) """ diff --git a/backend/requirements.txt b/backend/requirements.txt index dd60603..eb0a04d 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -14,4 +14,5 @@ typing-extensions==4.2.0 uvicorn==0.17.6 SQLAlchemy==1.4.19 python-dotenv==0.18.0 -PyMySQL==1.0.2 \ No newline at end of file +PyMySQL==1.0.2 +pytz==2022.1 \ No newline at end of file diff --git a/backend/routers/__init__.py b/backend/routers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/routers/comments.py b/backend/routers/comments.py new file mode 100644 index 0000000..ee7ce9d --- /dev/null +++ b/backend/routers/comments.py @@ -0,0 +1,24 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session +from typing import List + +from db import schemas, crud +from db.database import get_db + + +router = APIRouter(prefix="/api/comments", tags=["comments"]) + + +@router.get('/{place}', response_model=List[schemas.Comment]) +async def get_comments(place: str, page: int=1, db: Session = Depends(get_db)): + return crud.get_comments(place, page, db) + + +@router.post('/{place}', response_model=schemas.Comment) +async def create_comment(place: str, comment: schemas.CommentBase, db: Session = Depends(get_db)): + return crud.create_comment(place, comment, db) + + +@router.delete('/{id}', response_model=None) +async def delete_comment(id: int, db: Session = Depends(get_db)): + return crud.delete_comment(id, db) \ No newline at end of file diff --git a/backend/routers/news.py b/backend/routers/news.py new file mode 100644 index 0000000..4d0bd3e --- /dev/null +++ b/backend/routers/news.py @@ -0,0 +1,24 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session +from typing import List + +from db import schemas, crud +from db.database import get_db + + +router = APIRouter(prefix="/api/news", tags=["news"]) + + +@router.get('/{place}', response_model=List[schemas.News]) +async def get_news(place: str, db: Session = Depends(get_db)): + return crud.get_news(place, db) + + +@router.post('/{place}', response_model=schemas.News) +async def create_news(place: str, news: schemas.NewsBase, db: Session = Depends(get_db)): + return crud.create_news(place, news, db) + + +@router.delete('/{id}', response_model=None) +async def delete_news(id: int, db: Session = Depends(get_db)): + return crud.delete_news(id, db) \ No newline at end of file diff --git a/backend/routers/stats.py b/backend/routers/stats.py new file mode 100644 index 0000000..69bc337 --- /dev/null +++ b/backend/routers/stats.py @@ -0,0 +1,21 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session +from datetime import timedelta +from typing import List + +from db import crud +from db.database import get_db + + +router = APIRouter(prefix="/api", tags=["stats"]) + + +@router.get('/{place}/waiting_time', response_model=timedelta) +async def waiting_time(place: str, db: Session = Depends(get_db)): + return crud.get_waiting_time(place, db) + + +@router.get('/{place}/stats/{day}/{min_time_hour}/{min_time_mn}/{max_time_hour}/{max_time_mn}/{interval}', response_model=list) +async def stats(place: str, day: int, min_time_hour: int, min_time_mn: int, + max_time_hour: int, max_time_mn: int, interval: timedelta, db: Session = Depends(get_db)): + return crud.get_stats(place, day, min_time_hour, min_time_mn, max_time_hour, max_time_mn, interval, db) \ No newline at end of file -- GitLab