feat(rbac): 落地 Wagtail Group + GroupPagePermission/GroupCollectionPermission/Snippet 权限体系

新增 setup_rbac_groups 幂等管理命令,按设计方案 §2.8 矩阵创建 5 个 Group(站点管理员/编辑/审核员/作者/查看者),配置页面/图片文档/Snippet/用户管理权限;Author 仅编辑自己页面利用 Wagtail 内置 OwnershipPermissionPolicy 实现,无需自定义 hook;新增 7 个单元测试,pytest 33→40 全部通过。
This commit is contained in:
2026-08-07 17:07:39 +08:00
parent 3944e11330
commit f37571f395
3 changed files with 360 additions and 1 deletions
+11 -1
View File
@@ -280,6 +280,16 @@ Next.js 侧对应 `revalidateTag` API Route,收到 webhook 后失效对应 ISR
落地方式:使用 Wagtail 原生 `Group` + `GroupPagePermission` + `collections` 权限,不需要额外引入 RBAC 框架。
**已落地(`python manage.py setup_rbac_groups`,幂等命令,`apps/core/management/commands/setup_rbac_groups.py`):**
- Super Admin 直接对应 Django `is_superuser=True`,不建单独 Group;其余 5 个角色对应 5 个 Wagtail `Group`:站点管理员/编辑/审核员/作者/查看者。
- 页面权限(`GroupPagePermission`,挂载于页面树根节点 `depth=1`,适用于当前单站点部署):站点管理员拥有全部类型(add/change/publish/delete/bulk_delete/lock/unlock/view);编辑拥有 add/change/view(无 publish,创建的页面停留在草稿态等待发布);审核员拥有 change/publish/view(用于打开页面并执行发布,属于对“页面编辑=查看”矩阵条目的必要放宽);**作者仅拥有 add/view(不含 change**——利用 Wagtail 内置 `OwnershipPermissionPolicy`:只有 `add` 权限时,用户可创建新页面,且只能编辑/删除自己拥有(`owner`)的页面,天然满足“仅自己”要求,无需自定义 `wagtail_hooks`;查看者仅有 view。
- Snippet 权限(`TeamMember`/`Testimonial`/`Partner`/`NavigationMenu`/`FormDefinition`):站点管理员与编辑均为 add/change/delete/view,审核员仅 view,作者/查看者无权限。`Lead`(线索,含 PIPL 个人信息)出于数据保护考虑做了比矩阵更严格的收紧:仅站点管理员可管理,审核员仅 view,编辑/作者均不授予。`SiteSettings` 作为站点级单例配置仅站点管理员可 change/view。
- Collection(图片/文档)权限(`GroupCollectionPermission`,挂载于根 Collection):站点管理员 add/change/delete/choose/view;编辑与作者 add/change/choose/view(便于上传 StreamField 图片);审核员 choose/view;查看者无。
- 用户管理权限(`auth.add_user`/`change_user`/`delete_user`/`view_user`)仅授予站点管理员,对应矩阵“用户管理”列;“Django Admin”列不通过 Group 授予(Django Admin 访问由账号的 `is_staff` 属性决定,仅超级用户具备)。
- 简化说明:设计方案 §2.9 的 Workflow 审核模块尚未实现,因此“提交审核/审批发布”当前通过“编辑者无 publish、审核员/站点管理员有 publish”的权限差异形成审核闸门,而非正式的 Wagtail `Workflow`/`TaskState`;待 Workflow 模块落地后可在现有 Group 基础上叠加 `GroupApprovalTask`,无需重新设计权限组。
- 测试:`apps/core/tests.py` 新增 7 个用例覆盖 Group 创建、`access_admin` 授予、页面权限矩阵、Author 仅编辑自己页面、Lead 权限收紧、用户管理权限范围、命令幂等性。
### 2.9 工作流与内容审核
采用 Wagtail 5+ 内置 `Workflow` 模块,定义 `草稿 → 编辑自检 → 审核 → 通过 → 定时发布`,并在 `TaskState` 变更时通过企业微信机器人 Webhook 通知责任人(替代原文档 Slack 方案)。
@@ -376,9 +386,9 @@ CI 中要求单元测试覆盖率不低于 70%,核心 `apps/forms`(涉及线
- [x] Snippet`TeamMember`/`Testimonial`/`Partner`(简单 `@register_snippet`,均含 `order` 排序字段)、`NavigationMenu`+`NavigationMenuItem``ClusterableModel`+`Orderable`+`InlinePanel`,内部页面/外部链接二选一)、`SiteSettings``wagtail.contrib.settings` + `BaseSiteSetting`,公司信息/ICP备案/社交账号全局配置)均已创建;只读 API 挂载于 `/api/v1/custom/core/``team/`、`testimonials/`、`partners/`、`navigation/?name=`、`site-settings/`,限流 public 100/min);前端 `Header`/`Footer` 已接入 `NavigationMenu`/`SiteSettings`(接口不可用时回退静态内容),`TeamMember`/`Testimonial`/`Partner` 已提供 service 层,页面级展示留待对应 StreamField Block(见下)落地时接入
- [x] 预览模式:后端引入 `wagtail-headless-preview`0.9.0),`SEOablePage` 混入 `HeadlessPreviewMixin`(自动覆盖全部 6 个页面模型),新增自定义 `PagePreviewAPIViewSet` 挂载于 `/api/v2/page_preview/`;前端新增 `services/preview.service.ts``getPreviewOrFallback`/`fetchPreviewPage`/`resolvePreviewPath`)、`/preview`与 `/preview/disable` 两个 Route Handler(基于 Next.js Draft Mode + httpOnly cookie),并在首页/博客/产品/案例/解决方案详情页接入草稿优先逻辑,`layout.tsx` 新增预览模式提示条(含退出链接);`lint`/`build` 均验证通过,后端 31 个现有用例均通过(本次未新增自动化测试,仅依靠人工验证)
- [x] 剩余 6 个 StreamField Block`ProductCardBlock`/`PricingBlock`/`TimelineBlock`/`TeamBlock`/`TechStackBlock`/`VideoBlock`)已全部开发完成:`apps/core/blocks.py` 新增对应 Block 类并扩充 `COMMON_BLOCKS`(现共 14 个内容 Block + 1 个 `richtext`),因 Wagtail StreamField 会将 Block 结构写入迁移(`use_json_field=True` 不代表可跳过迁移),已为 blog/cases/home/products/solutions 五个 Page 模型生成并应用 `alter field body` 迁移;`TeamBlock` 复用 `FormBlock` 的 `get_api_representation` 覆写模式,新增 `TeamMemberChooserBlock(SnippetChooserBlock)` 展开 `TeamMember` 完整字段(含 `serialize_image` 复用),并补充对应的空值/展开单元测试(新增 2 个用例,后端共 33 个测试全部通过);前端 `types/wagtail.ts` 新增 6 个 Block 值类型与 `StreamFieldBlock` 联合类型分支,新建 6 个渲染组件(`ProductCardGrid`/`Pricing`/`Timeline`/`Team`/`TechStack`/`Video`)并接入 `BlockRenderer.tsx` 映射表,`lint`/`build` 均验证通过
- [x] RBAC 落地:`python manage.py setup_rbac_groups` 幂等命令创建 5 个 Wagtail Group(站点管理员/编辑/审核员/作者/查看者)并按 §2.8 矩阵配置 `GroupPagePermission`/`GroupCollectionPermission`/Snippet 与用户管理 `Permission`Author“仅自己”利用 Wagtail 内置 `OwnershipPermissionPolicy`(仅 add 权限)原生实现,无需自定义 hook;新增 7 个后端单元测试,全仓库 pytest 从 33 增至 40,全部通过
未完成(待规划排期):
- [ ] RBAC 落地(Wagtail `Group` + `GroupPagePermission` 实际配置)未开始
- [ ] 测试覆盖率仍不完整(已有基础单元测试,但集成测试、前端组件测试、E2E 均未编写,当前无 CI 流水线)
- [x] 生产安全 settings(§2.11 中 `SECURE_*`/CORS/CSRF 白名单等)已在 `production.py` 中逐项落实,并补充 `SECURE_PROXY_SSL_HEADER`(适配国内云厂商 SLB/CLB 边缘终止 TLS 场景);实际域名需在部署时通过 `.env` 填入
- [x] ICP 备案、页脚备案号展示、隐私政策内容、Cookie 同意条控件、表单 PIPL 数据删除权支持、字体/地图/验证码/CDN 国内可访问排查均已完成,§2.15 合规与本地化清单已全部完成