From b4e1cf462a99e3dec63f17890ad36aab7094369b Mon Sep 17 00:00:00 2001 From: qing <1776177662@qq.com> Date: Thu, 30 Jul 2026 09:17:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(dnfs):=20get=5Fnotes=20=E6=8C=89=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=94=A8=E6=88=B7=E6=B3=A8=E5=85=A5=20can=5Foperate?= =?UTF-8?q?=EF=BC=8C=E5=89=8D=E7=AB=AF=E6=8C=89=E6=9D=83=E6=98=BE=E9=9A=90?= =?UTF-8?q?=E7=BC=96=E8=BE=91/=E5=88=A0=E9=99=A4=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dnfs get_notes 可选解析 Authorization(畸形 Token try 兜底),为每个节点 附带 can_operate 标记(is_admin 或 owner,口径与 delete/update 一致); dnfs.js 卡片编辑/删除按钮仅 can_operate === true 时渲染,未登录或无权隐藏。 --- dnfs/dnfs.py | 17 +++++++++++++++++ static/public/js/dnfs.js | 40 +++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/dnfs/dnfs.py b/dnfs/dnfs.py index 6fdd957..c9733fb 100755 --- a/dnfs/dnfs.py +++ b/dnfs/dnfs.py @@ -252,6 +252,23 @@ def get_notes(): result = notes['data'] + # 解析当前用户(可选):为每个节点附带操作权标记 can_operate, + # 前端据此显隐编辑/删除按钮。口径与 delete_note / update_note 一致: + # 管理员(is_admin)或节点 owner 有权。 + # get_notes 保持公开:未携带 Token 或 Token 解析失败时,所有节点一律无权。 + info = None + auth: str = request.headers.get('Authorization', '') + if auth.startswith('Bearer '): + try: + info = decode_token(auth[7:]) + except Exception: + info = None + + for note in result: + note['can_operate'] = bool( + info and (info.get('is_admin') or note.get('owner') == info.get('user')) + ) + logs.info('dnfs', f'get_notes 查询 pid={pid} 返回{len(result)}条', extra={'ip': request.remote_addr}) return jsonify(result), 200 diff --git a/static/public/js/dnfs.js b/static/public/js/dnfs.js index f5fcfa2..bd52ec1 100644 --- a/static/public/js/dnfs.js +++ b/static/public/js/dnfs.js @@ -560,16 +560,21 @@ function load_notes(main_node) { sts_div.appendChild(makeStatItem(ICON_EYE, item.visit_count)); sts_div.appendChild(makeStatItem(ICON_HEART, item.like_count)); sts_div.appendChild(makeStatItem(ICON_SHARE, item.share_count)); - // 卡片操作按钮:编辑 / 删除(stopPropagation 防止触发卡片自身的点入跳转) + // 卡片操作按钮:编辑 / 移动 / 删除(stopPropagation 防止触发卡片自身的点入跳转) + // 编辑与删除按 can_operate 显隐:操作权由后端 get_notes 按 owner / is_admin 判定, + // 与 delete_note / update_note 鉴权口径一致;未登录或无权时隐藏 let act_div = document.createElement('div'); act_div.className = "card-actions"; - let edit_btn = document.createElement('button'); - edit_btn.className = "act-btn act-edit"; - edit_btn.innerHTML = ICON_EDIT + "编辑"; - edit_btn.addEventListener('click', function(event) { - event.stopPropagation(); - startEdit(item); - }); + if (item.can_operate === true) { + let edit_btn = document.createElement('button'); + edit_btn.className = "act-btn act-edit"; + edit_btn.innerHTML = ICON_EDIT + "编辑"; + edit_btn.addEventListener('click', function(event) { + event.stopPropagation(); + startEdit(item); + }); + act_div.appendChild(edit_btn); + } let move_btn = document.createElement('button'); move_btn.className = "act-btn act-move"; move_btn.innerHTML = ICON_MOVE + "移动"; @@ -577,16 +582,17 @@ function load_notes(main_node) { event.stopPropagation(); startMove(item); }); - let del_btn = document.createElement('button'); - del_btn.className = "act-btn act-del"; - del_btn.innerHTML = ICON_TRASH + "删除"; - del_btn.addEventListener('click', function(event) { - event.stopPropagation(); - deleteChild(item.id); - }); - act_div.appendChild(edit_btn); act_div.appendChild(move_btn); - act_div.appendChild(del_btn); + if (item.can_operate === true) { + let del_btn = document.createElement('button'); + del_btn.className = "act-btn act-del"; + del_btn.innerHTML = ICON_TRASH + "删除"; + del_btn.addEventListener('click', function(event) { + event.stopPropagation(); + deleteChild(item.id); + }); + act_div.appendChild(del_btn); + } ttl.appendChild(wrt_div); ttl.appendChild(sts_div); let ctt = document.createElement('p');