feat(groups): allow renaming a group id

Add PUT /admin/api/groups/:id/rename (owner role) which re-points the group's routes, migrates the per-group webhook secret (tenant:{id}) and pending invites, and records an audit entry. The group editor's id field is now editable and the console renames first, then persists remaining edits under the new id.
This commit is contained in:
RhenCloud 2026-08-13 09:58:02 +08:00
parent 39bb639883
commit f4959eebf8
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
11 changed files with 372 additions and 53 deletions

View file

@ -32,6 +32,7 @@ https://your-worker.workers.dev
| `PUT` | `/admin/api/groups` | Admin session | Replace groups (super) |
| `GET` | `/admin/api/groups/:id/routes` | Admin session | List a group's routes |
| `PUT` | `/admin/api/groups/:id/routes` | Admin session | Replace a group's routes |
| `PUT` | `/admin/api/groups/:id/rename` | Admin session | Rename a group (owner); routes/secret/invites follow |
| `GET` | `/admin/api/me` | Admin session | Current session info |
| `GET` | `/admin/api/logs` | Admin session | Send logs (scoped) |
| `GET` | `/admin/api/logs/:id` | Admin session | Single send-log entry (scoped) |

View file

@ -58,28 +58,29 @@ WebHooker ships with a built-in config console at `/admin` for managing routes i
The console is served as an SPA at `/admin`; its tabs are deep-linkable via the URL path (`/admin/groups`, `/admin/logs`, `/admin/audit`). URLs outside `/admin` that do not match an endpoint below return a plain `404` instead of the console.
| Endpoint | Description |
| ----------------------------------------------- | ---------------------------------------------------- |
| `GET /admin` | Config console UI |
| `GET /admin/login` | Start GitHub OAuth sign-in |
| `GET /admin/logout` | Destroy session |
| `GET /admin/invite?token=…` | Accept a group invite (browser page) |
| `GET /admin/api/me` | Current session, scope, groups, and roles |
| `GET /admin/api/routes` | List routes (scoped to access) |
| `PUT /admin/api/routes` | Replace routes (owner/admin per group) |
| `GET /admin/api/groups` | List groups + the signed-in user's role each |
| `PUT /admin/api/groups` | Replace groups (super: all; owner: own only) |
| `GET /admin/api/groups/:id/routes` | List a group's routes |
| `PUT /admin/api/groups/:id/routes` | Replace a group's routes (owner/admin) |
| `GET /admin/api/logs` | Send logs (scoped to accessible routes) |
| `GET /admin/api/logs/:id` | Single send-log entry (scoped) |
| `POST /admin/api/groups/:id/invites` | Create an invite link (owner) |
| `GET /admin/api/groups/:id/invites` | List pending invites (owner) |
| `DELETE /admin/api/invites/:token` | Revoke an invite (owner) |
| `GET /admin/api/audit` | Audit log (scoped to accessible groups) |
| `GET /admin/api/groups/:id/webhook` | Group webhook endpoint info (owner) |
| `POST /admin/api/groups/:id/webhook/regenerate` | Generate/regenerate the group webhook secret (owner) |
| `DELETE /admin/api/groups/:id/webhook` | Disable the group webhook ingress (owner) |
| Endpoint | Description |
| ----------------------------------------------- | ----------------------------------------------------------------- |
| `GET /admin` | Config console UI |
| `GET /admin/login` | Start GitHub OAuth sign-in |
| `GET /admin/logout` | Destroy session |
| `GET /admin/invite?token=…` | Accept a group invite (browser page) |
| `GET /admin/api/me` | Current session, scope, groups, and roles |
| `GET /admin/api/routes` | List routes (scoped to access) |
| `PUT /admin/api/routes` | Replace routes (owner/admin per group) |
| `GET /admin/api/groups` | List groups + the signed-in user's role each |
| `PUT /admin/api/groups` | Replace groups (super: all; owner: own only) |
| `GET /admin/api/groups/:id/routes` | List a group's routes |
| `PUT /admin/api/groups/:id/routes` | Replace a group's routes (owner/admin) |
| `PUT /admin/api/groups/:id/rename` | Rename a group (owner); routes, webhook secret and invites follow |
| `GET /admin/api/logs` | Send logs (scoped to accessible routes) |
| `GET /admin/api/logs/:id` | Single send-log entry (scoped) |
| `POST /admin/api/groups/:id/invites` | Create an invite link (owner) |
| `GET /admin/api/groups/:id/invites` | List pending invites (owner) |
| `DELETE /admin/api/invites/:token` | Revoke an invite (owner) |
| `GET /admin/api/audit` | Audit log (scoped to accessible groups) |
| `GET /admin/api/groups/:id/webhook` | Group webhook endpoint info (owner) |
| `POST /admin/api/groups/:id/webhook/regenerate` | Generate/regenerate the group webhook secret (owner) |
| `DELETE /admin/api/groups/:id/webhook` | Disable the group webhook ingress (owner) |
The console lets you add, edit, delete, and toggle routes. Saved routes are written to KV `config:routes` immediately and the config cache is invalidated so the webhook pipeline picks them up on the next run.
@ -249,7 +250,7 @@ Routes belong to groups. Groups scope admin access and can restrict which events
| Field | Type | Required | Description |
| ---------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | string | Yes | Lowercase id (`a-z0-9`, `-`); referenced by each route's `groupId` |
| `id` | string | Yes | Lowercase id (`a-z0-9`, `-`); referenced by each route's `groupId`. Editable: renaming a group re-points its routes, per-group webhook secret and pending invites |
| `name` | string | Yes | Human-readable group name |
| `members` | object[] | No | `{ login, role }` entries; role is `owner`, `admin`, or `viewer` |
| `adminIds` | string[] | No | Deprecated legacy field; treated as `members` with role `owner` when present |
@ -273,7 +274,7 @@ Every group member has one of three roles. Super admins (`ADMIN_USER_IDS`) alway
### Access Model
- **Super admins** (`ADMIN_USER_IDS`) see and edit every group and all routes; only they can edit a group's `owners` list.
- **Owners** manage their group's routes, members, invites, name, `emoji`, and `providers`. They cannot remove the last owner or demote themselves when no other owner remains.
- **Owners** manage their group's routes, members, invites, name, id, `emoji`, and `providers`. They cannot remove the last owner or demote themselves when no other owner remains.
- **Admins** edit routes inside their groups and view logs; **viewers** get a read-only console.
- Group admin endpoints operate on a single group at a time via `/admin/api/groups/:id/routes`; `groupId` is forced from the path parameter.
- The `owners` list restricts which event actors (sender logins) the group's routes will dispatch at all.

View file

@ -32,6 +32,7 @@ https://your-worker.workers.dev
| `PUT` | `/admin/api/groups` | 管理员会话 | 替换分组(仅超级管理员) |
| `GET` | `/admin/api/groups/:id/routes` | 管理员会话 | 列出某分组的路由 |
| `PUT` | `/admin/api/groups/:id/routes` | 管理员会话 | 替换某分组的路由 |
| `PUT` | `/admin/api/groups/:id/rename` | 管理员会话 | 重命名分组owner路由/secret/邀请自动跟随 |
| `GET` | `/admin/api/me` | 管理员会话 | 当前会话信息 |
| `GET` | `/admin/api/logs` | 管理员会话 | 发送日志(按权限过滤) |
| `GET` | `/admin/api/logs/:id` | 管理员会话 | 单条发送日志(按权限过滤) |

View file

@ -58,28 +58,29 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
控制台以 SPA 形式挂在 `/admin`,各标签页可通过 URL 路径直达(`/admin/groups``/admin/logs``/admin/audit`)。`/admin` 之外且未匹配下方端点的 URL 直接返回 `404`,不会再被吞进控制台。
| 端点 | 说明 |
| ----------------------------------------------- | ----------------------------------------- |
| `GET /admin` | 配置控制台页面 |
| `GET /admin/login` | 开始 GitHub OAuth 登录 |
| `GET /admin/logout` | 销毁会话 |
| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) |
| `GET /admin/api/me` | 当前会话、权限范围、分组和角色 |
| `GET /admin/api/routes` | 列出路由(按权限过滤) |
| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin 权限) |
| `GET /admin/api/groups` | 列出分组 + 当前用户在各组的角色 |
| `PUT /admin/api/groups` | 替换分组超管全量owner 仅自己的组) |
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由owner/admin |
| `GET /admin/api/logs` | 发送日志(按可访问路由过滤) |
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
| `POST /admin/api/groups/:id/invites` | 创建邀请链接owner |
| `GET /admin/api/groups/:id/invites` | 列出待接受邀请owner |
| `DELETE /admin/api/invites/:token` | 撤销邀请owner |
| `GET /admin/api/audit` | 审计日志(按可访问分组过滤) |
| `GET /admin/api/groups/:id/webhook` | 分组 webhook 入口信息owner |
| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secretowner |
| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口owner |
| 端点 | 说明 |
| ----------------------------------------------- | -------------------------------------------------------- |
| `GET /admin` | 配置控制台页面 |
| `GET /admin/login` | 开始 GitHub OAuth 登录 |
| `GET /admin/logout` | 销毁会话 |
| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) |
| `GET /admin/api/me` | 当前会话、权限范围、分组和角色 |
| `GET /admin/api/routes` | 列出路由(按权限过滤) |
| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin 权限) |
| `GET /admin/api/groups` | 列出分组 + 当前用户在各组的角色 |
| `PUT /admin/api/groups` | 替换分组超管全量owner 仅自己的组) |
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由owner/admin |
| `PUT /admin/api/groups/:id/rename` | 重命名分组owner路由、webhook secret 与邀请自动跟随 |
| `GET /admin/api/logs` | 发送日志(按可访问路由过滤) |
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
| `POST /admin/api/groups/:id/invites` | 创建邀请链接owner |
| `GET /admin/api/groups/:id/invites` | 列出待接受邀请owner |
| `DELETE /admin/api/invites/:token` | 撤销邀请owner |
| `GET /admin/api/audit` | 审计日志(按可访问分组过滤) |
| `GET /admin/api/groups/:id/webhook` | 分组 webhook 入口信息owner |
| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secretowner |
| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口owner |
控制台支持新增、编辑、删除和开关路由。保存后立即写入 KV `config:routes` 并使配置缓存失效,下一次 webhook 处理即会生效。
@ -249,7 +250,7 @@ GitHub App 安装后,**所有**安装方的事件都会到达全局端点。
| 字段 | 类型 | 必需 | 说明 |
| ---------------- | -------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | string | 是 | 小写 id`a-z0-9``-`),由每条路由的 `groupId` 引用 |
| `id` | string | 是 | 小写 id`a-z0-9``-`),由每条路由的 `groupId` 引用。可修改:重命名分组会同步更新其路由、分组级 webhook secret 与待接受邀请 |
| `name` | string | 是 | 可读的分组名称 |
| `members` | object[] | 否 | `{ login, role }` 列表;角色为 `owner``admin``viewer` |
| `adminIds` | string[] | 否 | 已废弃的旧字段;存在时按 role 为 `owner` 的成员处理 |
@ -273,7 +274,7 @@ GitHub App 安装后,**所有**安装方的事件都会到达全局端点。
### 权限模型
- **超级管理员**`ADMIN_USER_IDS`)可查看和编辑所有分组及全部路由;只有他们能修改分组的 `owners` 列表。
- **owner** 管理本组的路由、成员、邀请、名称、`emoji``providers`;不能移除最后一位 owner也没有其他 owner 时不能把自己降级。
- **owner** 管理本组的路由、成员、邀请、名称、id、`emoji``providers`;不能移除最后一位 owner也没有其他 owner 时不能把自己降级。
- **admin** 可编辑本组路由并查看日志;**viewer** 只读控制台。
- 分组管理端点通过 `/admin/api/groups/:id/routes` 一次只操作一个分组;`groupId` 由路径参数强制指定。
- `owners` 列表限定哪些事件参与者(发送者登录名)的事件会被该分组的路由投递。