generateur_v3/backend/api/routes/room/routes.py

266 lines
13 KiB
Python
Raw Normal View History

2023-02-22 12:43:39 +01:00
from typing import List, Optional
2022-09-26 10:04:02 +02:00
2022-10-10 01:34:38 +02:00
from fastapi import APIRouter, Depends, WebSocket, status, Query, Body
2023-02-22 12:43:39 +01:00
from fastapi.exceptions import HTTPException
from pydantic import BaseModel
from sqlmodel import Session, select
2022-09-18 22:43:04 +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.models import Exercice
from database.room.crud import serialize_parcours_short, change_correction, corrige_challenge, \
create_parcours_db, delete_parcours_db, create_room_db, get_member_dep, check_room, serialize_room, \
update_parcours_db, get_parcours, get_room, check_admin, get_exercices, get_challenge, get_correction, \
create_tmp_correction, create_challenge, change_challenge, serialize_parcours, getTops, getAvgRank, getRank, \
getAvgTops, ChallengerFromChallenge, getMemberAvgRank, getMemberRank
from database.room.models import Challenge, ChallengeRead, Challenges, ParcoursReadUpdate, ChallengeInfo, Member, \
Parcours, ParcoursCreate, ParcoursRead, ParcoursReadShort, Room, RoomConnectionInfos, \
RoomCreate, RoomInfo, TmpCorrection, CorrigedData, CorrectionData
from generateur.generateur_main import generate_from_path, parseGeneratorOut
2022-09-26 10:04:02 +02:00
from routes.room.consumer import RoomConsumer
from routes.room.manager import RoomManager
2022-09-18 22:43:04 +02:00
from services.auth import get_current_user_optional
2023-02-22 12:43:39 +01:00
from services.io import add_fast_api_root
from services.misc import stripKeyDict
from typing import List, Optional
from fastapi import APIRouter, Depends, WebSocket, status, Query, Body
2022-09-18 22:43:04 +02:00
from fastapi.exceptions import HTTPException
2023-02-22 12:43:39 +01:00
from pydantic import BaseModel
from sqlmodel import Session, select
from database.auth.models import User
from database.db import get_session
from database.exercices.models import Exercice
from database.room.crud import serialize_parcours_short, change_correction, corrige_challenge, \
create_parcours_db, delete_parcours_db, create_room_db, get_member_dep, check_room, serialize_room, \
update_parcours_db, get_parcours, get_room, check_admin, get_exercices, get_challenge, get_correction, \
create_tmp_correction, create_challenge, change_challenge, serialize_parcours, getTops, getAvgRank, getRank, \
getAvgTops, ChallengerFromChallenge, getMemberAvgRank, getMemberRank
from database.room.models import Challenge, ChallengeRead, Challenges, ParcoursReadUpdate, ChallengeInfo, Member, \
Parcours, ParcoursCreate, ParcoursRead, ParcoursReadShort, Room, RoomConnectionInfos, \
RoomCreate, RoomInfo, TmpCorrection, CorrigedData, CorrectionData
from generateur.generateur_main import generate_from_path, parseGeneratorOut
from routes.room.consumer import RoomConsumer
from routes.room.manager import RoomManager
from services.auth import get_current_user_optional
from services.io import add_fast_api_root
from services.misc import stripKeyDict
2022-09-16 21:50:55 +02:00
router = APIRouter(tags=["room"])
2022-10-10 01:34:38 +02:00
manager = RoomManager()
2022-09-16 21:50:55 +02:00
2022-10-10 01:34:38 +02:00
def get_manager():
return manager
2022-09-18 22:43:04 +02:00
2023-02-22 12:43:39 +01:00
2022-10-10 01:34:38 +02:00
@router.post('/room', response_model=RoomConnectionInfos)
2023-02-23 17:11:57 +01:00
def create_room(room: RoomCreate, username: Optional[str] = Query(default=None, max_length=20),
user: User | None = Depends(get_current_user_optional), db: Session = Depends(get_session)):
2022-09-18 22:43:04 +02:00
room_obj = create_room_db(room=room, user=user, username=username, db=db)
2022-10-10 01:34:38 +02:00
return {'room': room_obj['room'].id_code, "member": getattr(room_obj['member'].anonymous, "reconnect_code", None)}
2022-09-18 22:43:04 +02:00
2022-10-10 01:34:38 +02:00
@router.get('/room/{room_id}', response_model=RoomInfo)
2023-02-23 17:11:57 +01:00
def get_room_route(room: Room = Depends(get_room), member: Member = Depends(get_member_dep),
db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
return serialize_room(room, member, db)
@router.post('/room/{room_id}/parcours', response_model=ParcoursRead)
2023-02-23 17:11:57 +01:00
async def create_parcours(*, parcours: ParcoursCreate, room_id: str, member: Member = Depends(check_admin),
m: RoomManager = Depends(get_manager), db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
parcours_obj = create_parcours_db(parcours, member.room_id, db)
if type(parcours_obj) == str:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=parcours_obj)
2023-02-22 12:43:39 +01:00
await m.broadcast({"type": "add_parcours",
"data": {"parcours": ParcoursReadShort(**parcours_obj.dict(exclude_unset=True)).dict()}},
room_id)
return serialize_parcours(parcours_obj, member, db)
2022-10-10 01:34:38 +02:00
@router.get('/room/{room_id}/parcours/{parcours_id}', response_model=ParcoursRead)
2023-02-23 17:11:57 +01:00
async def get_parcours_route(*, parcours: Parcours = Depends(get_parcours), member: Member = Depends(get_member_dep),
db: Session = Depends(get_session)):
2023-02-22 12:43:39 +01:00
return serialize_parcours(parcours, member, db)
2022-10-10 01:34:38 +02:00
2023-02-22 12:43:39 +01:00
@router.put('/room/{room_id}/parcours/{parcours_id}', response_model=ParcoursRead)
async def update_parcours(*, room_id: str, parcours: ParcoursCreate, member: Member = Depends(check_admin),
parcours_old: Parcours = Depends(get_parcours), m: RoomManager = Depends(get_manager),
db: Session = Depends(get_session)):
parcours_obj, update_challenges = update_parcours_db(
parcours, parcours_old, db)
2022-10-10 01:34:38 +02:00
if type(parcours_obj) == str:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, detail=parcours_obj)
2023-02-22 12:43:39 +01:00
await m.broadcast(lambda m: {"type": "update_parcours",
"data": {"parcours": serialize_parcours_short(parcours_obj, m, db).dict()}}, room_id)
await m.broadcast({"type": "edit_parcours", "data": {
"parcours": ParcoursReadUpdate(**parcours_obj.dict(), update_challenges=update_challenges).dict()}},
parcours_old.id_code)
return serialize_parcours(parcours_obj, member, db)
return {**parcours_obj.dict()}
2022-10-10 01:34:38 +02:00
@router.delete('/room/{room_id}/parcours/{parcours_id}', dependencies=[Depends(check_admin)])
2023-02-23 17:11:57 +01:00
async def delete_parcours(parcours: Parcours = Depends(get_parcours), m: RoomManager = Depends(get_manager),
db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
delete_parcours_db(parcours, db)
await m.broadcast({"type": "del_parcours", "data": {"parcours_id": parcours.id_code}}, parcours.room.id_code)
return "ok"
class Exos(BaseModel):
exercice: Exercice
quantity: int
2023-02-22 12:43:39 +01:00
2022-10-10 01:34:38 +02:00
@router.get('/room/{room_id}/challenge/{parcours_id}')
2023-02-22 12:43:39 +01:00
def challenge_route(parcours: Parcours = Depends(get_parcours), exercices: List[Exos] = Depends(get_exercices),
member: Member = Depends(get_member_dep), db: Session = Depends(get_session)):
print('GENERATE', exercices)
2022-10-10 01:34:38 +02:00
correction = [parseGeneratorOut(generate_from_path(add_fast_api_root(
e['exercice'].exo_source), e['quantity'], "web")) for e in exercices]
2023-02-22 12:43:39 +01:00
infos = [{"name": e["exercice"].name, "consigne": e['exercice'].consigne, "id_code": e['exercice'].id_code}
for e in exercices]
sending = [{"exo": ei, "data": [{**c, 'inputs': [stripKeyDict(i, "correction")
for i in c['inputs']]} for c in e]} for e, ei in
zip(correction, infos)]
corriged = [{"exo": ei, "data": e} for e, ei in zip(correction, infos)]
tmpCorr = create_tmp_correction(corriged, parcours.id_code, member, db)
return {'challenge': sending, "id_code": tmpCorr.id_code,
'parcours': {"name": parcours.name, 'time': parcours.time, "max_mistakes": parcours.max_mistakes,
'id_code': parcours.id_code}}
2022-10-10 01:34:38 +02:00
@router.post('/room/{room_id}/challenge/{parcours_id}/{correction_id}', response_model=ChallengeRead)
2023-02-22 12:43:39 +01:00
async def send_challenge(*, challenge: List[CorrectionData], correction: TmpCorrection = Depends(get_correction),
time: int = Body(), db: Session = Depends(get_session),
m: RoomManager = Depends(get_manager), ):
2022-10-10 01:34:38 +02:00
parcours = correction.parcours
member = correction.member
data = corrige_challenge(challenge, correction)
2023-02-22 12:43:39 +01:00
2022-10-10 01:34:38 +02:00
if data is None:
raise HTTPException(
2023-02-22 12:43:39 +01:00
status_code=status.HTTP_400_BAD_REQUEST,
detail={"challenge_error": "Object does not correspond to correction"})
chall, challenger = create_challenge(**data, challenger=member,
parcours=parcours, time=time, db=db)
await m.broadcast({"type": "challenge", "data": ChallengeInfo(
challenger={"name": member.user.username if member.user_id != None else member.anonymous.username,
"id_code": member.id_code},
challenges=[Challenges(**{**chall.dict(), "canCorrige": chall.data != [], })]).dict()}, parcours.id_code,
conditions=[lambda c: c.member.is_admin or c.member.id_code == member.id_code])
2023-02-23 17:11:57 +01:00
# TODO : Envoyer que à ceux d'après
2023-02-22 12:43:39 +01:00
await m.broadcast(lambda m: {"type": "newRanks", "data": {"rank": getMemberRank(m, correction.parcours, db),
"avgRank": getMemberAvgRank(m, correction.parcours, db)}},
parcours.id_code)
2023-02-23 17:11:57 +01:00
print('WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOoo')
await m.send_to(parcours.room.id_code, member.id_code, {"type": "parcours_stats", "data": {
"parcours": ParcoursReadShort(name=parcours.name, best_note=challenger.best, validated=challenger.validated,
id_code=parcours.id_code, avg=challenger.avg).dict()}})
2023-02-22 12:43:39 +01:00
print('CHALLENGE', chall)
rank, avgRank = getRank(
challenger, parcours, db), getAvgRank(challenger, parcours, db)
print('RANKS', rank, avgRank)
if rank <= 3 or avgRank <= 3:
await m.broadcast({"type": "newTops", "data": {
"tops": getTops(correction.parcours, db),
"avgTops": getAvgTops(correction.parcours, db),
}}, parcours.id_code)
print('CHALLENGE', chall)
2022-10-10 01:34:38 +02:00
db.delete(correction)
2023-02-22 12:43:39 +01:00
returnValue = {**chall.dict(), 'validated': chall.mistakes <= correction.parcours.max_mistakes}
2022-10-10 01:34:38 +02:00
db.commit()
2023-02-22 12:43:39 +01:00
return returnValue
# return {**chall.dict(), 'validated': chall.mistakes <= correction.parcours.max_mistakes}
2022-10-10 01:34:38 +02:00
2023-02-22 12:43:39 +01:00
class ParcoursInfo(BaseModel):
name: str
time: int
# validate: int
id_code: str
2022-10-10 01:34:38 +02:00
2023-02-22 12:43:39 +01:00
class Chall(BaseModel):
challenge: Challenge
parcours: ParcoursInfo
2022-10-10 01:34:38 +02:00
2023-02-22 12:43:39 +01:00
# response_model=ChallengeRead
@router.get('/room/{room_id}/correction/{challenge_id}', dependencies=[Depends(get_member_dep)])
async def challenge_read(*, challenge: Challenge = Depends(get_challenge), db: Session = Depends(get_session)):
2022-10-10 01:34:38 +02:00
parcours = challenge.parcours
2023-02-22 12:43:39 +01:00
member = db.exec(select(Member).where(
Member.id == challenge.challenger_mid)).first()
challenger = ChallengerFromChallenge(challenge, db)
obj = member.user if member.user_id is not None else member.anonymous
return {**ChallengeRead(**challenge.dict()).dict(), "challenger": {"name": obj.username},
'parcours': {"name": parcours.name, 'time': parcours.time, "max_mistakes": parcours.max_mistakes,
'id_code': parcours.id_code}}
# response_model=ChallengeRead
@router.put('/room/{room_id}/correction/{challenge_id}', dependencies=[Depends(check_admin)])
async def corrige(*, correction: List[CorrigedData] = Body(), challenge: Challenge = Depends(get_challenge),
db: Session = Depends(get_session), m: RoomManager = Depends(get_manager), ):
2022-10-10 01:34:38 +02:00
data = change_correction(correction, challenge)
if data is None:
raise HTTPException(
2023-02-22 12:43:39 +01:00
status_code=status.HTTP_400_BAD_REQUEST,
detail={"correction_error": "Object does not correspond to challenge"})
2022-10-10 01:34:38 +02:00
2023-02-22 12:43:39 +01:00
parcours = challenge.parcours
member = db.exec(select(Member).where(
Member.id == challenge.challenger_mid)).first()
challenge, challenger = change_challenge(challenge, data, db)
obj = member.user if member.user_id is not None else member.anonymous
await m.broadcast(lambda m: {"type": "newRanks", "data": {"rank": getMemberRank(m, parcours, db),
"avgRank": getMemberAvgRank(m, parcours, db)}},
parcours.id_code)
rank, avgRank = getRank(
challenger, parcours, db), getAvgRank(challenger, parcours, db)
2023-02-23 17:11:57 +01:00
2023-02-22 12:43:39 +01:00
if rank <= 3 or avgRank <= 3:
await m.broadcast({"type": "newTops", "data": {
"tops": getTops(parcours, db),
"avgTops": getAvgTops(parcours, db),
}}, parcours.id_code)
await m.broadcast({"type": "challenge_change",
2023-02-23 17:11:57 +01:00
"data": {"challenge": Challenges(**challenge.dict()).dict(), "member": member.id_code,
"validated": challenger.validated}},
2023-02-22 12:43:39 +01:00
parcours.id_code, conditions=[lambda m: m.member.is_admin or m.member.id_code == member.id_code])
return {**ChallengeRead(**challenge.dict()).dict(), "challenger": {"name": obj.username}}
2023-02-23 17:11:57 +01:00
# return {**ChallengeRead.from_orm(challenge).dict(), "challenger": {"name": obj.username, }}
2022-09-21 22:31:50 +02:00
2022-09-26 10:04:02 +02:00
2022-09-18 22:43:04 +02:00
@router.websocket('/ws/room/{room_id}')
2023-02-23 17:11:57 +01:00
async def room_ws(ws: WebSocket, room: Room | None = Depends(check_room), db: Session = Depends(get_session),
m: RoomManager = Depends(get_manager)):
2022-09-18 22:43:04 +02:00
if room is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail='Room not found')
2022-10-10 01:34:38 +02:00
consumer = RoomConsumer(ws=ws, room=room, manager=m, db=db)
2022-09-18 22:43:04 +02:00
await consumer.run()