Harden auth and persist report schedules

This commit is contained in:
dwindown
2026-06-06 19:40:32 +07:00
parent aaf64264f7
commit fd7989f673
18 changed files with 748 additions and 105 deletions

View File

@@ -10,6 +10,7 @@ Endpoints:
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
@@ -122,6 +123,27 @@ async def complete_session(
items = {item.id: item for item in items_result.scalars().all()}
# Process each answer
submitted_item_ids = [answer.item_id for answer in request.user_answers]
if len(submitted_item_ids) != len(set(submitted_item_ids)):
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Duplicate item answers are not allowed in a session completion",
)
existing_answers_result = await db.execute(
select(UserAnswer.item_id).where(UserAnswer.session_id == session.session_id)
)
existing_answered_item_ids = {row[0] for row in existing_answers_result.all()}
duplicate_existing_ids = sorted(set(submitted_item_ids) & existing_answered_item_ids)
if duplicate_existing_ids:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail={
"message": "One or more items were already answered for this session",
"item_ids": duplicate_existing_ids,
},
)
total_benar = 0
total_bobot_earned = 0.0
user_answer_records = []
@@ -234,7 +256,13 @@ async def complete_session(
await update_tryout_stats(db, website_id, session.tryout_id, nm)
# Commit all changes
await db.commit()
try:
await db.commit()
except IntegrityError as exc:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Duplicate item answer detected for this session",
) from exc
# Refresh to get updated relationships
await db.refresh(session)
@@ -261,7 +289,6 @@ async def complete_session(
id=ua.id,
item_id=ua.item_id,
response=ua.response,
is_correct=ua.is_correct,
time_spent=ua.time_spent,
bobot_earned=ua.bobot_earned,
scoring_mode_used=ua.scoring_mode_used,