156 lines
4.8 KiB
Python
156 lines
4.8 KiB
Python
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
||
|
|
from fastapi.responses import HTMLResponse
|
||
|
|
from fastapi.templating import Jinja2Templates
|
||
|
|
from sqlalchemy import select
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
from pydantic import BaseModel
|
||
|
|
|
||
|
|
from ..database import get_db
|
||
|
|
from ..models import Set, Card, User
|
||
|
|
from ..auth import require_admin
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
|
||
|
|
async def require_admin_html(request: Request) -> User:
|
||
|
|
"""Admin check from cookie-based auth (HTML pages)."""
|
||
|
|
user = request.state.user
|
||
|
|
if not user or user.role != "admin":
|
||
|
|
raise HTTPException(status_code=401, detail="Admin login required")
|
||
|
|
return user
|
||
|
|
templates = Jinja2Templates(directory="app/templates")
|
||
|
|
|
||
|
|
|
||
|
|
class SetForm(BaseModel):
|
||
|
|
code: str
|
||
|
|
name: str
|
||
|
|
release_date: str | None = None
|
||
|
|
description: str | None = None
|
||
|
|
|
||
|
|
|
||
|
|
class CardForm(BaseModel):
|
||
|
|
number: str
|
||
|
|
name: str
|
||
|
|
type: str | None = None
|
||
|
|
rarity: str | None = None
|
||
|
|
hp: int | None = None
|
||
|
|
stage: str | None = None
|
||
|
|
description: str | None = None
|
||
|
|
image_url: str | None = None
|
||
|
|
|
||
|
|
|
||
|
|
# --- Admin pages ---
|
||
|
|
|
||
|
|
@router.get("/admin", response_class=HTMLResponse)
|
||
|
|
async def admin_dashboard(request: Request, user: User = Depends(require_admin_html)):
|
||
|
|
return templates.TemplateResponse("admin/dashboard.html", {"request": request, "user": user})
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/admin/sets", response_class=HTMLResponse)
|
||
|
|
async def admin_sets(request: Request, user: User = Depends(require_admin_html)):
|
||
|
|
return templates.TemplateResponse("admin/sets.html", {"request": request, "user": user})
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/admin/cards/{set_code}", response_class=HTMLResponse)
|
||
|
|
async def admin_cards(request: Request, set_code: str, user: User = Depends(require_admin_html)):
|
||
|
|
return templates.TemplateResponse("admin/cards.html", {"request": request, "user": user, "set_code": set_code})
|
||
|
|
|
||
|
|
|
||
|
|
# --- CRUD: Sets ---
|
||
|
|
|
||
|
|
@router.post("/api/admin/sets")
|
||
|
|
async def create_set(
|
||
|
|
data: SetForm,
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
exists = await db.execute(select(Set).where(Set.code == data.code.upper()))
|
||
|
|
if exists.scalar_one_or_none():
|
||
|
|
raise HTTPException(status_code=400, detail=f"Set '{data.code.upper()}' findes allerede")
|
||
|
|
|
||
|
|
s = Set(code=data.code.upper(), name=data.name, release_date=data.release_date, description=data.description)
|
||
|
|
db.add(s)
|
||
|
|
await db.commit()
|
||
|
|
await db.refresh(s)
|
||
|
|
return {"ok": True, "id": s.id, "code": s.code}
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/api/admin/sets")
|
||
|
|
async def list_sets_admin(
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
result = await db.execute(select(Set).order_by(Set.code))
|
||
|
|
sets = result.scalars().all()
|
||
|
|
return [{"id": s.id, "code": s.code, "name": s.name, "release_date": s.release_date or ""} for s in sets]
|
||
|
|
|
||
|
|
|
||
|
|
@router.delete("/api/admin/sets/{set_id}")
|
||
|
|
async def delete_set(
|
||
|
|
set_id: int,
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
s = await db.get(Set, set_id)
|
||
|
|
if not s:
|
||
|
|
raise HTTPException(status_code=404, detail="Set ikke fundet")
|
||
|
|
await db.delete(s)
|
||
|
|
await db.commit()
|
||
|
|
return {"ok": True}
|
||
|
|
|
||
|
|
|
||
|
|
# --- CRUD: Cards ---
|
||
|
|
|
||
|
|
@router.post("/api/admin/sets/{set_code}/cards")
|
||
|
|
async def create_card(
|
||
|
|
set_code: str,
|
||
|
|
data: CardForm,
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
result = await db.execute(select(Set).where(Set.code == set_code.upper()))
|
||
|
|
s = result.scalar_one_or_none()
|
||
|
|
if not s:
|
||
|
|
raise HTTPException(status_code=404, detail=f"Set '{set_code.upper()}' ikke fundet")
|
||
|
|
|
||
|
|
card = Card(
|
||
|
|
set_id=s.id, number=data.number, name=data.name,
|
||
|
|
type=data.type, rarity=data.rarity, hp=data.hp,
|
||
|
|
stage=data.stage, description=data.description, image_url=data.image_url,
|
||
|
|
)
|
||
|
|
db.add(card)
|
||
|
|
await db.commit()
|
||
|
|
await db.refresh(card)
|
||
|
|
return {"ok": True, "id": card.id, "full_code": card.full_code}
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/api/admin/sets/{set_code}/cards")
|
||
|
|
async def list_cards_admin(
|
||
|
|
set_code: str,
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
result = await db.execute(select(Set).where(Set.code == set_code.upper()))
|
||
|
|
s = result.scalar_one_or_none()
|
||
|
|
if not s:
|
||
|
|
raise HTTPException(status_code=404, detail="Set ikke fundet")
|
||
|
|
return [
|
||
|
|
{"id": c.id, "number": c.number, "name": c.name, "type": c.type or "",
|
||
|
|
"rarity": c.rarity or "", "hp": c.hp, "full_code": c.full_code}
|
||
|
|
for c in s.cards
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
@router.delete("/api/admin/cards/{card_id}")
|
||
|
|
async def delete_card(
|
||
|
|
card_id: int,
|
||
|
|
db: AsyncSession = Depends(get_db),
|
||
|
|
_: User = Depends(require_admin),
|
||
|
|
):
|
||
|
|
card = await db.get(Card, card_id)
|
||
|
|
if not card:
|
||
|
|
raise HTTPException(status_code=404, detail="Kort ikke fundet")
|
||
|
|
await db.delete(card)
|
||
|
|
await db.commit()
|
||
|
|
return {"ok": True}
|