create eleve

This commit is contained in:
2026-04-25 20:35:43 +02:00
parent bd7c67fc93
commit c420d539da
5 changed files with 215 additions and 46 deletions

View File

@@ -9,6 +9,8 @@ from .auth import (
AUTH_COOKIE_NAME,
create_access_token,
get_current_user,
hash_password,
require_roles,
seed_admin_user,
verify_password,
)
@@ -51,6 +53,14 @@ app.add_middleware(
allow_headers=["*"],
)
def ensure_student_access(current_user: models.User, student_id: int) -> None:
if current_user.role in {"teacher", "maintenance"}:
return
if current_user.role == "student" and current_user.student_id == student_id:
return
raise HTTPException(status_code=403, detail="Droits insuffisants pour cet eleve")
@app.get("/health")
def health():
return {"status": "ok"}
@@ -87,12 +97,19 @@ def logout(response: Response):
@app.get("/students", response_model=list[schemas.StudentRead])
def list_students(db: Session = Depends(get_db)):
def list_students(
db: Session = Depends(get_db),
current_user: models.User = Depends(require_roles("teacher", "maintenance")),
):
return db.query(models.Student).order_by(models.Student.id.asc()).all()
@app.post("/students", response_model=schemas.StudentRead)
def create_student(payload: schemas.StudentCreate, db: Session = Depends(get_db)):
def create_student(
payload: schemas.StudentCreate,
db: Session = Depends(get_db),
current_user: models.User = Depends(require_roles("teacher", "maintenance")),
):
student = models.Student(**payload.model_dump())
db.add(student)
db.commit()
@@ -101,8 +118,50 @@ def create_student(payload: schemas.StudentCreate, db: Session = Depends(get_db)
return student
@app.post("/admin/student-accounts", response_model=schemas.StudentAccountResponse)
def create_student_account(
payload: schemas.StudentAccountCreate,
db: Session = Depends(get_db),
current_user: models.User = Depends(require_roles("teacher", "maintenance")),
):
username = payload.username.strip()
first_name = payload.first_name.strip()
if not username or not first_name:
raise HTTPException(status_code=400, detail="Prenom et identifiant obligatoires")
existing_user = db.query(models.User).filter_by(username=username).first()
if existing_user:
raise HTTPException(status_code=409, detail="Identifiant deja utilise")
student = models.Student(
first_name=first_name,
age=payload.age,
grade=payload.grade,
)
db.add(student)
db.commit()
db.refresh(student)
ensure_student_mastery(db, student)
user = models.User(
username=username,
password_hash=hash_password(payload.password),
role="student",
student_id=student.id,
)
db.add(user)
db.commit()
db.refresh(user)
return schemas.StudentAccountResponse(student=student, user=user)
@app.post("/session/start", response_model=schemas.ChatResponse)
def start_session(student_id: int, db: Session = Depends(get_db)):
def start_session(
student_id: int,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
ensure_student_access(current_user, student_id)
student = db.query(models.Student).filter_by(id=student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Élève introuvable")
@@ -118,7 +177,12 @@ def start_session(student_id: int, db: Session = Depends(get_db)):
@app.post("/chat", response_model=schemas.ChatResponse)
def chat(payload: schemas.ChatRequest, db: Session = Depends(get_db)):
def chat(
payload: schemas.ChatRequest,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
ensure_student_access(current_user, payload.student_id)
student = db.query(models.Student).filter_by(id=payload.student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Élève introuvable")
@@ -134,7 +198,10 @@ def chat(payload: schemas.ChatRequest, db: Session = Depends(get_db)):
@app.post("/transcribe")
async def transcribe(file: UploadFile = File(...)):
async def transcribe(
file: UploadFile = File(...),
current_user: models.User = Depends(get_current_user),
):
if not file.filename:
raise HTTPException(status_code=400, detail="Fichier audio manquant")
@@ -156,7 +223,10 @@ def get_tts_profiles():
@app.post("/tts")
def text_to_speech(payload: schemas.TTSRequest):
def text_to_speech(
payload: schemas.TTSRequest,
current_user: models.User = Depends(get_current_user),
):
try:
audio_bytes = synthesize_speech(payload.text, payload.profile_id)
except ValueError as exc:
@@ -168,7 +238,12 @@ def text_to_speech(payload: schemas.TTSRequest):
@app.get("/progress/{student_id}", response_model=schemas.ProgressResponse)
def get_progress(student_id: int, db: Session = Depends(get_db)):
def get_progress(
student_id: int,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
ensure_student_access(current_user, student_id)
student = db.query(models.Student).filter_by(id=student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Élève introuvable")
@@ -195,7 +270,12 @@ def get_progress(student_id: int, db: Session = Depends(get_db)):
@app.get("/assessment/next/{student_id}", response_model=schemas.AssessmentQuestionResponse)
def next_assessment(student_id: int, db: Session = Depends(get_db)):
def next_assessment(
student_id: int,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
ensure_student_access(current_user, student_id)
student = db.query(models.Student).filter_by(id=student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Élève introuvable")
@@ -205,7 +285,12 @@ def next_assessment(student_id: int, db: Session = Depends(get_db)):
@app.post("/assessment/answer", response_model=schemas.AssessmentAnswerResponse)
def answer_assessment(payload: schemas.AssessmentAnswerRequest, db: Session = Depends(get_db)):
def answer_assessment(
payload: schemas.AssessmentAnswerRequest,
db: Session = Depends(get_db),
current_user: models.User = Depends(get_current_user),
):
ensure_student_access(current_user, payload.student_id)
student = db.query(models.Student).filter_by(id=payload.student_id).first()
if not student:
raise HTTPException(status_code=404, detail="Élève introuvable")

View File

@@ -23,6 +23,7 @@ class UserRead(BaseModel):
username: str
role: str
student_id: int | None = None
student: StudentRead | None = None
class Config:
from_attributes = True
@@ -39,6 +40,16 @@ class LoginResponse(BaseModel):
user: UserRead
class StudentAccountCreate(StudentCreate):
username: str = Field(..., min_length=1)
password: str = Field(..., min_length=1)
class StudentAccountResponse(BaseModel):
student: StudentRead
user: UserRead
class ChatRequest(BaseModel):
student_id: int
message: str