feat: complete UI tasks, backend optimizations, coupon admin, user kundli

This commit is contained in:
2026-07-10 12:36:56 +05:30
parent 149d365218
commit d5199682e3
16 changed files with 782 additions and 78 deletions

View File

@@ -147,6 +147,14 @@ def submit_test_attempt(payload: Dict[str, Any], session: Session = Depends(get_
attempt_id_str = payload.get("id")
import uuid as _uuid
attempt_id = _uuid.UUID(attempt_id_str) if attempt_id_str else _uuid.uuid4()
# Check if this is a retake
existing_attempts_query = select(models.Attempt).where(
models.Attempt.user_id == user_id,
models.Attempt.source_id == source_id
)
existing_attempts = session.exec(existing_attempts_query).all()
is_retake = len(existing_attempts) > 0
attempt_record = models.Attempt(
id=attempt_id,
@@ -160,7 +168,8 @@ def submit_test_attempt(payload: Dict[str, Any], session: Session = Depends(get_
score=0,
total_questions=total_questions,
accuracy=0.0,
status="Submitted"
status="Submitted",
is_retake=is_retake
)
session.add(attempt_record)
session.flush()
@@ -522,7 +531,8 @@ async def upload_user_avatar(user_id: UUID, file: UploadFile = File(...), sessio
contents = await file.read()
file_extension = file.filename.split(".")[-1] if "." in file.filename else "jpg"
object_name = f"avatar_{user_id}.{file_extension}"
current_year = datetime.utcnow().year
object_name = f"avatars/{current_year}/avatar_{user_id}.{file_extension}"
public_url = upload_file(contents, object_name, content_type=file.content_type)
if not public_url:
@@ -579,7 +589,8 @@ async def upload_admin_test(
from worker import process_pdf_test
pdf_bytes = await file.read()
object_name = f"tests/{uuid.uuid4()}_{file.filename}"
current_year = datetime.utcnow().year
object_name = f"tests/{current_year}/{uuid.uuid4()}_{file.filename}"
url = storage.upload_file(pdf_bytes, object_name, content_type="application/pdf")
if not url:
raise HTTPException(status_code=500, detail="Failed to upload PDF to MinIO")
@@ -739,4 +750,58 @@ def delete_test(test_id: UUID, session: Session = Depends(get_session)):
# 7. Delete the Test itself
session.delete(test_obj)
session.commit()
return {"status": "success", "message": "Test and all associated questions, attempts, and mistakes deleted successfully"}
return {"status": "success", "message": "Test and all associated questions, attempts, and mistakes deleted successfully"}
# --- COUPON CRUD ROUTES ---
class CouponCreate(BaseModel):
code: str
discount_percent: float
max_discount_amount: float
is_active: bool = True
expires_at: Optional[datetime] = None
class CouponUpdate(BaseModel):
code: Optional[str] = None
discount_percent: Optional[float] = None
max_discount_amount: Optional[float] = None
is_active: Optional[bool] = None
expires_at: Optional[datetime] = None
@app.get("/api/admin/coupons", tags=["Admin"])
def get_admin_coupons(session: Session = Depends(get_session)):
coupons = session.exec(select(models.Coupon)).all()
return coupons
@app.post("/api/admin/coupons", tags=["Admin"])
def create_coupon(payload: CouponCreate, session: Session = Depends(get_session)):
coupon = models.Coupon(**payload.dict())
session.add(coupon)
session.commit()
session.refresh(coupon)
return coupon
@app.put("/api/admin/coupons/{coupon_id}", tags=["Admin"])
def update_coupon(coupon_id: UUID, payload: CouponUpdate, session: Session = Depends(get_session)):
coupon = session.get(models.Coupon, coupon_id)
if not coupon:
raise HTTPException(status_code=404, detail="Coupon not found")
update_data = payload.dict(exclude_unset=True)
for key, value in update_data.items():
setattr(coupon, key, value)
session.add(coupon)
session.commit()
session.refresh(coupon)
return coupon
@app.delete("/api/admin/coupons/{coupon_id}", tags=["Admin"])
def delete_coupon(coupon_id: UUID, session: Session = Depends(get_session)):
coupon = session.get(models.Coupon, coupon_id)
if not coupon:
raise HTTPException(status_code=404, detail="Coupon not found")
session.delete(coupon)
session.commit()
return {"status": "success", "message": "Coupon deleted successfully"}