From bd65321068e01e78763ebd8b23a18838493bd7b6 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 13:54:31 +0800 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=20SQL=20?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=B8=AD=E7=9A=84=E5=BC=95=E5=8F=B7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=BB=A5=E7=A1=AE=E4=BF=9D=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/02-migrate-abpusers-table.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/02-migrate-abpusers-table.sql b/sql/02-migrate-abpusers-table.sql index de8f831f..74cee3d9 100644 --- a/sql/02-migrate-abpusers-table.sql +++ b/sql/02-migrate-abpusers-table.sql @@ -35,7 +35,7 @@ FROM sqlite_master WHERE type = 'table' AND name = 'AbpUsers'; -- 查看当前表结构 SELECT '=== 当前 AbpUsers 表结构 ===' AS section; -SELECT name AS ColumnName, type AS DataType, `notnull` AS NotNull +SELECT name AS ColumnName, type AS DataType, "notnull" AS NotNull FROM pragma_table_info('AbpUsers') ORDER BY cid; @@ -127,7 +127,7 @@ COMMIT; -- 验证新表结构(应只有 10 列) SELECT '=== 新 AbpUsers 表结构 ===' AS section; -SELECT name AS ColumnName, type AS DataType, `notnull` AS NotNull +SELECT name AS ColumnName, type AS DataType, "notnull" AS NotNull FROM pragma_table_info('AbpUsers') ORDER BY cid; From 1d61dc43b194c0344f3ee91d6dbc29a9311e61a1 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:12:22 +0800 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0=20AbpUsers=20?= =?UTF-8?q?=E8=A1=A8=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E5=B9=82=E7=AD=89=E6=80=A7=E5=92=8C=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/02-migrate-abpusers-table.sql | 42 +++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/sql/02-migrate-abpusers-table.sql b/sql/02-migrate-abpusers-table.sql index 74cee3d9..646f7eb5 100644 --- a/sql/02-migrate-abpusers-table.sql +++ b/sql/02-migrate-abpusers-table.sql @@ -1,9 +1,10 @@ -- ============================================================ --- AbpUsers 表精简迁移脚本 +-- AbpUsers 表精简迁移脚本(幂等安全版) -- 用途:移除 ABP Framework 遗留的冗余字段,使表结构与新 User 实体一致 -- 前置条件:已备份 DFApp.db,应用已停止运行 --- 执行方式:sqlite3 DFApp.db < sql/migrate-abpusers-table.sql +-- 执行方式:sqlite3 DFApp.db < sql/02-migrate-abpusers-table.sql -- 注意:此操作不可逆!请务必先备份数据库! +-- 幂等性:如果迁移已完成,脚本会安全终止,不会重复执行 -- ============================================================ -- -- 背景: @@ -18,14 +19,23 @@ -- 2. 从旧表复制未软删除的数据到新表(排除 IsDeleted=1 的记录) -- 3. 删除旧表 -- 4. 将新表重命名为 AbpUsers +-- +-- 安全机制: +-- - .bail on:遇到错误时立即终止,防止 INSERT 失败后继续执行 DROP TABLE +-- - 迁移状态检查:检测 IsDeleted 列是否存在,已完成迁移时安全退出 +-- - DROP TABLE IF EXISTS:清理上次失败运行遗留的临时表 -- ============================================================ +-- 关键安全设置:遇到错误时终止脚本执行 +-- 防止 INSERT 失败后脚本继续执行 DROP TABLE 导致数据丢失 +.bail on + -- ============================================================ -- 第一部分:前置检查 -- ============================================================ --- 确认 AbpUsers 表存在 +-- 1.1 确认 AbpUsers 表存在 SELECT '正在检查 AbpUsers 表是否存在...' AS step; SELECT CASE WHEN COUNT(*) > 0 THEN '✅ AbpUsers 表存在,可以继续' @@ -33,13 +43,27 @@ SELECT CASE END AS result FROM sqlite_master WHERE type = 'table' AND name = 'AbpUsers'; --- 查看当前表结构 +-- 1.2 查看当前表结构 SELECT '=== 当前 AbpUsers 表结构 ===' AS section; -SELECT name AS ColumnName, type AS DataType, "notnull" AS NotNull +SELECT name AS ColumnName, type AS DataType, "notnull" AS "NotNull" FROM pragma_table_info('AbpUsers') ORDER BY cid; --- 查看当前数据量(含已软删除的) +-- 1.3 检查迁移状态 +-- 通过 pragma_table_info 查询列信息,不直接引用 IsDeleted 列,因此总是安全的 +SELECT '=== 迁移状态检查 ===' AS section; +SELECT CASE + WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') > 0 + THEN '🔄 IsDeleted 列存在,需要执行数据迁移' + ELSE '⏭️ IsDeleted 列不存在,迁移已完成。脚本将安全终止。' +END AS migration_status; + +-- 1.4 查看当前数据量(含已软删除的) +-- 此查询引用 IsDeleted 列作为安全守卫: +-- - 如果 IsDeleted 列存在 → 正常输出统计数据 +-- - 如果 IsDeleted 列不存在 → 产生 "no such column: IsDeleted" 错误 +-- 配合 .bail on 指令,脚本将在此安全终止 +-- 后续的事务迁移操作(含 DROP TABLE)不会被执行,保护数据安全 SELECT '=== 当前数据统计 ===' AS section; SELECT COUNT(*) AS TotalRows, @@ -50,8 +74,12 @@ FROM AbpUsers; -- ============================================================ -- 第二部分:数据迁移(事务保护) +-- 仅在 IsDeleted 列存在时才会执行到这里(否则已在上方终止) -- ============================================================ +-- 清理上次失败运行遗留的临时表(幂等性保障) +DROP TABLE IF EXISTS _AbpUsers_new; + BEGIN TRANSACTION; -- 备份提示(仅输出提醒,SQLite 不支持自动备份) @@ -127,7 +155,7 @@ COMMIT; -- 验证新表结构(应只有 10 列) SELECT '=== 新 AbpUsers 表结构 ===' AS section; -SELECT name AS ColumnName, type AS DataType, "notnull" AS NotNull +SELECT name AS ColumnName, type AS DataType, "notnull" AS "NotNull" FROM pragma_table_info('AbpUsers') ORDER BY cid; From f8982c965d26f46df00d9ea3616b3fa1b1df1a02 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:17:33 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20AuditedEntity?= =?UTF-8?q?=20=E6=B4=BE=E7=94=9F=E5=AE=9E=E4=BD=93=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E5=AE=A1=E8=AE=A1=E5=88=97=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=20SQL=20=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/04-add-missing-audit-columns.sql | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sql/04-add-missing-audit-columns.sql b/sql/04-add-missing-audit-columns.sql index 9b3273cc..b621a103 100644 --- a/sql/04-add-missing-audit-columns.sql +++ b/sql/04-add-missing-audit-columns.sql @@ -1,5 +1,14 @@ +-- ============================================================= -- 修复 AuditedEntity 派生实体缺失的审计列(CreatorId, LastModifierId) --- 部分 AuditedEntity 派生实体的数据库表在迁移时遗漏了审计列 +-- 说明:部分 AuditedEntity 派生实体的数据库表在迁移时遗漏了审计列 +-- +-- 注意:AppPermissionGrants 表的审计列不在此脚本中添加。 +-- 该表由脚本 06 (06-migrate-to-app-permission-grants.sql) 创建, +-- 创建时已包含 CreatorId、LastModificationTime、LastModifierId 列。 +-- 之前此脚本引用了尚未创建的 AppPermissionGrants 表导致报错。 +-- ============================================================= + +.bail on -- AppMediaInfo(MediaInfo : AuditedEntity) ALTER TABLE "AppMediaInfo" ADD COLUMN "CreatorId" TEXT NULL; @@ -19,11 +28,6 @@ ALTER TABLE "AbpRoleClaims" ADD COLUMN "CreatorId" TEXT NULL; ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModificationTime" TEXT NULL; ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModifierId" TEXT NULL; --- AppPermissionGrants(PermissionGrant : AuditedEntity) -ALTER TABLE "AppPermissionGrants" ADD COLUMN "CreatorId" TEXT NULL; -ALTER TABLE "AppPermissionGrants" ADD COLUMN "LastModificationTime" TEXT NULL; -ALTER TABLE "AppPermissionGrants" ADD COLUMN "LastModifierId" TEXT NULL; - -- AbpRoles(Role : AuditedEntity) -- CreationTime 已存在,仅补充 CreatorId 和修改审计列 ALTER TABLE "AbpRoles" ADD COLUMN "CreatorId" TEXT NULL; From bf62ec052c96202d890e8b8b4664202a18694b49 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:28:33 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=20AuditedEntity?= =?UTF-8?q?=20=E6=B4=BE=E7=94=9F=E5=AE=9E=E4=BD=93=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E5=AE=A1=E8=AE=A1=E5=88=97=EF=BC=8C=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=20SQL=20=E8=84=9A=E6=9C=AC=E7=9A=84=E5=B9=82=E7=AD=89=E6=80=A7?= =?UTF-8?q?=E5=92=8C=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/04-add-missing-audit-columns.sql | 138 ++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 12 deletions(-) diff --git a/sql/04-add-missing-audit-columns.sql b/sql/04-add-missing-audit-columns.sql index b621a103..a4f23143 100644 --- a/sql/04-add-missing-audit-columns.sql +++ b/sql/04-add-missing-audit-columns.sql @@ -1,35 +1,149 @@ -- ============================================================= -- 修复 AuditedEntity 派生实体缺失的审计列(CreatorId, LastModifierId) +-- 幂等安全版:可安全地重复执行 +-- -- 说明:部分 AuditedEntity 派生实体的数据库表在迁移时遗漏了审计列 -- -- 注意:AppPermissionGrants 表的审计列不在此脚本中添加。 -- 该表由脚本 06 (06-migrate-to-app-permission-grants.sql) 创建, -- 创建时已包含 CreatorId、LastModificationTime、LastModifierId 列。 -- 之前此脚本引用了尚未创建的 AppPermissionGrants 表导致报错。 +-- +-- 幂等性原理: +-- SQLite 不支持 ALTER TABLE ADD COLUMN IF NOT EXISTS 语法, +-- 也不支持 SQL 中的 IF/ELSE 条件执行 DDL 语句。 +-- 本脚本使用以下技巧实现幂等性: +-- 1. 通过 SELECT 'ALTER TABLE ...' WHERE (列不存在) 仅输出需要执行的语句 +-- 2. 将输出重定向到临时文件(.output) +-- 3. 通过 .read 执行临时文件中的语句 +-- 已存在的列不会生成对应语句,从而避免 "duplicate column name" 错误。 -- ============================================================= .bail on +.headers off + +-- ============================================================ +-- 第一部分:检查当前状态 +-- ============================================================ + +SELECT '=== 审计列迁移前状态检查 ==='; + +-- AppMediaInfo +SELECT 'AppMediaInfo:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'CreatorId') > 0 THEN ' CreatorId=已存在' ELSE ' CreatorId=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'LastModifierId') > 0 THEN ', LastModifierId=已存在' ELSE ', LastModifierId=缺失' END; + +-- AppRssSubscriptions +SELECT 'AppRssSubscriptions:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptions') WHERE name = 'CreatorId') > 0 THEN ' CreatorId=已存在' ELSE ' CreatorId=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptions') WHERE name = 'LastModifierId') > 0 THEN ', LastModifierId=已存在' ELSE ', LastModifierId=缺失' END; + +-- AppRssMirrorItem +SELECT 'AppRssMirrorItem:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'CreatorId') > 0 THEN ' CreatorId=已存在' ELSE ' CreatorId=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'LastModifierId') > 0 THEN ', LastModifierId=已存在' ELSE ', LastModifierId=缺失' END; + +-- AbpRoleClaims +SELECT 'AbpRoleClaims:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreationTime') > 0 THEN ' CreationTime=已存在' ELSE ' CreationTime=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreatorId') > 0 THEN ', CreatorId=已存在' ELSE ', CreatorId=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModificationTime') > 0 THEN ', LastModificationTime=已存在' ELSE ', LastModificationTime=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModifierId') > 0 THEN ', LastModifierId=已存在' ELSE ', LastModifierId=缺失' END; + +-- AbpRoles +SELECT 'AbpRoles:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'CreatorId') > 0 THEN ' CreatorId=已存在' ELSE ' CreatorId=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModificationTime') > 0 THEN ', LastModificationTime=已存在' ELSE ', LastModificationTime=缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModifierId') > 0 THEN ', LastModifierId=已存在' ELSE ', LastModifierId=缺失' END; + + +-- ============================================================ +-- 第二部分:动态生成并执行 ALTER TABLE 语句 +-- 仅对不存在的列生成 ALTER TABLE,已存在的列自动跳过 +-- ============================================================ + +.output /tmp/_migration_04_steps.sql -- AppMediaInfo(MediaInfo : AuditedEntity) -ALTER TABLE "AppMediaInfo" ADD COLUMN "CreatorId" TEXT NULL; -ALTER TABLE "AppMediaInfo" ADD COLUMN "LastModifierId" TEXT NULL; +SELECT 'ALTER TABLE "AppMediaInfo" ADD COLUMN "CreatorId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'CreatorId') = 0; + +SELECT 'ALTER TABLE "AppMediaInfo" ADD COLUMN "LastModifierId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'LastModifierId') = 0; -- AppRssSubscriptions(RssSubscription : AuditedEntity) -- CreatorId 已存在,仅补充 LastModifierId -ALTER TABLE "AppRssSubscriptions" ADD COLUMN "LastModifierId" TEXT NULL; +SELECT 'ALTER TABLE "AppRssSubscriptions" ADD COLUMN "LastModifierId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptions') WHERE name = 'LastModifierId') = 0; -- AppRssMirrorItem(RssMirrorItem : AuditedEntity) -ALTER TABLE "AppRssMirrorItem" ADD COLUMN "CreatorId" TEXT NULL; -ALTER TABLE "AppRssMirrorItem" ADD COLUMN "LastModifierId" TEXT NULL; +SELECT 'ALTER TABLE "AppRssMirrorItem" ADD COLUMN "CreatorId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'CreatorId') = 0; + +SELECT 'ALTER TABLE "AppRssMirrorItem" ADD COLUMN "LastModifierId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'LastModifierId') = 0; -- AbpRoleClaims(RoleClaim : AuditedEntity) -ALTER TABLE "AbpRoleClaims" ADD COLUMN "CreationTime" TEXT NOT NULL DEFAULT '0001-01-01 00:00:00'; -ALTER TABLE "AbpRoleClaims" ADD COLUMN "CreatorId" TEXT NULL; -ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModificationTime" TEXT NULL; -ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModifierId" TEXT NULL; +SELECT 'ALTER TABLE "AbpRoleClaims" ADD COLUMN "CreationTime" TEXT NOT NULL DEFAULT ''0001-01-01 00:00:00'';' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreationTime') = 0; + +SELECT 'ALTER TABLE "AbpRoleClaims" ADD COLUMN "CreatorId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreatorId') = 0; + +SELECT 'ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModificationTime" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModificationTime') = 0; + +SELECT 'ALTER TABLE "AbpRoleClaims" ADD COLUMN "LastModifierId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModifierId') = 0; -- AbpRoles(Role : AuditedEntity) -- CreationTime 已存在,仅补充 CreatorId 和修改审计列 -ALTER TABLE "AbpRoles" ADD COLUMN "CreatorId" TEXT NULL; -ALTER TABLE "AbpRoles" ADD COLUMN "LastModificationTime" TEXT NULL; -ALTER TABLE "AbpRoles" ADD COLUMN "LastModifierId" TEXT NULL; +SELECT 'ALTER TABLE "AbpRoles" ADD COLUMN "CreatorId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'CreatorId') = 0; + +SELECT 'ALTER TABLE "AbpRoles" ADD COLUMN "LastModificationTime" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModificationTime') = 0; + +SELECT 'ALTER TABLE "AbpRoles" ADD COLUMN "LastModifierId" TEXT NULL;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModifierId') = 0; + +.output stdout + +-- 执行动态生成的 ALTER TABLE 语句 +-- 如果所有列都已存在,临时文件为空,.read 不会执行任何操作 +.read /tmp/_migration_04_steps.sql + +-- 清理临时文件 +.shell rm -f /tmp/_migration_04_steps.sql + + +-- ============================================================ +-- 第三部分:迁移后验证 +-- ============================================================ + +SELECT '=== 迁移后验证 ==='; + +SELECT 'AppMediaInfo:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'CreatorId') > 0 THEN ' ✅CreatorId' ELSE ' ❌CreatorId缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppMediaInfo') WHERE name = 'LastModifierId') > 0 THEN ' ✅LastModifierId' ELSE ' ❌LastModifierId缺失' END; + +SELECT 'AppRssSubscriptions:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptions') WHERE name = 'CreatorId') > 0 THEN ' ✅CreatorId' ELSE ' ❌CreatorId缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptions') WHERE name = 'LastModifierId') > 0 THEN ' ✅LastModifierId' ELSE ' ❌LastModifierId缺失' END; + +SELECT 'AppRssMirrorItem:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'CreatorId') > 0 THEN ' ✅CreatorId' ELSE ' ❌CreatorId缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssMirrorItem') WHERE name = 'LastModifierId') > 0 THEN ' ✅LastModifierId' ELSE ' ❌LastModifierId缺失' END; + +SELECT 'AbpRoleClaims:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreationTime') > 0 THEN ' ✅CreationTime' ELSE ' ❌CreationTime缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'CreatorId') > 0 THEN ' ✅CreatorId' ELSE ' ❌CreatorId缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModificationTime') > 0 THEN ' ✅LastModificationTime' ELSE ' ❌LastModificationTime缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoleClaims') WHERE name = 'LastModifierId') > 0 THEN ' ✅LastModifierId' ELSE ' ❌LastModifierId缺失' END; + +SELECT 'AbpRoles:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'CreatorId') > 0 THEN ' ✅CreatorId' ELSE ' ❌CreatorId缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModificationTime') > 0 THEN ' ✅LastModificationTime' ELSE ' ❌LastModificationTime缺失' END || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpRoles') WHERE name = 'LastModifierId') > 0 THEN ' ✅LastModifierId' ELSE ' ❌LastModifierId缺失' END; + +SELECT '✅ 审计列迁移完成(幂等安全,可重复执行)'; From 045d35c1832cbc7438262d67ab8e92cc80a647ac Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:36:05 +0800 Subject: [PATCH 05/11] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=20AppPermission?= =?UTF-8?q?Grants=20=E8=A1=A8=E4=B8=AD=E5=A4=A7=E5=86=99=20Guid=20?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=9C=A8?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC=E4=B8=AD=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E4=B8=BA=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/05-fix-guid-case-migration.sql | 6 +++--- sql/06-migrate-to-app-permission-grants.sql | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sql/05-fix-guid-case-migration.sql b/sql/05-fix-guid-case-migration.sql index bbaa364c..6f4efdd3 100644 --- a/sql/05-fix-guid-case-migration.sql +++ b/sql/05-fix-guid-case-migration.sql @@ -117,9 +117,9 @@ UPDATE AppLotteryPrizegrades SET CreatorId = LOWER(CreatorId) WHERE CreatorId IS -- 列:CreatorId UPDATE AppLotteryResult SET CreatorId = LOWER(CreatorId) WHERE CreatorId IS NOT NULL AND CreatorId != LOWER(CreatorId); --- 20. AppPermissionGrants(应用权限授予,ProviderKey 可能是 Guid 或角色名) --- 列:ProviderKey(仅当 ProviderKey 符合 Guid 格式时转换) -UPDATE AppPermissionGrants SET ProviderKey = LOWER(ProviderKey) WHERE ProviderKey LIKE '%-%-%-%-%' AND ProviderKey != LOWER(ProviderKey); +-- 20. AppPermissionGrants 已移至脚本 06 处理 +-- 原因:AppPermissionGrants 表在脚本 06 中创建,脚本 05 执行时该表尚不存在 +-- 脚本 06 在数据迁移时已统一使用 lower(ProviderKey),并在迁移完成后清理残留大写 Guid -- 21. AppMediaExternalLink(媒体外链) -- 列:CreatorId, LastModifierId diff --git a/sql/06-migrate-to-app-permission-grants.sql b/sql/06-migrate-to-app-permission-grants.sql index 7d531cdb..d3fb7494 100644 --- a/sql/06-migrate-to-app-permission-grants.sql +++ b/sql/06-migrate-to-app-permission-grants.sql @@ -51,6 +51,11 @@ AND EXISTS ( WHERE UPPER(r.Id) = UPPER(AppPermissionGrants.ProviderKey) ); +-- 5.5 清理残留的大写 Guid 格式 ProviderKey(从脚本 05 移入) +-- 确保所有 Guid 格式的 ProviderKey 统一为小写(角色名等非 Guid 值不受影响) +UPDATE AppPermissionGrants SET ProviderKey = LOWER(ProviderKey) +WHERE ProviderKey LIKE '%-%-%-%-%' AND ProviderKey != LOWER(ProviderKey); + -- 6. 验证迁移结果 SELECT '=== 迁移结果统计 ===' AS info; SELECT '旧表总数' AS label, COUNT(*) AS cnt FROM AbpPermissionGrants From 8b90c662942b4e9bf093fe066e9803a4a29c6302 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:44:34 +0800 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E8=BD=AF?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=92=8C=E5=A4=9A=E7=A7=9F=E6=88=B7=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E9=80=BB=E8=BE=91=EF=BC=8C=E7=A1=AE=E4=BF=9D=E5=9C=A8?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E5=90=8E=E6=AD=A3=E7=A1=AE=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=AE=8C=E6=95=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/08-verify-identity-data.sql | 56 +++++++++++++-------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/sql/08-verify-identity-data.sql b/sql/08-verify-identity-data.sql index c9891811..9adae86b 100644 --- a/sql/08-verify-identity-data.sql +++ b/sql/08-verify-identity-data.sql @@ -42,39 +42,27 @@ SELECT COUNT(*) AS '禁用用户数' FROM AbpUsers WHERE IsActive = 0; -- 1.2 软删除检查 -- 迁移脚本 migrate-abpusers-table.sql 会移除 IsDeleted 列, -- 如果该列仍存在则检查是否有残留的软删除数据 +-- 注意:SQLite 会解析整个语句,不能在 CASE 中条件引用已删除的列, +-- 因此只能通过 pragma_table_info 检查列是否存在 SELECT '--- 软删除检查 ---' AS section; SELECT CASE - WHEN COUNT(*) = 0 THEN '⚠️ IsDeleted 列不存在(已执行表结构迁移,此项跳过)' - ELSE '检查软删除数据...' -END AS status -FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted'; + WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') = 0 + THEN '✅ IsDeleted 列已移除,无软删除数据' + ELSE '⚠️ IsDeleted 列仍存在,请检查是否有软删除用户残留' +END AS '软删除验证结果'; -SELECT COUNT(*) AS '软删除用户数(IsDeleted=1)' -FROM AbpUsers -WHERE name = 'IsDeleted' AND (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') > 0 -AND IsDeleted = 1; - --- 使用子查询方式避免列不存在时报错 -SELECT - CASE - WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') = 0 - THEN '✅ IsDeleted 列已移除,无软删除数据' - WHEN (SELECT COUNT(*) FROM AbpUsers WHERE IsDeleted = 1) = 0 - THEN '✅ 无软删除用户' - ELSE '❌ 仍有软删除用户残留,数量: ' || (SELECT COUNT(*) FROM AbpUsers WHERE IsDeleted = 1) - END AS '软删除验证结果'; -- 1.3 多租户检查 -- 迁移脚本会移除 TenantId 列,如果该列仍存在则检查是否有多租户数据残留 +-- 注意:SQLite 会解析整个语句,不能在 CASE 中条件引用已删除的列, +-- 因此只能通过 pragma_table_info 检查列是否存在 SELECT '--- 多租户检查 ---' AS section; -SELECT - CASE - WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'TenantId') = 0 - THEN '✅ TenantId 列已移除,无多租户数据' - WHEN (SELECT COUNT(*) FROM AbpUsers WHERE TenantId IS NOT NULL) = 0 - THEN '✅ 所有用户 TenantId 均为 NULL,无多租户数据' - ELSE '❌ 存在多租户用户数据,数量: ' || (SELECT COUNT(*) FROM AbpUsers WHERE TenantId IS NOT NULL) - END AS '多租户验证结果'; +SELECT CASE + WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'TenantId') = 0 + THEN '✅ TenantId 列已移除,无多租户数据' + ELSE '⚠️ TenantId 列仍存在,请检查是否有多租户数据残留' +END AS '多租户验证结果'; + -- 1.4 密码哈希检查 -- 所有用户都应设置密码哈希 @@ -371,6 +359,8 @@ SELECT )) AS '重复用户名数'; -- 8.3 迁移状态检查 +-- 注意:SQLite 会解析整个语句,不能在 CASE 中条件引用已删除的列, +-- 因此只通过 pragma_table_info 检查列是否存在 SELECT '--- 迁移状态检查 ---' AS section; SELECT CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') = 0 @@ -379,12 +369,10 @@ SELECT END AS '表结构迁移状态', CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'TenantId') = 0 THEN '✅ 已清理' - ELSE CASE WHEN (SELECT COUNT(*) FROM AbpUsers WHERE TenantId IS NOT NULL) = 0 - THEN '✅ 已清理(列存在但值为空)' - ELSE '❌ 存在多租户数据' - END + ELSE '⚠️ TenantId 列仍存在,请检查是否有多租户数据残留' END AS '多租户数据清理状态'; + -- 8.4 最终验证结论 SELECT '' AS blank; SELECT '===== 最终验证结论 =====' AS step; @@ -407,13 +395,11 @@ SELECT CASE SELECT UserName FROM AbpUsers GROUP BY UserName HAVING COUNT(*) > 1 )) > 0 THEN '❌ 数据完整性存在问题:存在重复用户名' - -- 迁移残留检查(仅在列仍存在时才报错) + -- 迁移残留检查(仅检查列是否仍存在,不引用已删除的列) WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'IsDeleted') > 0 - AND (SELECT COUNT(*) FROM AbpUsers WHERE IsDeleted = 1) > 0 - THEN '❌ 数据完整性存在问题:存在软删除用户残留' + THEN '❌ 数据完整性存在问题:IsDeleted 列仍存在,迁移未完成' WHEN (SELECT COUNT(*) FROM pragma_table_info('AbpUsers') WHERE name = 'TenantId') > 0 - AND (SELECT COUNT(*) FROM AbpUsers WHERE TenantId IS NOT NULL) > 0 - THEN '❌ 数据完整性存在问题:存在多租户数据残留' + THEN '❌ 数据完整性存在问题:TenantId 列仍存在,迁移未完成' -- 所有检查通过 ELSE '✅ 所有数据验证通过,数据完整性良好' END AS '验证结论'; From 5e8de558fc1894534691c5fff3dbcee69d3ff0c0 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 14:48:00 +0800 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=E7=A3=81?= =?UTF-8?q?=E7=9B=98=E7=A9=BA=E9=97=B4=E6=9A=82=E5=AD=98=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=88=B0=20AppRssSubscriptionDownloads=20=E8=A1=A8=EF=BC=8C?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E8=BF=81=E7=A7=BB=E7=9A=84=E5=B9=82=E7=AD=89?= =?UTF-8?q?=E6=80=A7=E5=92=8C=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/10-add-disk-space-check.sql | 58 ++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/sql/10-add-disk-space-check.sql b/sql/10-add-disk-space-check.sql index 6b330d61..4b235c1f 100644 --- a/sql/10-add-disk-space-check.sql +++ b/sql/10-add-disk-space-check.sql @@ -1,2 +1,58 @@ +-- ============================================================= -- 添加磁盘空间暂存字段到订阅下载表 -ALTER TABLE "AppRssSubscriptionDownloads" ADD COLUMN "IsPendingDueToLowDiskSpace" INTEGER NOT NULL DEFAULT 0; +-- 幂等安全版:可安全地重复执行 +-- +-- 说明:为 AppRssSubscriptionDownloads 表添加 IsPendingDueToLowDiskSpace 列, +-- 用于标记因磁盘空间不足而暂缓下载的任务。 +-- +-- 幂等性原理: +-- SQLite 不支持 ALTER TABLE ADD COLUMN IF NOT EXISTS 语法, +-- 本脚本使用与 04-add-missing-audit-columns.sql 相同的技巧: +-- 1. 通过 pragma_table_info 检查列是否存在 +-- 2. 仅在列不存在时生成 ALTER TABLE 语句到临时文件 +-- 3. 通过 .read 执行临时文件中的语句 +-- ============================================================= + +.bail on +.headers off + +-- ============================================================ +-- 第一部分:检查当前状态 +-- ============================================================ + +SELECT '=== 磁盘空间暂存字段迁移前状态检查 ==='; + +SELECT 'AppRssSubscriptionDownloads:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptionDownloads') WHERE name = 'IsPendingDueToLowDiskSpace') > 0 THEN ' IsPendingDueToLowDiskSpace=已存在' ELSE ' IsPendingDueToLowDiskSpace=缺失' END; + + +-- ============================================================ +-- 第二部分:动态生成并执行 ALTER TABLE 语句 +-- 仅对不存在的列生成 ALTER TABLE,已存在的列自动跳过 +-- ============================================================ + +.output /tmp/_migration_10_steps.sql + +SELECT 'ALTER TABLE "AppRssSubscriptionDownloads" ADD COLUMN "IsPendingDueToLowDiskSpace" INTEGER NOT NULL DEFAULT 0;' +WHERE (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptionDownloads') WHERE name = 'IsPendingDueToLowDiskSpace') = 0; + +.output stdout + +-- 执行动态生成的 ALTER TABLE 语句 +-- 如果列已存在,临时文件为空,.read 不会执行任何操作 +.read /tmp/_migration_10_steps.sql + +-- 清理临时文件 +.shell rm -f /tmp/_migration_10_steps.sql + + +-- ============================================================ +-- 第三部分:迁移后验证 +-- ============================================================ + +SELECT '=== 迁移后验证 ==='; + +SELECT 'AppRssSubscriptionDownloads:' || + CASE WHEN (SELECT COUNT(*) FROM pragma_table_info('AppRssSubscriptionDownloads') WHERE name = 'IsPendingDueToLowDiskSpace') > 0 THEN ' ✅IsPendingDueToLowDiskSpace' ELSE ' ❌IsPendingDueToLowDiskSpace缺失' END; + +SELECT '✅ 磁盘空间暂存字段迁移完成(幂等安全,可重复执行)'; From f7e9a87fe21914a4558ed9bc3a8da5b68cfd2091 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 15:12:32 +0800 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=AF=86=E7=A0=81=E5=93=88=E5=B8=8C=E5=80=BC=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=84=9A=E6=9C=AC=EF=BC=8C=E7=A1=AE=E4=BF=9D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=AF=86=E7=A0=81=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/14-fix-default-password.sql | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 sql/14-fix-default-password.sql diff --git a/sql/14-fix-default-password.sql b/sql/14-fix-default-password.sql new file mode 100644 index 00000000..3c0cbfd6 --- /dev/null +++ b/sql/14-fix-default-password.sql @@ -0,0 +1,12 @@ +-- 修复默认密码哈希值 +-- 使用与 PasswordHasher.cs (PBKDF2-HMAC-SHA256, 16字节盐, 10000次迭代, 32字节哈希) 相同的算法生成 +-- 密码: 123456 + +UPDATE AbpUsers +SET PasswordHash = 'EgF/qeET7z/4R73QxvdpsQEx2guIRo4N6gvKv/Funm0qfjs0+hNRY6BTHzUYsKkT' +WHERE PasswordHash IS NULL OR PasswordHash = '8rZB1hd/U7b290OS9NGoVwQ13WanO9EfDHjqNzTQGsyIriXgmxg3dfAoaMCpP9pz'; + +-- 输出更新的用户数量 +SELECT COUNT(*) AS UpdatedCount +FROM AbpUsers +WHERE PasswordHash = 'EgF/qeET7z/4R73QxvdpsQEx2guIRo4N6gvKv/Funm0qfjs0+hNRY6BTHzUYsKkT'; From 3de1418ea91791e75be4e09f791422d5e389af84 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 15:24:06 +0800 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=AF=86=E7=A0=81=E5=93=88=E5=B8=8C=E5=80=BC=EF=BC=8C?= =?UTF-8?q?=E7=A1=AE=E4=BF=9D=E7=94=A8=E6=88=B7=E5=AF=86=E7=A0=81=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/14-fix-default-password.sql | 6 +- sql/15-grant-admin-new-permissions.sql | 99 ++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 sql/15-grant-admin-new-permissions.sql diff --git a/sql/14-fix-default-password.sql b/sql/14-fix-default-password.sql index 3c0cbfd6..6d7ca8d2 100644 --- a/sql/14-fix-default-password.sql +++ b/sql/14-fix-default-password.sql @@ -1,12 +1,12 @@ -- 修复默认密码哈希值 -- 使用与 PasswordHasher.cs (PBKDF2-HMAC-SHA256, 16字节盐, 10000次迭代, 32字节哈希) 相同的算法生成 --- 密码: 123456 +-- 密码: qwe123# UPDATE AbpUsers -SET PasswordHash = 'EgF/qeET7z/4R73QxvdpsQEx2guIRo4N6gvKv/Funm0qfjs0+hNRY6BTHzUYsKkT' +SET PasswordHash = 'ad1UIl5Y6YqFeRC+5ixQnPy9cW3wjY0QVFT25NiRu/DQmle5JZ+mJSxScxfOOsWV' WHERE PasswordHash IS NULL OR PasswordHash = '8rZB1hd/U7b290OS9NGoVwQ13WanO9EfDHjqNzTQGsyIriXgmxg3dfAoaMCpP9pz'; -- 输出更新的用户数量 SELECT COUNT(*) AS UpdatedCount FROM AbpUsers -WHERE PasswordHash = 'EgF/qeET7z/4R73QxvdpsQEx2guIRo4N6gvKv/Funm0qfjs0+hNRY6BTHzUYsKkT'; +WHERE PasswordHash = 'ad1UIl5Y6YqFeRC+5ixQnPy9cW3wjY0QVFT25NiRu/DQmle5JZ+mJSxScxfOOsWV'; diff --git a/sql/15-grant-admin-new-permissions.sql b/sql/15-grant-admin-new-permissions.sql new file mode 100644 index 00000000..88ed911c --- /dev/null +++ b/sql/15-grant-admin-new-permissions.sql @@ -0,0 +1,99 @@ +-- 为 admin 角色补齐脚本 11 之后新增的权限 +-- 背景:脚本 11 (11-grant-admin-all-permissions.sql) 之后,DFAppPermissions.cs 中 +-- 新增了 UserManagement、RoleManagement、PermissionGrantManagement、 +-- UserRoleManagement、FileFilter、RssSubscription 共 6 个权限组 24 个权限, +-- 需要为 admin 角色补齐授予 +-- 日期:2026-04-26 +-- +-- 注意:使用 INSERT OR IGNORE 确保幂等性,重复执行不会出错 +-- 不指定 Id 字段(自增) + +-- ======================================== +-- UserManagement 用户管理(5个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserManagement', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserManagement.Create', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserManagement.Update', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserManagement.Delete', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserManagement.ChangePassword', 'Role', 'admin'); + +-- ======================================== +-- RoleManagement 角色管理(4个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RoleManagement', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RoleManagement.Create', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RoleManagement.Update', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RoleManagement.Delete', 'Role', 'admin'); + +-- ======================================== +-- PermissionGrantManagement 权限授予管理(3个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.PermissionGrantManagement', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.PermissionGrantManagement.Grant', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.PermissionGrantManagement.Revoke', 'Role', 'admin'); + +-- ======================================== +-- UserRoleManagement 用户角色管理(3个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserRoleManagement', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserRoleManagement.Assign', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.UserRoleManagement.Remove', 'Role', 'admin'); + +-- ======================================== +-- FileFilter 文件过滤(4个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.FileFilter', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.FileFilter.Create', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.FileFilter.Edit', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.FileFilter.Delete', 'Role', 'admin'); + +-- ======================================== +-- RssSubscription RSS订阅(5个权限) +-- ======================================== +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RssSubscription', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RssSubscription.Create', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RssSubscription.Update', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RssSubscription.Delete', 'Role', 'admin'); + +INSERT OR IGNORE INTO AppPermissionGrants (PermissionName, ProviderType, ProviderKey) +VALUES ('DFApp.RssSubscription.Download', 'Role', 'admin'); From 7e039bee60d8d5e66a1a4cd940f215514451256d Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 15:45:11 +0800 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E9=9D=99?= =?UTF-8?q?=E6=80=81=E6=96=87=E4=BB=B6=E4=B8=AD=E9=97=B4=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BA=94=E7=94=A8=E7=A8=8B=E5=BA=8F=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DFApp.Web/Program.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/DFApp.Web/Program.cs b/src/DFApp.Web/Program.cs index 0a76860b..92dd7da2 100644 --- a/src/DFApp.Web/Program.cs +++ b/src/DFApp.Web/Program.cs @@ -276,8 +276,6 @@ public async static Task Main(string[] args) app.UseDeveloperExceptionPage(); } - app.UseStaticFiles(); - app.UseRouting(); if (!env.IsDevelopment()) From 575ba1f64ecd5eca1cf68471d5a72713aa9a1351 Mon Sep 17 00:00:00 2001 From: df123 Date: Sun, 26 Apr 2026 16:25:49 +0800 Subject: [PATCH 11/11] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=20Aria2RpcClien?= =?UTF-8?q?t=20=E4=B8=AD=E7=9A=84=20RPC=20URL=20=E5=92=8C=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=BA=93=E5=9B=9E=E9=80=80=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DFApp.Web/Domain/Aria2/Aria2RpcClient.cs | 50 ++++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/DFApp.Web/Domain/Aria2/Aria2RpcClient.cs b/src/DFApp.Web/Domain/Aria2/Aria2RpcClient.cs index 0a7d2497..7c8d907f 100644 --- a/src/DFApp.Web/Domain/Aria2/Aria2RpcClient.cs +++ b/src/DFApp.Web/Domain/Aria2/Aria2RpcClient.cs @@ -5,7 +5,9 @@ using System.Text; using System.Text.Json; using System.Threading.Tasks; +using DFApp.Web.Data.Configuration; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace DFApp.Aria2; @@ -17,8 +19,11 @@ public class Aria2RpcClient { private readonly HttpClient _httpClient; private readonly IConfiguration _configuration; + private readonly IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; + private const string ModuleName = "DFApp.Aria2.Aria2RpcClient"; + // JSON 序列化选项:不区分大小写,使用驼峰命名 private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions { @@ -26,27 +31,52 @@ public class Aria2RpcClient PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; - public Aria2RpcClient(HttpClient httpClient, IConfiguration configuration, ILogger logger) + public Aria2RpcClient( + HttpClient httpClient, + IConfiguration configuration, + IServiceScopeFactory scopeFactory, + ILogger logger) { _httpClient = httpClient; _configuration = configuration; + _scopeFactory = scopeFactory; _logger = logger; } /// - /// 获取 RPC URL + /// 从数据库获取 RPC URL,读取失败时回退到 IConfiguration 或默认值 /// - private string GetRpcUrl() + private async Task GetRpcUrlAsync() { - return _configuration["Aria2:RpcUrl"] ?? "http://localhost:6800/jsonrpc"; + try + { + using var scope = _scopeFactory.CreateScope(); + var configRepo = scope.ServiceProvider.GetRequiredService(); + return await configRepo.GetConfigurationInfoValue("aria2rpc", ModuleName); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "从数据库读取 aria2rpc 配置失败,使用 IConfiguration 兜底值"); + return _configuration["Aria2:RpcUrl"] ?? "http://localhost:6800/jsonrpc"; + } } /// - /// 获取 RPC 密钥 + /// 从数据库获取 RPC 密钥,读取失败时回退到 IConfiguration 或空字符串 /// - private string GetSecret() + private async Task GetSecretAsync() { - return _configuration["Aria2:Secret"] ?? string.Empty; + try + { + using var scope = _scopeFactory.CreateScope(); + var configRepo = scope.ServiceProvider.GetRequiredService(); + return await configRepo.GetConfigurationInfoValue("aria2secret", ModuleName); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "从数据库读取 aria2secret 配置失败,使用 IConfiguration 兜底值"); + return _configuration["Aria2:Secret"] ?? string.Empty; + } } /// @@ -56,8 +86,8 @@ private async Task SendRequestAsync(string method, List parameter { try { - var rpcUrl = GetRpcUrl(); - var rpcToken = GetSecret(); + var rpcUrl = await GetRpcUrlAsync(); + var rpcToken = await GetSecretAsync(); // 添加 token 到参数 if (!string.IsNullOrWhiteSpace(rpcToken)) @@ -97,7 +127,7 @@ private async Task SendRequestAsync(string method, List parameter } catch (Exception ex) { - _logger.LogError(ex, "调用 Aria2 RPC 失败: {Method}, URL: {Url}", method, GetRpcUrl()); + _logger.LogError(ex, "调用 Aria2 RPC 失败: {Method}", method); throw; } }