import os import io import base64 import json import datetime from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from google.oauth2.service_account import Credentials from googleapiclient.discovery import build from googleapiclient.http import MediaIoBaseUpload import qrcode app = FastAPI() # Allow frontend (your InfinityFree domain) to call API app.add_middleware( CORSMiddleware, allow_origins=["*"], # Restrict to your domain in production allow_methods=["*"], allow_headers=["*"], ) # Load secrets from environment (set in Hugging Face Secrets) SHEET_ID = os.getenv("GOOGLE_SHEET_ID") FOLDER_ID = os.getenv("GOOGLE_DRIVE_FOLDER_ID") SERVICE_ACCOUNT_INFO = json.loads(os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")) def get_services(): creds = Credentials.from_service_account_info( SERVICE_ACCOUNT_INFO, scopes=[ "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/spreadsheets" ] ) drive = build("drive", "v3", credentials=creds) sheets = build("sheets", "v4", credentials=creds) return drive, sheets class CertRequest(BaseModel): pdfBase64: str # base64 encoded PDF fileName: str # e.g., "John_Doe_certificate.pdf" name: str email: str = "" # optional, for future code: str # 9-character verification code @app.post("/api/upload-certificate") async def upload_certificate(req: CertRequest): try: drive, sheets = get_services() # Decode PDF pdf_bytes = base64.b64decode(req.pdfBase64) media = MediaIoBaseUpload(io.BytesIO(pdf_bytes), mimetype='application/pdf', resumable=False) # Upload to Drive file = drive.files().create( body={'name': req.fileName, 'parents': [FOLDER_ID]}, media_body=media, fields='id,webViewLink' ).execute() # Make it publicly viewable (anyone with link can view) drive.permissions().create( fileId=file['id'], body={'type': 'anyone', 'role': 'reader'} ).execute() # Append record to Google Sheet now = datetime.datetime.now().isoformat() values = [[ now, req.name, req.email, req.code, file['id'], file['webViewLink'], 'active' ]] sheets.spreadsheets().values().append( spreadsheetId=SHEET_ID, range='Certificates!A:G', # Assumes headers in row 1 valueInputOption='USER_ENTERED', body={'values': values} ).execute() return {"success": True, "fileUrl": file['webViewLink']} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/api/verify/{code}") async def verify(code: str): try: _, sheets = get_services() result = sheets.spreadsheets().values().get( spreadsheetId=SHEET_ID, range='Certificates!A:G' ).execute() rows = result.get('values', []) # Skip header row for row in rows[1:]: if len(row) >= 4 and row[3] == code: return { "valid": True, "name": row[1], "date": row[0], "fileUrl": row[5] } return {"valid": False} except Exception as e: raise HTTPException(status_code=500, detail=str(e)) @app.get("/health") async def health(): return {"status": "ok"}