Files
mce/templates/MetaLab-2026/static/js/settings-notify.js
Victor_Jay 2449a27eb5
Some checks failed
CI / Lint + Build (push) Has been cancelled
refactor: CSP nonce替代unsafe-inline, HSTS始终启用, router/api拆分, 管理后台+用户设置页拆分, DB健康降级, 时区配置, UID统一解析, CI接入
审计修复:
- CSP: unsafe-inline移除, nonce替代; unsafe-eval保留供Vditor使用
- HSTS: 始终启用(不再依赖release模式)
- Controller Exp: common.GetGinExp包装, 不再直接读context
- UID解析: common.ParseUIDParam统一, follow/admin controller改用

重构:
- router/api.go(198行)拆为7个域文件: auth/settings/posts/comments/reactions/social/studio
- 管理后台站点设置: 单页拆为4个子页(brand/security/registration/content)+子菜单
- 前台用户设置页: 1201行拆为6个独立模板+6个独立JS文件

新增:
- DB健康检测中间件(middleware/db_health.go): 5s ping+降级页面
- 时区配置: config.yaml server.timezone→time.Local初始化
- .gitea/workflows/ci.yml: strict模式CI流水线
2026-06-22 03:06:24 +08:00

91 lines
4.2 KiB
JavaScript

(function(){'use strict';
<script nonce="{{.CSPNonce}}">
(function () {
'use strict';
var toastEl = document.getElementById('settingsToast');
var toastTimer = null;
function showSettingsToast(msg, isError) {
if (!toastEl) return;
clearTimeout(toastTimer);
toastEl.textContent = msg;
toastEl.className = 'settings-toast' + (isError ? ' error' : '');
void toastEl.offsetWidth;
toastEl.classList.add('show');
toastTimer = setTimeout(function () {
toastEl.classList.remove('show');
}, 5000);
}
// ===== 通知偏好 Tab =====
(function () {
var bodyEl = document.getElementById('notifyPrefsBody');
if (!bodyEl) return;
function loadPrefs() {
fetch('/api/settings/notify-prefs')
.then(function (r) { return r.json(); })
.then(function (d) {
if (!d.success || !d.data) {
bodyEl.innerHTML = '<div class="energy-log-empty">加载失败</div>';
return;
}
var prefs = d.data;
var items = [
{ key: 'comment', label: '评论通知', desc: '有人评论我的文章时通知我' },
{ key: 'comment_reply', label: '回复通知', desc: '有人回复我的评论时通知我' },
{ key: 'like_aggregated', label: '点赞通知', desc: '每日汇总的点赞通知' },
{ key: 'follow', label: '关注通知', desc: '有人关注我时通知我' }
];
var html = '';
items.forEach(function (item) {
var checked = prefs[item.key] ? 'checked' : '';
html += '<div class="notify-pref-row">'
+ '<div class="notify-pref-info">'
+ '<span class="notify-pref-label">' + item.label + '</span>'
+ '<span class="notify-pref-desc">' + item.desc + '</span>'
+ '</div>'
+ '<label class="notify-pref-toggle">'
+ '<input type="checkbox" class="notify-pref-cb" data-key="' + item.key + '" ' + checked + '>'
+ '<span class="notify-pref-slider"></span>'
+ '</label>'
+ '</div>';
});
bodyEl.innerHTML = html;
// 绑定切换事件
bodyEl.querySelectorAll('.notify-pref-cb').forEach(function (cb) {
cb.addEventListener('change', function () {
var key = cb.getAttribute('data-key');
var enabled = cb.checked;
var xhr = new XMLHttpRequest();
xhr.open('PUT', '/api/settings/notify-prefs', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
try {
var r = JSON.parse(xhr.responseText);
if (r.success) {
showSettingsToast('通知偏好已更新');
} else {
showSettingsToast(r.message || '更新失败', true);
cb.checked = !enabled;
}
} catch (e) {
showSettingsToast('更新失败', true);
cb.checked = !enabled;
}
};
xhr.send(JSON.stringify({ key: key, enabled: enabled }));
});
});
})
.catch(function () {
bodyEl.innerHTML = '<div class="energy-log-empty">加载失败</div>';
});
}
loadPrefs();
})();
})();