76 lines
2.0 KiB
Python
76 lines
2.0 KiB
Python
import sqlite3
|
|
import os
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from pydantic import BaseModel
|
|
|
|
DB_PATH = os.environ.get("DB_PATH", "/srv/form-backend/submissions.db")
|
|
|
|
def get_db():
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA journal_mode=WAL")
|
|
return conn
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
db = get_db()
|
|
db.execute("""
|
|
CREATE TABLE IF NOT EXISTS submissions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
email TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
domain TEXT NOT NULL,
|
|
created_at TEXT NOT NULL
|
|
)
|
|
""")
|
|
db.commit()
|
|
db.close()
|
|
yield
|
|
|
|
app = FastAPI(title="Form Backend", lifespan=lifespan)
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
class Submission(BaseModel):
|
|
email: str
|
|
name: str
|
|
domain: str
|
|
|
|
@app.post("/api/submit", status_code=201)
|
|
def submit(data: Submission):
|
|
if not data.email or "@" not in data.email:
|
|
return {"error": "Invalid email"}, 422
|
|
if not data.name.strip():
|
|
return {"error": "Name required"}, 422
|
|
if not data.domain.strip():
|
|
return {"error": "Domain required"}, 422
|
|
|
|
db = get_db()
|
|
cur = db.execute(
|
|
"INSERT INTO submissions (email, name, domain, created_at) VALUES (?, ?, ?, datetime(\"now\"))",
|
|
(data.email.strip(), data.name.strip(), data.domain.strip())
|
|
)
|
|
db.commit()
|
|
row_id = cur.lastrowid
|
|
db.close()
|
|
return {"ok": True, "id": row_id}
|
|
|
|
@app.get("/api/submissions")
|
|
def list_submissions():
|
|
db = get_db()
|
|
rows = db.execute("SELECT id, email, name, domain, created_at FROM submissions ORDER BY id DESC LIMIT 100").fetchall()
|
|
db.close()
|
|
return [dict(r) for r in rows]
|
|
|
|
@app.get("/health")
|
|
def health():
|
|
return {"status": "ok"}
|