"""admin 广告配置:读/写穿山甲 app_id / 各场景广告位ID / 验签密钥 / 各场景开关。 存在 app_config 表的 ad_config dict(见 repositories/app_config.get_ad_config/set_ad_config)。 客户端经 /api/v1/platform/ad-config 拉取(不含 reward_mkey)。权限 operator/finance + 审计。 """ from __future__ import annotations from typing import Annotated from fastapi import APIRouter, Depends, Request from app.admin.audit import write_audit from app.admin.deps import AdminDb, get_client_ip, get_current_admin, require_role from app.admin.schemas.ad_config import AdConfigOut, AdConfigUpdate from app.models.admin import AdminUser from app.repositories import app_config router = APIRouter( prefix="/admin/api/ad-config", tags=["admin-ad-config"], dependencies=[Depends(get_current_admin)], ) @router.get("", response_model=AdConfigOut, summary="广告配置(穿山甲ID/验签密钥/各场景开关)") def get_ad_config(db: AdminDb) -> AdConfigOut: return AdConfigOut(**app_config.get_ad_config(db)) @router.patch("", response_model=AdConfigOut, summary="改广告配置(部分更新,带审计)") def update_ad_config( body: AdConfigUpdate, request: Request, admin: Annotated[AdminUser, Depends(require_role("operator", "finance"))], db: AdminDb, ) -> AdConfigOut: data = body.model_dump(exclude_none=True) app_config.set_ad_config(db, data, admin_id=admin.id, commit=False) # 审计只记改了哪些字段,不记 mkey 明文(机密) write_audit( db, admin, action="ad_config.set", target_type="ad_config", target_id="ad_config", detail={"changed": sorted(data.keys())}, ip=get_client_ip(request), commit=False, ) db.commit() return AdConfigOut(**app_config.get_ad_config(db))