TESTING / services /api.py
HansTran's picture
Upload 21 files
0d872e9 verified
Raw
History Blame Contribute Delete
5.12 kB
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any
from uuid import uuid4
import requests
import streamlit as st
TIMEOUT_SECONDS = 20
def get_database_url() -> str:
url = st.secrets.get("FIREBASE_DATABASE_URL", "").strip().rstrip("/")
if not url:
raise RuntimeError(
"Missing FIREBASE_DATABASE_URL in .streamlit/secrets.toml or Hugging Face Space secrets."
)
return url
def get_auth_params() -> dict[str, str]:
token = st.secrets.get("FIREBASE_AUTH_TOKEN", "").strip()
return {"auth": token} if token else {}
def build_url(path: str) -> str:
clean_path = path.strip("/")
return f"{get_database_url()}/{clean_path}.json"
def validate_response(response: requests.Response) -> Any:
response.raise_for_status()
payload = response.json()
if isinstance(payload, dict) and payload.get("error"):
raise RuntimeError(str(payload["error"]))
return payload
def load_cards() -> list[dict[str, Any]]:
response = requests.get(
build_url("cards"),
params=get_auth_params(),
timeout=TIMEOUT_SECONDS,
)
payload = validate_response(response) or {}
if not isinstance(payload, dict):
return []
cards = []
for card_id, card in payload.items():
if not isinstance(card, dict):
continue
cards.append(
{
"id": str(card.get("id", card_id)),
"title": str(card.get("title", "")),
"startHour": str(card.get("startHour", "08")).zfill(2),
"startMinute": str(card.get("startMinute", "00")).zfill(2),
"endHour": str(card.get("endHour", "10")).zfill(2),
"endMinute": str(card.get("endMinute", "00")).zfill(2),
"createdAt": str(card.get("createdAt", "")),
"tabId": str(card.get("tabId", "")),
}
)
cards.sort(key=lambda item: item.get("createdAt", ""))
return cards
def sanitize_card(card: dict[str, Any], card_id: str | None = None) -> dict[str, str]:
now = datetime.now(timezone.utc).isoformat()
final_id = card_id or str(card.get("id") or card.get("clientKey") or uuid4())
return {
"id": final_id,
"title": str(card.get("title", "")).strip(),
"startHour": str(card.get("startHour", "08")).zfill(2),
"startMinute": str(card.get("startMinute", "00")).zfill(2),
"endHour": str(card.get("endHour", "10")).zfill(2),
"endMinute": str(card.get("endMinute", "00")).zfill(2),
"createdAt": str(card.get("createdAt") or now),
"tabId": str(card.get("tabId", "")).strip(),
}
def load_tabs() -> list[dict[str, str]]:
response = requests.get(
build_url("tabs"),
params=get_auth_params(),
timeout=TIMEOUT_SECONDS,
)
payload = validate_response(response) or {}
if not isinstance(payload, dict):
return []
tabs = []
for tab_id, tab in payload.items():
if not isinstance(tab, dict):
continue
tabs.append(
{
"id": str(tab.get("id", tab_id)),
"title": str(tab.get("title", "Untitled Tab")),
"createdAt": str(tab.get("createdAt", "")),
}
)
tabs.sort(key=lambda item: (item.get("createdAt", ""), item.get("title", "").lower()))
return tabs
def save_tab(tab: dict[str, Any]) -> dict[str, str]:
now = datetime.now(timezone.utc).isoformat()
tab_id = str(tab.get("id") or uuid4())
saved_tab = {
"id": tab_id,
"title": str(tab.get("title", "New Tab")).strip() or "New Tab",
"createdAt": str(tab.get("createdAt") or now),
}
response = requests.put(
build_url(f"tabs/{tab_id}"),
params=get_auth_params(),
json=saved_tab,
timeout=TIMEOUT_SECONDS,
)
validate_response(response)
return saved_tab
def save_card(card: dict[str, Any]) -> dict[str, Any]:
saved_card = sanitize_card(card)
response = requests.put(
build_url(f"cards/{saved_card['id']}"),
params=get_auth_params(),
json=saved_card,
timeout=TIMEOUT_SECONDS,
)
validate_response(response)
return saved_card
def update_card(card: dict[str, Any]) -> dict[str, Any]:
card_id = str(card.get("id", "")).strip()
if not card_id:
raise RuntimeError("Card ID is required for update.")
updated_card = sanitize_card(card, card_id=card_id)
response = requests.put(
build_url(f"cards/{card_id}"),
params=get_auth_params(),
json=updated_card,
timeout=TIMEOUT_SECONDS,
)
validate_response(response)
return updated_card
def delete_card(card_id: str) -> dict[str, Any]:
if not str(card_id).strip():
raise RuntimeError("Card ID is required for deletion.")
response = requests.delete(
build_url(f"cards/{card_id}"),
params=get_auth_params(),
timeout=TIMEOUT_SECONDS,
)
validate_response(response)
return {"success": True}