feat(content): 资讯增删改 + C端资讯中心(类别)端点
- ContentRepository:+update(部分字段)/get/delete
- schemas.operator:+ContentUpdateRequest(全可选)
- rbac_operator:+PUT/DELETE /admin/content/{id}(action:content.manage+审计)
- rbac_opc:+GET /opc/content?type=policy|news|skill|dynamic(仅published)、/opc/content/{id}(详情)
- 类别字典 policy/news/skill/dynamic
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -87,6 +87,28 @@ async def opc_policy(
|
||||
return {"items": await db.content.list(ctype="policy", status="published")}
|
||||
|
||||
|
||||
@router.get("/content", summary="资讯中心(按类别,已发布)")
|
||||
async def opc_content(
|
||||
type: str = "news",
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("opc_member")),
|
||||
):
|
||||
"""C 端资讯:type ∈ policy(政策)/news(资讯)/skill(技能)/dynamic(动态),仅 published。"""
|
||||
return {"items": await db.content.list(ctype=type, status="published")}
|
||||
|
||||
|
||||
@router.get("/content/{content_id}", summary="资讯详情")
|
||||
async def opc_content_detail(
|
||||
content_id: str,
|
||||
db: Database = Depends(get_db),
|
||||
_u: dict = Depends(require_roles("opc_member")),
|
||||
):
|
||||
item = await db.content.get(content_id)
|
||||
if item is None or item.get("status") != "published":
|
||||
raise HTTPException(status_code=404, detail="内容不存在")
|
||||
return item
|
||||
|
||||
|
||||
@router.get("/finance", summary="财务流水")
|
||||
async def opc_finance(
|
||||
db: Database = Depends(get_db),
|
||||
|
||||
@@ -11,7 +11,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..dependencies import get_db
|
||||
from ..schemas.operator import TaskCreateRequest, TaskUpdateRequest, TaskStatusRequest, TaskAssignRequest, TaskRecommendRequest, TaskSelectRecommendRequest, ProviderCreateRequest, ProviderUpdateRequest, ContentCreateRequest, ContentStatusRequest, ConfigUpdateRequest, ComputePingResponse, ComputeBalanceRequest, ComputeProvisionRequest, ComputeProvisionResponse, CourseCreateRequest, CourseStatusRequest, CourseUpdateRequest, ActivityCreateRequest, ActivityStatusRequest, ActivityUpdateRequest, BookingUpdateRequest, TestCreateRequest, TestStatusRequest
|
||||
from ..schemas.operator import TaskCreateRequest, TaskUpdateRequest, TaskStatusRequest, TaskAssignRequest, TaskRecommendRequest, TaskSelectRecommendRequest, ProviderCreateRequest, ProviderUpdateRequest, ContentCreateRequest, ContentStatusRequest, ContentUpdateRequest, ConfigUpdateRequest, ComputePingResponse, ComputeBalanceRequest, ComputeProvisionRequest, ComputeProvisionResponse, CourseCreateRequest, CourseStatusRequest, CourseUpdateRequest, ActivityCreateRequest, ActivityStatusRequest, ActivityUpdateRequest, BookingUpdateRequest, TestCreateRequest, TestStatusRequest
|
||||
from ...rbac import require_permission, require_roles, write_audit
|
||||
from ...infrastructure.repositories import Database
|
||||
from ...services import compute_client
|
||||
@@ -231,6 +231,37 @@ async def set_content_status(
|
||||
return item
|
||||
|
||||
|
||||
@router.put("/content/{content_id}", summary="编辑内容")
|
||||
async def update_content(
|
||||
content_id: str,
|
||||
req: ContentUpdateRequest,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:content.manage")),
|
||||
):
|
||||
item = await db.content.update(content_id, req.model_dump(exclude_unset=True, exclude_none=True))
|
||||
if item is None:
|
||||
raise HTTPException(status_code=404, detail="Content not found")
|
||||
await write_audit(db, action="content.update", resource="content", resource_id=content_id,
|
||||
detail=item.get("title", ""), user=actor, request=request)
|
||||
return item
|
||||
|
||||
|
||||
@router.delete("/content/{content_id}", summary="删除内容")
|
||||
async def delete_content(
|
||||
content_id: str,
|
||||
request: Request,
|
||||
db: Database = Depends(get_db),
|
||||
actor: dict = Depends(require_permission("action:content.manage")),
|
||||
):
|
||||
ok = await db.content.delete(content_id)
|
||||
if not ok:
|
||||
raise HTTPException(status_code=404, detail="Content not found")
|
||||
await write_audit(db, action="content.delete", resource="content", resource_id=content_id,
|
||||
detail=content_id, user=actor, request=request)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
# ── 系统配置 ──────────────────────────────────────────────────────────────
|
||||
@router.get("/config", summary="系统配置列表")
|
||||
async def list_config(
|
||||
|
||||
@@ -94,6 +94,15 @@ class ContentStatusRequest(BaseModel):
|
||||
status: str # published/offline/draft
|
||||
|
||||
|
||||
class ContentUpdateRequest(BaseModel):
|
||||
"""内容更新(字段全可选,仅更新传入项)。"""
|
||||
type: str | None = None # policy/news/skill/dynamic
|
||||
title: str | None = None
|
||||
summary: str | None = None
|
||||
body: str | None = None
|
||||
status: str | None = None
|
||||
|
||||
|
||||
|
||||
class ConfigUpdateRequest(BaseModel):
|
||||
value: str
|
||||
|
||||
Reference in New Issue
Block a user