From 429b2d965fb2ea96a8f0715413005749b626b3a6 Mon Sep 17 00:00:00 2001 From: uncle6me-web Date: Tue, 28 Jul 2026 23:54:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(t97+t114):=20=E5=BA=AB=E7=9B=AE=E9=8C=84?= =?UTF-8?q?=E5=8F=AA=E9=A1=AF=E7=A4=BA=E7=94=A8=E6=88=B6=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=80=B2=E4=BE=86=E7=9A=84=E5=BA=AB=E3=80=81=E6=8B=BF=E6=8E=89?= =?UTF-8?q?=E5=85=A9=E6=AE=B5=E5=BC=8F=E7=99=BB=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit leo 07-28 原話:「用戶沒加上的庫,不要自作主張給它加上」/「掃進來的就是要進目錄… 加入目錄這件小事還要分兩段做?…這是在攻打用戶嗎?根本是 attack」。 - portal.ts:859 auto 段濾掉 general(系統未標庫桶,非用戶的庫) - index.html:bootstrap 不再預埋 kb 庫;移除「登記到目錄」按鈕與 auto/registered 視覺分岔 驗證(總管 grep 真相源):登記到目錄=0、kb 種子=0、general 濾在; os-split 10/10+safejson 8/8 綠;portal-admin 1 紅=console HTML 搬遷陳舊測試 (stash 基線同紅,與本案無關)。(實作=子 CC;驗證+commit=總管) --- console-ui/public/portal/index.html | 45 +++------------------- cypher-executor/src/routes/portal.ts | 3 +- cypher-executor/tests/portal-admin.test.ts | 25 +++++++++++- 3 files changed, 31 insertions(+), 42 deletions(-) diff --git a/console-ui/public/portal/index.html b/console-ui/public/portal/index.html index d600cee..39d2fcd 100644 --- a/console-ui/public/portal/index.html +++ b/console-ui/public/portal/index.html @@ -943,8 +943,6 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { .then(function (b) { // 409=已 bootstrap 過(冪等視為就緒);其餘失敗誠實丟出 if (!b.ok && b.status !== 409) throw new Error(b.d.error || '初始化沒有成功,請再試一次'); - // 預設庫 kb 自動登記(leo:庫要自動出現,不是叫用戶去登記)—— - // 同步小幫手預設就寫進 kb 庫,這裡把登記簿先蓋好章;已存在(409/重複)不吵。 return post('/portal/login', { email: email, password: pw }); }); }) @@ -952,12 +950,6 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { if (!l.ok || !l.d.session_token) throw new Error(l.d.error || '帳號建好了,但自動登入沒成功——請用剛設定的帳密登入'); S.token = l.d.session_token; try { localStorage.setItem('arcrun_portal_session', S.token); } catch (e) { /* noop */ } - // 預設庫登記(用 portal session;失敗不擋進入) - return fetch(API_BASE + '/portal/admin/libraries', { - method: 'POST', - headers: Object.assign({ 'Content-Type': 'application/json' }, authHeaders()), - body: JSON.stringify({ name: 'kb', display_name: '知識庫', description: '同步小幫手預設寫入的庫' }) - }).catch(function () { /* 已存在或無權限都不擋 */ }); }) .then(function () { $('fs-submit').disabled = false; @@ -1476,29 +1468,18 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { } function renderAdminLibs() { - if (!adminLibs.length) { $('ad-libs').innerHTML = '
還沒有登記任何庫。未登記時整個系統視同單一 general 庫。
'; return; } + if (!adminLibs.length) { $('ad-libs').innerHTML = '
同步小幫手還沒送來任何庫。裝好小幫手並選好資料夾後,庫會自動出現在這裡。
'; return; } $('ad-libs').innerHTML = adminLibs.map(function (l) { var disabled = l.status === 'disabled'; - // t52:auto 庫=資料蓋章自動出現、還沒登記進登記簿(沒有 record_id)—— - // 那兩顆按鈕會帶空 id 打 API=按了就錯,改給「登記到目錄」一顆(leo 判準:不放死按鈕)。 - if (l.auto) { - return '
' + - '
' + - '' + esc(l.display_name || l.name) + '' + - '' + esc(l.name) + '' + - '啟用中同步自動出現
' + - '
' - + '這個庫來自同步小幫手的資料夾,已經可以搜尋與設權限。登記到目錄後可以改顯示名。
' + - '
' + - '
'; - } return '
' + '
' + '' + esc(l.display_name || l.name) + '' + '' + esc(l.name) + '' + - '' + (disabled ? '已停用' : '啟用中') + '' + + (l.auto + ? '啟用中同步自動出現' + : '' + (disabled ? '已停用' : '啟用中') + '') + '
' + - (l.description ? '
' + esc(l.description) + '
' : '') + + (!l.auto && l.description ? '
' + esc(l.description) + '
' : '') + '
'; }).join(''); } @@ -1614,22 +1595,6 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return { .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); }); return; } - // t52:把「自動出現的庫」正式登記進目錄(之後就能改顯示名) - if (act === 'lib-adopt') { - var lname = t.getAttribute('data-name') || ''; - if (!lname) return; - t.disabled = true; - adminApi('POST', '/portal/admin/libraries', { name: lname, display_name: lname, description: '同步小幫手看守的資料夾' }) - .then(function (x) { - t.disabled = false; - if (guard401(x.status)) return; - if (!x.ok && x.status !== 409) { toast(x.d.error || ('登記失敗(HTTP ' + x.status + ')')); return; } - toast('已登記到目錄'); - loadAdmin(); - }) - .catch(function (e) { t.disabled = false; toast(friendlyErr(e)); }); - return; - } }); // 一次性密碼關閉鈕(otpbox 動態生成,掛在容器上) $('ad-otp').addEventListener('click', function (ev) { diff --git a/cypher-executor/src/routes/portal.ts b/cypher-executor/src/routes/portal.ts index 2a99f49..84abaa9 100644 --- a/cypher-executor/src/routes/portal.ts +++ b/cypher-executor/src/routes/portal.ts @@ -855,7 +855,8 @@ portalRouter.get('/portal/admin/libraries', (c) => const body = (await res.json()) as { libraries?: string[] }; for (const name of body.libraries ?? []) { const n = String(name ?? '').trim(); - if (!n || known.has(n)) continue; + // general 是系統內部「未標庫」桶(未標記 entry 的 fallback),不在用戶目錄露臉 + if (!n || n === 'general' || known.has(n)) continue; known.add(n); out.push({ record_id: '', name: n, display_name: n, description: '資料同步時自動出現(可在此補顯示名)', status: 'active', graph_source: false, auto: true }); } diff --git a/cypher-executor/tests/portal-admin.test.ts b/cypher-executor/tests/portal-admin.test.ts index 37da814..d6aaa1e 100644 --- a/cypher-executor/tests/portal-admin.test.ts +++ b/cypher-executor/tests/portal-admin.test.ts @@ -376,12 +376,29 @@ describe('/portal/admin/libraries', () => { const res = await json('GET', '/portal/admin/libraries', undefined, { Authorization: 'Bearer tok-user' }); expect(res.status).toBe(403); }); + + it('GET auto 庫列表過濾 general(general 是系統桶,不在用戶目錄顯示)', async () => { + await seedAdminSession(); + mockGetRecord('rec_admin', adminValues()); + mockListByTemplate('portal_library', []); + fetchMock + .get(KBDB) + .intercept({ path: (p: string) => p.startsWith('/entries/libraries'), method: 'GET' }) + .reply(200, { libraries: ['kb', 'general', 'notes'] }); + const res = await json('GET', '/portal/admin/libraries', undefined, { Authorization: 'Bearer tok-admin' }); + expect(res.status).toBe(200); + const data = (await res.json()) as { libraries: { name: string; auto?: boolean }[] }; + const names = data.libraries.map((l) => l.name); + expect(names).toContain('kb'); + expect(names).toContain('notes'); + expect(names).not.toContain('general'); + }); }); // ═══════════════ 6. /portal HTML 殼(P4 admin 頁後紅線不回退)═══════════════ describe('GET /portal(P4 admin 頁 HTML 殼)', () => { - it('admin view 存在;仍零租戶字串、零 /kbdb/、零 X-Arcrun-API-Key、零 Mira', async () => { + it('admin view 存在;仍零租戶字串、零 /kbdb/、零 X-Arcrun-API-Key、零 Mira;無 kb 種子、無登記到目錄', async () => { const res = await SELF.fetch('http://localhost/portal'); expect(res.status).toBe(200); const html = await res.text(); @@ -393,5 +410,11 @@ describe('GET /portal(P4 admin 頁 HTML 殼)', () => { expect(html).not.toContain('/kbdb/'); expect(html).not.toContain('X-Arcrun-API-Key'); expect(html).not.toContain('Mira'); + // t97a:bootstrap 後不再預埋 kb 庫 + expect(html).not.toContain('"name": "kb"'); + expect(html).not.toContain("name: 'kb'"); + // t114:無「登記到目錄」按鈕 + expect(html).not.toContain('lib-adopt'); + expect(html).not.toContain('登記到目錄'); }); });