from fastapi import APIRouter, HTTPException, Request from config.database import get_supabase_admin from middleware.admin_guard import get_admin_user from services.email import send_ticket_reply_to_user router = APIRouter(prefix="/api/cn-admin-nc-0947", tags=["admin"]) @router.get("/stats") async def get_stats(request: Request): await get_admin_user(request) db = get_supabase_admin() users = db.table("users").select("id", count="exact").execute() analyses = db.table("analyses").select("id", count="exact").execute() tickets = db.table("support_tickets").select("id", count="exact").eq("status", "open").execute() subs = db.table("challenge_submissions").select("id", count="exact").execute() return { "total_users": users.count or 0, "total_analyses": analyses.count or 0, "open_tickets": tickets.count or 0, "total_submissions": subs.count or 0, } @router.get("/users") async def get_users(request: Request, page: int = 1): await get_admin_user(request) db = get_supabase_admin() offset = (page - 1) * 50 result = db.table("users").select("*").order("created_at", desc=True).range(offset, offset + 49).execute() return result.data or [] @router.patch("/users/{user_id}/ban") async def ban_user(user_id: str, request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("users").update({"is_banned": body.get("is_banned", True)}).eq("id", user_id).execute() return {"message": "User ban status updated"} @router.patch("/users/{user_id}/role") async def change_role(user_id: str, request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("users").update({"role": body.get("role", "free")}).eq("id", user_id).execute() return {"message": "Role updated"} @router.delete("/users/{user_id}") async def delete_user(user_id: str, request: Request): await get_admin_user(request) db = get_supabase_admin() db.table("analyses").delete().eq("user_id", user_id).execute() db.table("challenge_submissions").delete().eq("user_id", user_id).execute() db.table("users").delete().eq("id", user_id).execute() try: db.auth.admin.delete_user(user_id) except Exception: pass return {"message": "User deleted"} @router.post("/challenges") async def create_challenge(request: Request): user = await get_admin_user(request) body = await request.json() db = get_supabase_admin() body["created_by"] = str(user.id) body.setdefault("status", "published") body.setdefault("starter_code", {}) body.setdefault("test_cases", []) result = db.table("challenges").insert(body).execute() return result.data[0] if result.data else {} @router.patch("/challenges/{challenge_id}") async def update_challenge(challenge_id: str, request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("challenges").update(body).eq("id", challenge_id).execute() return {"message": "Challenge updated"} @router.delete("/challenges/{challenge_id}") async def delete_challenge(challenge_id: str, request: Request): await get_admin_user(request) db = get_supabase_admin() db.table("challenges").delete().eq("id", challenge_id).execute() return {"message": "Challenge deleted"} @router.get("/tickets") async def get_tickets(request: Request, status: str = ""): await get_admin_user(request) db = get_supabase_admin() query = db.table("support_tickets").select("*").order("created_at", desc=True) if status: query = query.eq("status", status) return query.execute().data or [] @router.patch("/tickets/{ticket_id}/reply") async def reply_ticket(ticket_id: str, request: Request): await get_admin_user(request) body = await request.json() reply = body.get("reply", "") db = get_supabase_admin() ticket = db.table("support_tickets").select("*").eq("id", ticket_id).single().execute() if not ticket.data: raise HTTPException(status_code=404, detail="Ticket not found") db.table("support_tickets").update({"admin_reply": reply, "status": "resolved"}).eq("id", ticket_id).execute() try: await send_ticket_reply_to_user(ticket.data["user_email"], reply) except Exception: pass return {"message": "Reply sent"} @router.post("/blog") async def create_blog_post(request: Request): user = await get_admin_user(request) body = await request.json() db = get_supabase_admin() body["author_id"] = str(user.id) body.setdefault("status", "draft") result = db.table("blog_posts").insert(body).execute() return result.data[0] if result.data else {} @router.patch("/blog/{post_id}") async def update_blog_post(post_id: str, request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("blog_posts").update(body).eq("id", post_id).execute() return {"message": "Post updated"} @router.delete("/blog/{post_id}") async def delete_blog_post(post_id: str, request: Request): await get_admin_user(request) db = get_supabase_admin() db.table("blog_posts").delete().eq("id", post_id).execute() return {"message": "Post deleted"} @router.post("/announcements") async def create_announcement(request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("announcements").update({"is_active": False}).eq("is_active", True).execute() result = db.table("announcements").insert({"message": body.get("message"), "is_active": True}).execute() return result.data[0] if result.data else {} @router.get("/security-logs") async def get_security_logs(request: Request): await get_admin_user(request) db = get_supabase_admin() result = db.table("security_logs").select("*").order("created_at", desc=True).limit(200).execute() return result.data or [] @router.get("/settings") async def get_site_settings(request: Request): await get_admin_user(request) db = get_supabase_admin() result = db.table("site_settings").select("*").execute() return result.data or [] @router.patch("/settings/{key}") async def update_site_setting(key: str, request: Request): await get_admin_user(request) body = await request.json() db = get_supabase_admin() db.table("site_settings").update({"value": body.get("value")}).eq("key", key).execute() return {"message": f"Setting {key} updated"}