File size: 3,633 Bytes
0b56fac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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"}