"""Admin routes: dashboard, team management, generate invite link (login required).""" from fastapi import APIRouter, Depends, Query, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlmodel import Session from app.core.auth import require_admin from app.core.db import get_redis, get_session from app.managers.team import create_team, delete_team, get_all_teams, get_team_by_id, update_team router = APIRouter() @router.get("", response_class=HTMLResponse) @router.get("/", response_class=HTMLResponse) async def admin_index( request: Request, time_range: str = Query("past_14_days"), _: object = Depends(require_admin), ): """Admin dashboard shell — data is loaded asynchronously via /admin/api/stats.""" from app.managers.admin_stats import TIME_RANGES if time_range not in TIME_RANGES: time_range = "past_14_days" templates = request.app.state.templates return templates.TemplateResponse( request, "admin/index.html", {"current_page": "dashboard", "selected_time_range": time_range}, ) @router.get("/api/stats") async def admin_stats_api( time_range: str = Query("past_14_days"), session: Session = Depends(get_session), _: object = Depends(require_admin), ): """JSON stats API used by the dashboard for async data loading.""" from app.managers.admin_stats import get_admin_dashboard_stats, TIME_RANGES if time_range not in TIME_RANGES: time_range = "past_14_days" return get_admin_dashboard_stats(session, time_range=time_range, redis=get_redis()) @router.get("/teams", response_class=HTMLResponse) async def admin_teams_list( request: Request, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """List all teams with links to edit.""" teams = get_all_teams(session) templates = request.app.state.templates return templates.TemplateResponse( request, "admin/teams.html", {"teams": teams, "current_page": "teams"} ) @router.get("/teams/add", response_class=HTMLResponse) async def admin_team_add( request: Request, _: object = Depends(require_admin), ): """Show form to add a new team.""" templates = request.app.state.templates error = request.query_params.get("error") return templates.TemplateResponse( request, "admin/team_add.html", {"current_page": "teams", "error": error} ) @router.post("/teams/add") async def admin_team_add_submit( request: Request, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """Create a new team integration.""" form = await request.form() team_id = (form.get("team_id") or "").strip() team_name = (form.get("team_name") or "").strip() team_domain = (form.get("team_domain") or "").strip() team_token = (form.get("team_token") or "").strip() invite_link = (form.get("invite_link") or "").strip() if not all([team_id, team_name, team_domain, team_token, invite_link]): return RedirectResponse("/admin/teams/add?error=missing_fields", status_code=302) # Check if team_id already exists if get_team_by_id(session, team_id): return RedirectResponse("/admin/teams/add?error=duplicate_id", status_code=302) create_team( session, team_id=team_id, team_name=team_name, team_domain=team_domain, team_token=team_token, invite_link=invite_link, ) return RedirectResponse("/admin/teams", status_code=302) @router.get("/teams/{team_id}/edit", response_class=HTMLResponse) async def admin_team_edit( request: Request, team_id: str, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """Edit team form: team name, domain, invite link, optional token.""" team = get_team_by_id(session, team_id) if team is None: return RedirectResponse("/admin/teams", status_code=302) templates = request.app.state.templates return templates.TemplateResponse( request, "admin/team_edit.html", {"team": team, "current_page": "teams"} ) @router.post("/teams/{team_id}/edit") async def admin_team_edit_submit( request: Request, team_id: str, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """Process team edit form.""" team = get_team_by_id(session, team_id) if team is None: return RedirectResponse("/admin/teams", status_code=302) form = await request.form() team_name = (form.get("team_name") or "").strip() team_domain = (form.get("team_domain") or "").strip() invite_link_raw = form.get("invite_link") invite_link = (invite_link_raw.strip() if isinstance(invite_link_raw, str) else "") or None team_token = (form.get("team_token") or "").strip() or None update_team( session, team_id, team_name=team_name or team.team_name, team_domain=team_domain or team.team_domain, team_token=team_token, invite_link=invite_link, ) return RedirectResponse("/admin/teams", status_code=302) @router.post("/teams/{team_id}/delete") async def admin_team_delete( team_id: str, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """Delete a team. Redirects to teams list.""" delete_team(session, team_id) return RedirectResponse("/admin/teams", status_code=302) @router.get("/generate", response_class=HTMLResponse) async def admin_generate( request: Request, session: Session = Depends(get_session), _: object = Depends(require_admin), ): """Generate invite link page (one of the admin features).""" teams = get_all_teams(session) templates = request.app.state.templates return templates.TemplateResponse( request, "generate.html", {"teams": teams, "current_page": "generate"} )