fix(友链): 修复申请「通过不了/删不掉」;feat(评论): 通知按文章作者分派
## 友链自助申请(通过不了 / 删除不掉)
根因:admin.js 全局事件委托把 data-id 一律 parseInt,
而友链申请 id 是字符串(lamus5uptzcdam)→ NaN → JSON 成 {"id":null}
→ 后端 String(null||'') 为空 → 400 id and action required,查看/通过/拒绝全失效。
引入于 a74b3c71(10-04 归档 rss-robot 时;后台只有友链申请用字符串 id)。
- admin.js:纯数字才转数字,其余原样(评论/用户/站点按钮请求完全不变)
- admin.js:待审卡片加「删除」按钮
- links.ts:新增 action:'delete'(不受「已处理过」限制,处理过的也能删)
- links.ts:approve 改为先写友链再改状态 + URL 去重(重试幂等)
- links.ts:已是目标状态时返回 {ok:true,already:true},不再 409
—— 否则网络抖动后重试会让用户以为「怎么点都通不过」
## 评论通知按文章作者分派
编辑角色(女朋友)写的文章,评论通知改发给她,不再打扰博主。
不需要「文章→作者」同步表:Hugo 模板把 author_id 注入 artalkConfig,
artalk.js 已有的 fetch 拦截器把它塞进评论提交体,Worker 直接读。
- artalk.html:artalkConfig 增 pageAuthorId(老文章 0)
- artalk.js:提交评论时带上 author_id(读 window.artalkConfig,防 PJAX 过期)
- comments.ts:createComment 解析 author_id 并传给通知
- mail.ts:收件人改为「这篇文章的主人」——作者非管理员且开了邮件则发给他,
否则回退博主;已被回复通知过 / 作者本人评论自己的文章都不重复发
- mail.ts:增一行收件人决策日志,便于线上排查
验证:Worker tsc 通过;Hugo 构建通过;artalk.js 语法通过;
友链本地跑通(通过 200 → 再通过 already:true → 友链仅 1 条 → 删除 200 → 再删 404)。
This commit is contained in:
1 parent
68416366eb
commit
1b2e3d46f8
6 files changed
+124
-25
No files matched your search
@@ -1123,7 +1123,8 @@ async function viewLinks() {
|
||||
'<span class="c">' +
|
||||
'<button class="btn tiny" data-act="l-ap-view" data-id="' + esc(a.id) + '">查看</button>' +
|
||||
'<button class="btn tiny" data-act="l-ap-approve" data-id="' + esc(a.id) + '">通过</button>' +
|
||||
'<button class="btn tiny danger" data-act="l-ap-reject" data-id="' + esc(a.id) + '">拒绝</button>' +
|
||||
'<button class="btn tiny" data-act="l-ap-reject" data-id="' + esc(a.id) + '">拒绝</button>' +
|
||||
'<button class="btn tiny danger" data-act="l-ap-del" data-id="' + esc(a.id) + '">删除</button>' +
|
||||
'</span>' +
|
||||
'</div>').join('');
|
||||
appHtml =
|
||||
@@ -1906,7 +1907,12 @@ document.addEventListener('click', async (e) => {
|
||||
const el = e.target.closest('[data-act]');
|
||||
if (!el) return;
|
||||
const act = el.dataset.act;
|
||||
const id = el.dataset.id ? parseInt(el.dataset.id, 10) : 0;
|
||||
// ★ 不能无脑 parseInt:友链申请的 id 是字符串(la + base36,如 lamus5uptzcdam),
|
||||
// parseInt 会得到 NaN,序列化成 JSON 变成 null —— 后端只看到空 id,一律 400
|
||||
// 「id and action required」,表现就是「查看/通过/拒绝点了没反应」。
|
||||
// 规矩:纯数字才转数字,其余原样保留。
|
||||
const rawId = el.dataset.id || '';
|
||||
const id = /^\d+$/.test(rawId) ? parseInt(rawId, 10) : rawId;
|
||||
|
||||
// --- 通用
|
||||
if (act === 'modal-close') { closeModal(); return; }
|
||||
@@ -2071,6 +2077,14 @@ document.addEventListener('click', async (e) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (act === 'l-ap-del') {
|
||||
const a = (state.linkApps || []).find((x) => x.id === id);
|
||||
confirmBox('删除申请记录', '确定删除「' + (a ? a.name : '') + '」这条申请吗?只清掉申请记录,已有的友链不受影响。', async () => {
|
||||
await rssApi('/api/link-apply/review', { method: 'POST', body: { id, action: 'delete' } });
|
||||
toast('✓ 已删除申请记录'); await viewLinks();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// --- 友链
|
||||
if (act === 'l-reload') { el.dataset.busy = '1'; try { await viewLinks(); } finally { delete el.dataset.busy; } return; }
|
||||
if (act === 'l-add') { addLink(); return; }
|
||||
|
||||
Reference in new issue
Block a user