|
| 1 | +import os |
| 2 | +from fastapi import FastAPI, HTTPException, Depends, Header |
| 3 | +from fastapi.middleware.cors import CORSMiddleware |
| 4 | +from sqlalchemy.orm import Session |
| 5 | +from starlette.responses import JSONResponse |
| 6 | +from datetime import datetime |
| 7 | +from . import models, schemas, crud, database, security |
| 8 | + |
| 9 | +app = FastAPI(title="MathCodeLab Certificate Verification API") |
| 10 | + |
| 11 | +# CORS |
| 12 | +ALLOWED_ORIGINS = os.getenv("ALLOWED_ORIGINS", "*").split(",") |
| 13 | +app.add_middleware( |
| 14 | + CORSMiddleware, |
| 15 | + allow_origins=[origin.strip() for origin in ALLOWED_ORIGINS], |
| 16 | + allow_credentials=True, |
| 17 | + allow_methods=["*"], |
| 18 | + allow_headers=["*"], |
| 19 | +) |
| 20 | + |
| 21 | +# Dependency |
| 22 | +get_db = database.get_db |
| 23 | + |
| 24 | +@app.get("/health") |
| 25 | +def health(): |
| 26 | + return {"status": "ok"} |
| 27 | + |
| 28 | +@app.get("/verify/{certificate_id}", response_model=schemas.CertificateVerificationResponse) |
| 29 | +def verify_certificate(certificate_id: str, db: Session = Depends(get_db)): |
| 30 | + cert = crud.get_certificate_by_public_id(db, certificate_id) |
| 31 | + if not cert: |
| 32 | + return JSONResponse(status_code=404, content={ |
| 33 | + "status": "invalid", |
| 34 | + "certificate_id": certificate_id, |
| 35 | + "message": "Certificate not found" |
| 36 | + }) |
| 37 | + if cert.status == "revoked": |
| 38 | + return { |
| 39 | + "status": "revoked", |
| 40 | + "certificate_id": cert.certificate_id, |
| 41 | + "revocation_reason": cert.revocation_reason or "" |
| 42 | + } |
| 43 | + return { |
| 44 | + "status": "valid", |
| 45 | + "certificate_id": cert.certificate_id, |
| 46 | + "student_name": cert.student_name, |
| 47 | + "course_title": cert.course_title, |
| 48 | + "completion_date": cert.completion_date, |
| 49 | + "duration_hours": cert.duration_hours, |
| 50 | + "issuer": cert.issuer, |
| 51 | + "instructor": cert.instructor, |
| 52 | + "verified_at": datetime.utcnow().isoformat() + "Z" |
| 53 | + } |
| 54 | + |
| 55 | +@app.post("/admin/certificates", response_model=schemas.CertificateOut) |
| 56 | +def create_certificate( |
| 57 | + cert_in: schemas.CertificateCreate, |
| 58 | + db: Session = Depends(get_db), |
| 59 | + api_key: str = Depends(security.verify_api_key) |
| 60 | +): |
| 61 | + return crud.create_certificate(db, cert_in) |
| 62 | + |
| 63 | +@app.patch("/admin/certificates/{certificate_id}/revoke", response_model=schemas.CertificateOut) |
| 64 | +def revoke_certificate( |
| 65 | + certificate_id: str, |
| 66 | + body: schemas.CertificateRevoke, |
| 67 | + db: Session = Depends(get_db), |
| 68 | + api_key: str = Depends(security.verify_api_key) |
| 69 | +): |
| 70 | + cert = crud.revoke_certificate(db, certificate_id, body.revocation_reason) |
| 71 | + if not cert: |
| 72 | + raise HTTPException(status_code=404, detail="Certificate not found") |
| 73 | + return cert |
0 commit comments