import uuid from typing import Annotated from fastapi import APIRouter, Depends, Query, status from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import require_admin from app.database import get_db from app.models.user import User from app.schemas.chat import ContextFileResponse, UpdateContextRequest from app.schemas.skill import ( CreateSkillRequest, SkillListResponse, SkillResponse, UpdateSkillRequest, ) from app.schemas.admin import ( AdminUserCreateRequest, AdminUserListResponse, AdminUserResponse, AdminUserUpdateRequest, ) from app.schemas.setting import SettingResponse, SettingsListResponse, UpdateSettingRequest from app.services import context_service, skill_service, setting_service, admin_user_service router = APIRouter(prefix="/admin", tags=["admin"]) # --- Context --- @router.get("/context", response_model=ContextFileResponse | None) async def get_primary_context( _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): ctx = await context_service.get_primary_context(db) if not ctx: return None return ContextFileResponse.model_validate(ctx) @router.put("/context", response_model=ContextFileResponse) async def update_primary_context( data: UpdateContextRequest, admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): ctx = await context_service.upsert_primary_context(db, data.content, admin.id) return ContextFileResponse.model_validate(ctx) # --- Skills --- @router.get("/skills", response_model=SkillListResponse) async def list_general_skills( _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): skills = await skill_service.get_general_skills(db) return SkillListResponse(skills=[SkillResponse.model_validate(s) for s in skills]) @router.post("/skills", response_model=SkillResponse, status_code=status.HTTP_201_CREATED) async def create_general_skill( data: CreateSkillRequest, _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): skill = await skill_service.create_general_skill(db, **data.model_dump()) return SkillResponse.model_validate(skill) @router.patch("/skills/{skill_id}", response_model=SkillResponse) async def update_general_skill( skill_id: uuid.UUID, data: UpdateSkillRequest, _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): skill = await skill_service.update_general_skill(db, skill_id, **data.model_dump(exclude_unset=True)) return SkillResponse.model_validate(skill) @router.delete("/skills/{skill_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_general_skill( skill_id: uuid.UUID, _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): await skill_service.delete_general_skill(db, skill_id) # --- Users --- @router.get("/users", response_model=AdminUserListResponse) async def list_users( _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], limit: int = Query(default=50, le=200), offset: int = Query(default=0), ): users, total = await admin_user_service.list_users(db, limit, offset) return AdminUserListResponse( users=[AdminUserResponse.model_validate(u) for u in users], total=total, ) @router.post("/users", response_model=AdminUserResponse, status_code=status.HTTP_201_CREATED) async def create_user( data: AdminUserCreateRequest, _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): user = await admin_user_service.create_user( db, data.email, data.username, data.password, data.full_name, data.role, data.max_chats, ) return AdminUserResponse.model_validate(user) @router.patch("/users/{user_id}", response_model=AdminUserResponse) async def update_user( user_id: uuid.UUID, data: AdminUserUpdateRequest, _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): user = await admin_user_service.update_user(db, user_id, **data.model_dump(exclude_unset=True)) return AdminUserResponse.model_validate(user) # --- Settings --- @router.get("/settings", response_model=SettingsListResponse) async def get_settings( _admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): settings = await setting_service.get_all_settings(db) return SettingsListResponse(settings=[SettingResponse.model_validate(s) for s in settings]) @router.patch("/settings/{key}", response_model=SettingResponse) async def update_setting( key: str, data: UpdateSettingRequest, admin: Annotated[User, Depends(require_admin)], db: Annotated[AsyncSession, Depends(get_db)], ): setting = await setting_service.upsert_setting(db, key, data.value, admin.id) return SettingResponse.model_validate(setting)