From b9ef48e5ddff4fac549a84ccd92e4382569c1f21 Mon Sep 17 00:00:00 2001 From: sunlei Date: Wed, 24 Jun 2026 11:12:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0NapCat=20WebUI?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/qqbot-init.sql | 2 ++ sql/refactor-v3/01-seed-core.sql | 2 ++ sql/refactor-v3/99-verify.sql | 9 ++++++ .../webui-gateway-contract.spec.ts | 32 +++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 test/modules/qqbot/napcat-webui-gateway/webui-gateway-contract.spec.ts diff --git a/sql/qqbot-init.sql b/sql/qqbot-init.sql index 9926196..20a1859 100644 --- a/sql/qqbot-init.sql +++ b/sql/qqbot-init.sql @@ -1031,12 +1031,14 @@ VALUES (2041700000000100401, 2041700000000100400, 'QqBotDashboard', '/qqbot/dashboard', '/qqbot/dashboard/list', NULL, 'QqBot:Dashboard:List', 'menu', '{"icon":"lucide:gauge","title":"工作台"}', 1, 0), (2041700000000100402, 2041700000000100400, 'QqBotAccount', '/qqbot/account', '/qqbot/account/list', NULL, 'QqBot:Account:List', 'menu', '{"icon":"lucide:radio-receiver","title":"账号连接"}', 1, 1), (2041700000000100410, 2041700000000100400, 'QqBotAccountConfig', '/qqbot/account/config', '/qqbot/account/config', NULL, 'QqBot:Account:Config', 'menu', '{"activePath":"/qqbot/account","hideInMenu":true,"title":"账号功能配置"}', 1, 0), + (2041700000000100412, 2041700000000100400, 'QqBotAccountNapcatWebui', '/qqbot/account/:accountId/napcat-webui', '/qqbot/account/napcat-webui/index', NULL, 'QqBot:Account:WebUI', 'menu', '{"activePath":"/qqbot/account","hideInMenu":true,"title":"NapCat WebUI"}', 1, 0), (2041700000000120401, 2041700000000100402, 'QqBotAccountCreate', NULL, NULL, NULL, 'QqBot:Account:Create', 'button', '{"title":"common.create"}', 1, 0), (2041700000000120402, 2041700000000100402, 'QqBotAccountEdit', NULL, NULL, NULL, 'QqBot:Account:Edit', 'button', '{"title":"common.edit"}', 1, 0), (2041700000000120403, 2041700000000100402, 'QqBotAccountDelete', NULL, NULL, NULL, 'QqBot:Account:Delete', 'button', '{"title":"common.delete"}', 1, 0), (2041700000000120404, 2041700000000100402, 'QqBotAccountKick', NULL, NULL, NULL, 'QqBot:Account:Kick', 'button', '{"title":"断开连接"}', 1, 0), (2041700000000120405, 2041700000000100402, 'QqBotAccountRefreshLogin', NULL, NULL, NULL, 'QqBot:Account:RefreshLogin', 'button', '{"title":"更新登录"}', 1, 0), (2041700000000120406, 2041700000000100402, 'QqBotAccountConfigButton', NULL, NULL, NULL, 'QqBot:Account:Config', 'button', '{"title":"配置"}', 1, 0), + (2041700000000120407, 2041700000000100402, 'QqBotAccountWebUI', NULL, NULL, NULL, 'QqBot:Account:WebUI', 'button', '{"title":"NapCat WebUI"}', 1, 0), (2041700000000100403, 2041700000000100400, 'QqBotRule', '/qqbot/rule', '/qqbot/rule/list', NULL, 'QqBot:Rule:List', 'menu', '{"icon":"lucide:workflow","title":"自动回复规则"}', 1, 2), (2041700000000120411, 2041700000000100403, 'QqBotRuleCreate', NULL, NULL, NULL, 'QqBot:Rule:Create', 'button', '{"title":"common.create"}', 1, 0), (2041700000000120412, 2041700000000100403, 'QqBotRuleEdit', NULL, NULL, NULL, 'QqBot:Rule:Edit', 'button', '{"title":"common.edit"}', 1, 0), diff --git a/sql/refactor-v3/01-seed-core.sql b/sql/refactor-v3/01-seed-core.sql index e33cad1..fa5fd62 100644 --- a/sql/refactor-v3/01-seed-core.sql +++ b/sql/refactor-v3/01-seed-core.sql @@ -120,12 +120,14 @@ INSERT INTO admin_menu ( (2041700000000100401, 2041700000000100400, 'QqBotDashboard', '/qqbot/dashboard', '/qqbot/dashboard/list', NULL, 'QqBot:Dashboard:List', 'menu', '{"icon":"lucide:gauge","title":"工作台"}', 1, 0), (2041700000000100402, 2041700000000100400, 'QqBotAccount', '/qqbot/account', '/qqbot/account/list', NULL, 'QqBot:Account:List', 'menu', '{"icon":"lucide:radio-receiver","title":"账号连接"}', 1, 1), (2041700000000100410, 2041700000000100400, 'QqBotAccountConfig', '/qqbot/account/config', '/qqbot/account/config', NULL, 'QqBot:Account:Config', 'menu', '{"activePath":"/qqbot/account","hideInMenu":true,"title":"账号功能配置"}', 1, 0), + (2041700000000100412, 2041700000000100400, 'QqBotAccountNapcatWebui', '/qqbot/account/:accountId/napcat-webui', '/qqbot/account/napcat-webui/index', NULL, 'QqBot:Account:WebUI', 'menu', '{"activePath":"/qqbot/account","hideInMenu":true,"title":"NapCat WebUI"}', 1, 0), (2041700000000120401, 2041700000000100402, 'QqBotAccountCreate', NULL, NULL, NULL, 'QqBot:Account:Create', 'button', '{"title":"common.create"}', 1, 0), (2041700000000120402, 2041700000000100402, 'QqBotAccountEdit', NULL, NULL, NULL, 'QqBot:Account:Edit', 'button', '{"title":"common.edit"}', 1, 0), (2041700000000120403, 2041700000000100402, 'QqBotAccountDelete', NULL, NULL, NULL, 'QqBot:Account:Delete', 'button', '{"title":"common.delete"}', 1, 0), (2041700000000120404, 2041700000000100402, 'QqBotAccountKick', NULL, NULL, NULL, 'QqBot:Account:Kick', 'button', '{"title":"断开连接"}', 1, 0), (2041700000000120405, 2041700000000100402, 'QqBotAccountRefreshLogin', NULL, NULL, NULL, 'QqBot:Account:RefreshLogin', 'button', '{"title":"更新登录"}', 1, 0), (2041700000000120406, 2041700000000100402, 'QqBotAccountConfigButton', NULL, NULL, NULL, 'QqBot:Account:Config', 'button', '{"title":"配置"}', 1, 0), + (2041700000000120407, 2041700000000100402, 'QqBotAccountWebUI', NULL, NULL, NULL, 'QqBot:Account:WebUI', 'button', '{"title":"NapCat WebUI"}', 1, 0), (2041700000000100403, 2041700000000100400, 'QqBotRule', '/qqbot/rule', '/qqbot/rule/list', NULL, 'QqBot:Rule:List', 'menu', '{"icon":"lucide:workflow","title":"自动回复规则"}', 1, 2), (2041700000000120411, 2041700000000100403, 'QqBotRuleCreate', NULL, NULL, NULL, 'QqBot:Rule:Create', 'button', '{"title":"common.create"}', 1, 0), (2041700000000120412, 2041700000000100403, 'QqBotRuleEdit', NULL, NULL, NULL, 'QqBot:Rule:Edit', 'button', '{"title":"common.edit"}', 1, 0), diff --git a/sql/refactor-v3/99-verify.sql b/sql/refactor-v3/99-verify.sql index 5eb57b0..aed6341 100644 --- a/sql/refactor-v3/99-verify.sql +++ b/sql/refactor-v3/99-verify.sql @@ -19,6 +19,11 @@ SELECT 'napcat_risk_mode' AS table_name, COUNT(*) AS row_count FROM napcat_risk_ SELECT 'qqbot_plugin_task' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task; SELECT 'qqbot_plugin_task_run' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task_run; +SELECT 'qqbot_napcat_webui_gateway_audit table exists' AS check_name, COUNT(*) AS matched_rows +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = 'qqbot_napcat_webui_gateway_audit'; + SELECT 'seed_admin_user' AS check_name, COUNT(*) AS matched_rows FROM admin_user WHERE username = 'admin' @@ -83,6 +88,10 @@ WHERE plugin_key = 'bangdream' AND enabled = 1 AND is_deleted = 0; +SELECT 'seed_qqbot_account_webui_permission' AS check_name, COUNT(*) AS matched_rows +FROM admin_menu +WHERE auth_code = 'QqBot:Account:WebUI'; + SELECT 'index_admin_user_username' AS check_name, COUNT(*) AS matched_rows FROM information_schema.statistics WHERE table_schema = DATABASE() diff --git a/test/modules/qqbot/napcat-webui-gateway/webui-gateway-contract.spec.ts b/test/modules/qqbot/napcat-webui-gateway/webui-gateway-contract.spec.ts new file mode 100644 index 0000000..b997fb2 --- /dev/null +++ b/test/modules/qqbot/napcat-webui-gateway/webui-gateway-contract.spec.ts @@ -0,0 +1,32 @@ +import { readFileSync } from 'fs'; +import { resolve } from 'path'; + +const repoRoot = resolve(__dirname, '../../../..'); + +/** + * 读取仓库内契约文件内容。 + * @param path - 相对仓库根目录的文件路径。 + * @returns UTF-8 文本内容,用于结构契约断言。 + */ +const readSource = (path: string) => { + return readFileSync(resolve(repoRoot, path), 'utf8'); +}; + +describe('NapCat WebUI Gateway contract seeds', () => { + it('registers a dedicated Admin permission for full NapCat WebUI access', () => { + const coreSeed = readSource('sql/refactor-v3/01-seed-core.sql'); + const qqbotSeed = readSource('sql/qqbot-init.sql'); + + expect(coreSeed).toContain('QqBot:Account:WebUI'); + expect(coreSeed).toContain('QqBotAccountNapcatWebui'); + expect(qqbotSeed).toContain('QqBot:Account:WebUI'); + expect(qqbotSeed).toContain('QqBotAccountNapcatWebui'); + }); + + it('verifies the gateway audit table during full schema checks', () => { + const verifySql = readSource('sql/refactor-v3/99-verify.sql'); + + expect(verifySql).toContain('qqbot_napcat_webui_gateway_audit'); + expect(verifySql).toContain('QqBot:Account:WebUI'); + }); +});