feat(api): add public RESTful API with API key auth and documentation page
This commit is contained in:
@@ -305,13 +305,16 @@ def settings_page(
|
||||
user: User = Depends(get_current_user_web),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
from app.models import ApiKey
|
||||
profiles = db.query(Profile).filter(Profile.user_id == user.id).all()
|
||||
profile_cards = {}
|
||||
for p in profiles:
|
||||
profile_cards[p.id] = db.query(Postcard).filter(Postcard.profile_id == p.id).all()
|
||||
api_keys = db.query(ApiKey).filter(ApiKey.user_id == user.id).order_by(ApiKey.created_at.desc()).all()
|
||||
return templates.TemplateResponse("settings.html", {
|
||||
"request": request, "user": user, "profiles": profiles,
|
||||
"profile_cards": profile_cards, "active_tab": active_tab,
|
||||
"api_keys": api_keys,
|
||||
})
|
||||
|
||||
|
||||
@@ -558,6 +561,13 @@ def postcard_create(
|
||||
if not profile:
|
||||
return _redirect("/profiles")
|
||||
|
||||
cn = card_number.strip()
|
||||
if db.query(Postcard).filter(Postcard.card_number == cn).first():
|
||||
return templates.TemplateResponse("postcard_form.html", {
|
||||
"request": request, "user": user, "profile": profile, "postcard": None,
|
||||
"error": _t("pc_list.duplicate", user.language),
|
||||
})
|
||||
|
||||
def _parse_dt(s: str) -> datetime | None:
|
||||
s = s.strip()
|
||||
if not s:
|
||||
@@ -638,6 +648,14 @@ def postcard_update(
|
||||
if not pc:
|
||||
return _redirect("/profiles")
|
||||
|
||||
cn = card_number.strip()
|
||||
dup = db.query(Postcard).filter(Postcard.card_number == cn, Postcard.id != postcard_id).first()
|
||||
if dup:
|
||||
return templates.TemplateResponse("postcard_form.html", {
|
||||
"request": request, "user": user, "profile": pc.profile, "postcard": pc,
|
||||
"error": _t("pc_list.duplicate", user.language),
|
||||
})
|
||||
|
||||
def _parse_dt(s: str) -> datetime | None:
|
||||
s = s.strip()
|
||||
if not s:
|
||||
@@ -821,3 +839,54 @@ def public_showcase(request: Request, username: str, db: Session = Depends(get_d
|
||||
"profile_groups": profile_groups, "sent_all": sent_all, "received_all": received_all,
|
||||
"lang": user.language,
|
||||
})
|
||||
|
||||
|
||||
# ---------- API Keys ----------
|
||||
|
||||
@router.post("/settings/apikeys/create")
|
||||
def apikey_create(
|
||||
request: Request,
|
||||
name: str = Form(""),
|
||||
user: User = Depends(get_current_user_web),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
from app.models import ApiKey
|
||||
from secrets import token_hex
|
||||
key = f"mv_{token_hex(24)}"
|
||||
ak = ApiKey(key=key, name=name.strip(), user_id=user.id)
|
||||
db.add(ak)
|
||||
db.commit()
|
||||
db.refresh(ak)
|
||||
# Re-render settings with apikeys tab active and the new key shown
|
||||
api_keys = db.query(ApiKey).filter(ApiKey.user_id == user.id).order_by(ApiKey.created_at.desc()).all()
|
||||
return templates.TemplateResponse("settings.html", {
|
||||
"request": request, "user": user, "active_tab": "apikeys",
|
||||
"api_keys": api_keys, "new_key": ak.key, "success": "API Key created",
|
||||
})
|
||||
|
||||
|
||||
@router.post("/settings/apikeys/{key_id}/delete")
|
||||
def apikey_delete(
|
||||
key_id: int,
|
||||
user: User = Depends(get_current_user_web),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
from app.models import ApiKey
|
||||
ak = db.query(ApiKey).filter(ApiKey.id == key_id, ApiKey.user_id == user.id).first()
|
||||
if ak:
|
||||
db.delete(ak)
|
||||
db.commit()
|
||||
return _redirect("/settings?tab=apikeys")
|
||||
|
||||
|
||||
# ---------- API Docs ----------
|
||||
|
||||
@router.get("/api/docs", response_class=HTMLResponse)
|
||||
def api_docs_page(
|
||||
request: Request,
|
||||
user: User = Depends(get_current_user_web),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
return templates.TemplateResponse("api_docs.html", {
|
||||
"request": request, "user": user,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user