generateur_v3/backend/api/routes/exercices/routes.py

253 lines
11 KiB
Python
Raw Normal View History

2023-02-22 12:43:39 +01:00
import csv
import io
2022-10-10 01:34:38 +02:00
from enum import Enum
2022-09-16 21:50:55 +02:00
from typing import List
2023-02-22 12:43:39 +01:00
from fastapi import APIRouter, Depends, Query, UploadFile, HTTPException, status
from fastapi.responses import FileResponse, StreamingResponse
from fastapi_pagination.ext.sqlalchemy_future import paginate as p
from pydantic import BaseModel
2023-02-26 16:29:05 +01:00
from sqlmodel import Session, select, col
2023-02-22 12:43:39 +01:00
2022-09-16 21:50:55 +02:00
from database.auth.models import User
from database.db import get_session
2023-02-22 12:43:39 +01:00
from database.exercices.crud import add_tags_db, check_exercice_author, check_private, check_tag_author, create_exo_db, \
delete_exo_db, get_exo_dependency, clone_exo_db, remove_tag_db, serialize_exo, update_exo_db, get_tags_dependency
from database.exercices.models import Exercice, ExerciceCreate, ExerciceEdit, ExerciceReadFull, ExercicesTagLink, Tag, \
TagCreate, TagRead, ExerciceRead
from generateur.generateur_csv import Csv_generator
2022-09-16 21:50:55 +02:00
from services.auth import get_current_user, get_current_user_optional
from services.exoValidation import validate_file, validate_file_optionnal
from services.io import add_fast_api_root, get_filename_from_path
2023-01-27 21:41:08 +01:00
from services.models import Page
2022-09-16 21:50:55 +02:00
router = APIRouter(tags=['exercices'])
2023-02-22 12:43:39 +01:00
2022-10-10 01:34:38 +02:00
class ExoType(str, Enum):
2023-02-22 12:43:39 +01:00
csv = "csv"
pdf = "pdf"
web = "web"
2022-10-10 01:34:38 +02:00
2022-09-16 21:50:55 +02:00
def filter_exo_by_tags(exos: List[tuple[Exercice, str]], tags: List[Tag]):
valid_exos = [exo for exo, tag in exos if all(
str(t) in tag.split(',') for t in tags)]
return valid_exos
2023-02-22 12:43:39 +01:00
def queryFilters_dependency(search: str = "", tags: List[str] | None = Depends(get_tags_dependency),
type: ExoType | None = Query(default=None)):
2022-10-10 01:34:38 +02:00
return search, tags, type
2022-09-16 21:50:55 +02:00
2022-12-27 18:26:05 +01:00
@router.post('/exercices', response_model=ExerciceReadFull, status_code=status.HTTP_201_CREATED)
2023-02-22 12:43:39 +01:00
def create_exo(exercice: ExerciceCreate = Depends(ExerciceCreate.as_form), file: UploadFile = Depends(validate_file),
user: User = Depends(get_current_user), db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
file_obj = file['file'].file._file
file_obj.name = file['file'].filename
2022-09-16 21:50:55 +02:00
exo_obj = create_exo_db(exercice=exercice, user=user,
2023-02-22 12:43:39 +01:00
exo_source=file_obj, supports=file['supports'], db=db)
2022-09-16 21:50:55 +02:00
return serialize_exo(exo=exo_obj, user_id=user.id, db=db)
2022-12-27 18:26:05 +01:00
@router.post('/clone/{id_code}', response_model=ExerciceReadFull)
2023-02-22 12:43:39 +01:00
def clone_exo(exercice: Exercice | None = Depends(check_private), user: User = Depends(get_current_user),
db: Session = Depends(get_session)):
2022-09-16 21:50:55 +02:00
if not exercice:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail={
2023-02-22 12:43:39 +01:00
"Exercice introuvable"})
2022-09-16 21:50:55 +02:00
exo_obj = clone_exo_db(exercice, user, db)
if type(exo_obj) == str:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=exo_obj)
return serialize_exo(exo=exo_obj, user_id=user.id, db=db)
2023-02-22 12:43:39 +01:00
@router.get('/exercices/user', response_model=Page[ExerciceRead | ExerciceReadFull])
def get_user_exercices(user: User = Depends(get_current_user),
queryFilters: tuple[str, List[int] | None, ExoType | None] = Depends(queryFilters_dependency),
db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
search, tags, type = queryFilters
2023-02-22 12:43:39 +01:00
2023-01-27 21:41:08 +01:00
statement = select(Exercice)
2022-09-16 21:50:55 +02:00
statement = statement.where(Exercice.author_id == user.id)
statement = statement.where(Exercice.name.startswith(search))
2023-02-22 12:43:39 +01:00
2022-10-10 01:34:38 +02:00
if type == ExoType.csv:
statement = statement.where(Exercice.csv == True)
if type == ExoType.pdf:
statement = statement.where(Exercice.pdf == True)
if type == ExoType.web:
statement = statement.where(Exercice.web == True)
2023-02-22 12:43:39 +01:00
2023-01-27 21:41:08 +01:00
for t in tags:
2023-02-22 12:43:39 +01:00
sub = select(ExercicesTagLink).where(ExercicesTagLink.exercice_id == Exercice.id).where(
2023-01-27 21:41:08 +01:00
ExercicesTagLink.tag_id == t).exists()
statement = statement.where(sub)
2023-02-26 16:29:05 +01:00
statement = statement.order_by(col(Exercice.id).desc())
2022-12-27 18:26:05 +01:00
page = p(db, statement)
exercices = page.items
page.items = [
serialize_exo(exo=e, user_id=user.id, db=db) for e in exercices]
return page
2022-09-16 21:50:55 +02:00
2023-02-22 12:43:39 +01:00
@router.get('/exercices/public', response_model=Page[ExerciceRead | ExerciceReadFull])
def get_public_exercices(user: User | None = Depends(get_current_user_optional),
queryFilters: tuple[str, List[int] | None] = Depends(queryFilters_dependency),
db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
search, tags, type = queryFilters
2022-09-16 21:50:55 +02:00
if user is not None:
2023-01-27 21:41:08 +01:00
statement = select(Exercice)
2022-09-16 21:50:55 +02:00
statement = statement.where(Exercice.author_id != user.id)
statement = statement.where(Exercice.private == False)
2023-02-22 12:43:39 +01:00
statement = statement.where(Exercice.origin_id == None)
2022-09-16 21:50:55 +02:00
statement = statement.where(Exercice.name.startswith(search))
2022-10-10 01:34:38 +02:00
if type == ExoType.csv:
statement = statement.where(Exercice.csv == True)
if type == ExoType.pdf:
statement = statement.where(Exercice.pdf == True)
if type == ExoType.web:
statement = statement.where(Exercice.web == True)
2023-02-22 12:43:39 +01:00
2023-01-27 21:41:08 +01:00
for t in tags:
2023-02-22 12:43:39 +01:00
sub = select(ExercicesTagLink).where(ExercicesTagLink.exercice_id == Exercice.id).where(
ExercicesTagLink.tag_id == t).exists()
2023-01-27 21:41:08 +01:00
statement = statement.where(sub)
2023-02-26 16:29:05 +01:00
statement = statement.order_by(col(Exercice.id).desc())
2023-01-27 21:41:08 +01:00
page = p(db, statement)
2023-02-28 10:21:08 +01:00
2023-01-27 21:41:08 +01:00
exercices = page.items
page.items = [
2022-09-16 21:50:55 +02:00
serialize_exo(exo=e, user_id=user.id, db=db) for e in exercices]
2023-01-27 21:41:08 +01:00
return page
2023-02-22 12:43:39 +01:00
2022-09-16 21:50:55 +02:00
else:
statement = select(Exercice)
statement = statement.where(Exercice.private == False)
statement = statement.where(Exercice.name.startswith(search))
2022-10-10 01:34:38 +02:00
if type == ExoType.csv:
statement = statement.where(Exercice.csv == True)
if type == ExoType.pdf:
statement = statement.where(Exercice.pdf == True)
if type == ExoType.web:
statement = statement.where(Exercice.web == True)
2023-02-22 12:43:39 +01:00
2023-01-27 21:41:08 +01:00
page = p(db, statement)
exercices = page.items
page.items = [
serialize_exo(exo=e, user_id=None, db=db) for e in exercices]
return page
2022-09-16 21:50:55 +02:00
2022-12-27 18:26:05 +01:00
@router.get('/exercice/{id_code}', response_model=ExerciceReadFull)
2023-02-22 12:43:39 +01:00
def get_exercice(exo: Exercice = Depends(check_private), user: User | None = Depends(get_current_user_optional),
db: Session = Depends(get_session)):
2022-09-16 21:50:55 +02:00
return serialize_exo(exo=exo, user_id=getattr(user, 'id', None), db=db)
2022-12-27 18:26:05 +01:00
@router.put('/exercice/{id_code}', response_model=ExerciceReadFull)
2023-02-22 12:43:39 +01:00
def update_exo(file: UploadFile = Depends(validate_file_optionnal), exo: Exercice = Depends(check_exercice_author),
exercice: ExerciceEdit = Depends(ExerciceEdit.as_form), db: Session = Depends(get_session)):
2022-09-16 21:50:55 +02:00
if exo is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='Exercice introuvable')
if exo == False:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
detail='Cet exercice ne vous appartient pas')
file_obj = None
if file:
2022-10-10 01:34:38 +02:00
file_obj = file["file"].file._file
file_obj.name = file['file'].filename
2023-01-27 21:41:08 +01:00
exo_obj = update_exo_db(exo, exercice, file['supports'] if file is not None else None, file_obj, db)
2022-09-16 21:50:55 +02:00
return serialize_exo(exo=exo_obj, user_id=exo_obj.author_id, db=db)
@router.delete('/exercice/{id_code}')
2023-02-22 12:43:39 +01:00
def delete_exercice(exercice: Exercice | bool | None = Depends(check_exercice_author),
db: Session = Depends(get_session)):
2022-09-16 21:50:55 +02:00
if exercice is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail="Exercice introuvable")
if exercice == False:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
detail='Cet exercice ne vous appartient pas')
delete_exo_db(exercice, db)
return {'detail': 'Exercice supprimé avec succès'}
2023-01-27 21:41:08 +01:00
class NewTags(BaseModel):
exo: ExerciceReadFull
tags: list[TagRead]
2023-02-22 12:43:39 +01:00
2023-01-27 21:41:08 +01:00
@router.post('/exercice/{id_code}/tags', response_model=NewTags, tags=['tags'])
2023-02-22 12:43:39 +01:00
def add_tags(tags: List[TagCreate], exo: Exercice | None = Depends(get_exo_dependency),
db: Session = Depends(get_session), user: User = Depends(get_current_user)):
2022-09-16 21:50:55 +02:00
if exo is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='Exercice introuvable')
2023-01-27 21:41:08 +01:00
exo_obj, new = add_tags_db(exo, tags, user, db)
2023-02-22 12:43:39 +01:00
return {"exo": serialize_exo(exo=exo_obj, user_id=user.id, db=db), "tags": new}
2022-09-16 21:50:55 +02:00
2022-12-27 18:26:05 +01:00
@router.delete('/exercice/{id_code}/tags/{tag_id}', response_model=ExerciceReadFull, tags=['tags'])
2023-02-22 12:43:39 +01:00
def remove_tag(exo: Exercice | None = Depends(get_exo_dependency), tag: Tag | None | bool = Depends(check_tag_author),
db: Session = Depends(get_session)):
2022-09-16 21:50:55 +02:00
if exo is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail='Exercice introuvable')
if tag is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='Tag introuvable')
if tag == False:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail="Vous n'êtes pas le propriétaire du tag")
exo_obj = remove_tag_db(exo, tag, db)
return serialize_exo(exo=exo_obj, user_id=tag.author_id, db=db)
@router.get('/exercice/{id_code}/exo_source')
2023-02-22 12:43:39 +01:00
async def get_exo_source(exo: Exercice = Depends(check_exercice_author)):
2022-09-16 21:50:55 +02:00
if exo is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
detail='Exercice introuvable')
if exo == False:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
detail='Cet exercice ne vous appartient pas')
path = add_fast_api_root(exo.exo_source)
filename = get_filename_from_path(path)
2023-02-22 12:43:39 +01:00
return FileResponse(path, headers={'content-disposition': 'attachment;filename=' + filename})
2022-09-16 21:50:55 +02:00
@router.get('/tags', response_model=List[TagRead], tags=['tags'])
def get_tags(user: User = Depends(get_current_user), db: Session = Depends(get_session)):
return user.tags
2023-02-22 12:43:39 +01:00
@router.get('/generator/csv/{id_code}')
async def generate_csv(*, exo: Exercice | None = Depends(get_exo_dependency), filename: str):
if exo.csv is False:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,
detail='Impossible de générer cet exercice sur dans ce format')
source_path = add_fast_api_root(exo.exo_source)
consigne = exo.consigne
buffer = io.StringIO()
writer = csv.writer(buffer, delimiter=',',
quotechar=',', quoting=csv.QUOTE_MINIMAL, dialect='excel') # mettre | comme sep un jour
Csv_generator(source_path, 10, 10, 12, consigne, writer)
return StreamingResponse(iter([buffer.getvalue()]),
headers={"Content-Disposition": f'attachment;filename={filename}'}, media_type='text/csv')