feat: 卡片编辑/删除按钮 + dnfs 管理员豁免

- dnfs.js: 卡片底部新增编辑/删除按钮,复用下方表单支持编辑模式
  (startEdit/cancelEdit/updateNode/deleteChild),stopPropagation 防误触
- theme.css: 新增 card-actions/act-btn 按钮样式,编辑橙色/删除红色软底
- dnfs.py: ADMIN_USERS 统一管理豁免名单(admin, admin@qsont.me),
  update_note 新增管理员豁免,delete_note 同步改用名单
- dnfs/README.md: 同步更新所有权豁免说明
This commit is contained in:
qing committed 2026-07-29 11:22:30 +08:00
1 parent a0f6a14b5d
commit ace98caff6
4 files changed
+193 -7

No files matched your search

+2 -2
View File
@@ -44,7 +44,7 @@ Authorization: Bearer <base64_payload>_<rsa_sign>
- payload 中取 `user` 字段作为操作者,写入 `owner`。
- `delete_note` 与 `update_note` 校验所有权:
- 节点 `owner` 必须等于当前 `user`,否则 `403`;
- **例外**:`user == 'admin'` 可删除任意节点(管理员豁免,仅 delete)。
- **例外**:管理员账号(`ADMIN_USERS`:`admin`、`admin@qsont.me`)可删除/更新任意节点。
- `get_notes` 不需要鉴权。
## 接口文档
@@ -154,7 +154,7 @@ curl -X POST http://localhost:8006/delete_note \
更新节点的 pid / title / content(pid 变更可用于迁移节点)。流程:校验参数 → 校验 Token → 校验所有权 → AI 内容审核 → 更新。
仅节点 owner 可更新;update 路径下 **admin 不享豁免**(与 delete 不同)。
仅节点 owner 可更新;管理员账号(`ADMIN_USERS`:`admin`、`admin@qsont.me`)豁免,可更新任意节点。
**Request**
+8 -4
View File
@@ -37,6 +37,9 @@ from pymsg import MsgClient # noqa: E402
_DBV2_ADDR = '127.0.0.1'
_DBV2_PORT = 8005
# 管理员账号:删除/更新节点时豁免所有权校验(保留旧的 'admin' 以兼容历史数据)
ADMIN_USERS = ('admin', 'admin@qsont.me')
def _call_dbv2(payload: dict, timeout: int = 10) -> dict:
"""通过 pymsg 短连接调用 dbv2 数据库服务。
自动注入 ``_route: "execute"``。
@@ -325,7 +328,7 @@ def delete_note():
data = _call_dbv2(select_payload)
notes = data['data']
if not info['user'] == 'admin':
if info['user'] not in ADMIN_USERS:
if not len(notes) == 1 or not notes[0]['owner'] == info['user']:
logs.warning('dnfs', f'delete_note 所有权拒绝 id={note_id}', extra={'user': info['user']})
return jsonify({"error": 'It\'s not your note'}), 403
@@ -400,9 +403,10 @@ def update_note():
data = _call_dbv2(select_payload)
notes = data['data']
if not len(notes) == 1 or not notes[0]['owner'] == info['user']:
logs.warning('dnfs', f'update_note 所有权拒绝 id={id}', extra={'user': info['user']})
return jsonify({"error": 'It\'s not your note'}), 403
if info['user'] not in ADMIN_USERS:
if not len(notes) == 1 or not notes[0]['owner'] == info['user']:
logs.warning('dnfs', f'update_note 所有权拒绝 id={id}', extra={'user': info['user']})
return jsonify({"error": 'It\'s not your note'}), 403
# 内容审查
review = review_content(title + '\n' + content, 10)