feat(权限): 收敛普通账号写权限至本人凭证
将调度时刻、采集参数等实例级配置收归管理员,普通账号仅可维护本人 Cookie 与 User-Agent。 新增 config.writable_by 作为唯一写权限入口,set_setting 强制全局键落到 user_id=0, 消除「管理员改了只有自己生效」的静默缺陷。新增 tools/check_docs.py 文档自检, smoke 断言扩至 215 项、check_live 扩至 122 项并支持普通账号越权验收, 忽略 backups/、data/*.bak* 与 legacy-v1/,版本升至 v1.3.0。
这个提交包含在:
@@ -190,7 +190,9 @@
|
||||
<div class="navback">
|
||||
<a class="abtn" href="/">← 返回后台</a>
|
||||
<a class="abtn" href="/records">数据明细</a>
|
||||
<a class="abtn" href="/logs">日志管理</a>
|
||||
<!-- 日志管理仅管理员可达:角色由 /api/manifest 的 role 字段带回,
|
||||
非管理员时在 boot() 里隐藏,避免给出会 403 的死链 -->
|
||||
<a class="abtn" id="abtnLogs" href="/logs" hidden>日志管理</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta" data-page-node-id="4jmZuGBGC8JQmVAE2IOJ7H">
|
||||
@@ -1272,6 +1274,9 @@
|
||||
$("#err").style.display = "none";
|
||||
const mf = src.manifest || {};
|
||||
$("#mUpdate").textContent = mf.generated || "-";
|
||||
// 管理员入口按角色显隐(大屏是静态页,拿不到 Jinja 上下文)
|
||||
const logsBtn = $("#abtnLogs");
|
||||
if (logsBtn) logsBtn.hidden = (mf.role !== "admin");
|
||||
initDays();
|
||||
bind();
|
||||
renderScope();
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
var out = {};
|
||||
Array.prototype.forEach.call(form.elements, function (el) {
|
||||
if (!el.name || el.type === "submit" || el.name === "_csrf") return;
|
||||
// 只读控件必须跳过:disabled 的 input 仍然出现在 form.elements 里,
|
||||
// 若被一起提交,服务端会因为「越权修改只读项」把**整单**拒掉 ——
|
||||
// 表现成「改了 A 却提示 A 不能改」,很难归因。
|
||||
// 注意:fieldset 被 disable 时子元素自身的 disabled 仍是 false,
|
||||
// 所以还要往上找祖先 fieldset。
|
||||
if (el.disabled || (el.closest && el.closest("fieldset[disabled]"))) return;
|
||||
if (el.type === "checkbox") { out[el.name] = el.checked ? "1" : "0"; return; }
|
||||
if (el.type === "radio") { if (el.checked) out[el.name] = el.value; return; }
|
||||
out[el.name] = el.value;
|
||||
@@ -72,7 +78,7 @@
|
||||
function hintOf(j) {
|
||||
if (!j) return "";
|
||||
if (j.error === "cookie_expired") return "\n请到「配置管理」更新 Cookie 与 User-Agent(两者须取自同一次浏览器请求)。";
|
||||
if (j.error === "busy") return "\n已有采集在进行,可稍后重试,或到「日志管理」查看进度。";
|
||||
if (j.error === "busy") return "\n已有采集在进行,可稍后重试;「任务管理」里能看到本次运行的状态。";
|
||||
if (j.errors && j.errors.length) return "\n" + j.errors.join("\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户