[CLAUDE] Infra: tạm ẩn HRM/Văn phòng số/Cá nhân khỏi user thường + Danh mục xuống cuối sidebar (S58)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m24s

Anh yêu cầu (screenshot eoffice): ẩn các tính năng chưa golive + thu hồi
phân quyền user thường; nhóm Danh mục đưa xuống cuối.

- NEW RevokeTemporarilyHiddenModulesAsync (chạy cuối seed pipeline): set 4 cờ
  CRUD=false cho MỌI role TRỪ Admin trên keys Hrm* (gồm Hrm_Config*) + Off*
  (gồm Off_ChamCong thuộc Cá nhân) + Personal. Giữ row (không xóa) — flip lại
  nhanh khi golive. Menu tự ẩn cả 2 app (GetMyMenuTree lọc CanRead).
- SeedAllRolesReviewReadPermissionsAsync: thu hẹp grant scope còn
  Master/Catalogs/Pe_* (bỏ Hrm/Off/Personal — không re-grant cái vừa revoke).
- Menu "Danh mục" (Master) Order 20→80 — cuối vùng nghiệp vụ, trước System 90.
  Main upsert tự re-set Order trên DB cũ (idempotent sẵn).
- KHÔNG đụng: Pe_* (sếp cần all-role) + Master/Catalogs CanRead (flow PE cần
  xem master data) + Admin (quản trị) + IsVisible layer (Menu eOffice toggle).

Runtime-proof Dev: MasterOrder=80 · NonAdminHrmOffPersonalCanRead=0 ·
AdminHrmOffCanRead=28 · NonAdminPeCanCreate=120 · NonAdminMasterCanRead=48.
Build 0/0, test 240 PASS. Lưu ý mức che: menu + permission matrix; URL gõ
trực tiếp chưa chặn (FE không PermissionGuard per-route — chấp nhận "tạm ẩn").

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-11 13:36:08 +07:00
parent 2aefb3134d
commit 6c5fd26428

View File

@ -1787,7 +1787,10 @@ public static class DbInitializer
var tree = new List<(string Key, string Label, string? Parent, int Order, string Icon)> var tree = new List<(string Key, string Label, string? Parent, int Order, string Icon)>
{ {
(MenuKeys.Dashboard, "Tổng quan", null, 10, "LayoutDashboard"), (MenuKeys.Dashboard, "Tổng quan", null, 10, "LayoutDashboard"),
(MenuKeys.Master, "Danh mục", null, 20, "Database"), // [S58 2026-06-11] "Danh mục" 20→80: anh yêu cầu đưa xuống CUỐI sidebar
// (sau Reports 50, trước vùng System 90 admin). Main upsert tự re-set
// Order trên DB cũ. Con (21-25) giữ nguyên — order chỉ so trong siblings.
(MenuKeys.Master, "Danh mục", null, 80, "Database"),
(MenuKeys.Suppliers, "Nhà cung cấp", MenuKeys.Master, 21, "Building2"), (MenuKeys.Suppliers, "Nhà cung cấp", MenuKeys.Master, 21, "Building2"),
(MenuKeys.Projects, "Dự án", MenuKeys.Master, 22, "FolderKanban"), (MenuKeys.Projects, "Dự án", MenuKeys.Master, 22, "FolderKanban"),
(MenuKeys.Departments, "Phòng ban", MenuKeys.Master, 23, "Users"), (MenuKeys.Departments, "Phòng ban", MenuKeys.Master, 23, "Users"),
@ -2050,7 +2053,15 @@ public static class DbInitializer
// [S57] Mở quyền XEM (Read-only) cho TẤT CẢ role để mọi bộ phận review/góp ý // [S57] Mở quyền XEM (Read-only) cho TẤT CẢ role để mọi bộ phận review/góp ý
// các module HRM + Văn phòng số + Danh mục (master). KHÔNG đụng Duyệt NCC // các module HRM + Văn phòng số + Danh mục (master). KHÔNG đụng Duyệt NCC
// (Pe_*/PeWf_*/AwV2 — sắp go-live, giữ phân quyền cũ), Contracts/Budgets/System. // (Pe_*/PeWf_*/AwV2 — sắp go-live, giữ phân quyền cũ), Contracts/Budgets/System.
// [S58] Scope grant THU HẸP còn Master/Catalogs/Pe_* — xem note trong method.
await SeedAllRolesReviewReadPermissionsAsync(db, roleManager, logger); await SeedAllRolesReviewReadPermissionsAsync(db, roleManager, logger);
// [S58 2026-06-11] TẠM ẨN module chưa golive với user thường (anh yêu cầu,
// screenshot eoffice): thu hồi quyền HRM (Hrm*) + Văn phòng số (Off*) +
// Cá nhân (Personal) khỏi MỌI role TRỪ Admin. Menu tự ẩn cả 2 app
// (GetMyMenuTree lọc CanRead). Chạy SAU grant seed để revoke thắng.
// Mở lại sau golive: gỡ prefix khỏi revoke + thêm lại vào InReviewScope.
await RevokeTemporarilyHiddenModulesAsync(db, roleManager, logger);
} }
// [S57] Cấp CanRead (CHỈ xem) cho MỌI role trên menu HRM + Office + Master để mọi // [S57] Cấp CanRead (CHỈ xem) cho MỌI role trên menu HRM + Office + Master để mọi
@ -2068,12 +2079,13 @@ public static class DbInitializer
private static async Task SeedAllRolesReviewReadPermissionsAsync( private static async Task SeedAllRolesReviewReadPermissionsAsync(
ApplicationDbContext db, RoleManager<Role> roleManager, ILogger logger) ApplicationDbContext db, RoleManager<Role> roleManager, ILogger logger)
{ {
// Scope read-only = HRM (Hrm*) + Office (Off*) + Personal + Master + Catalogs. // Scope grant = Master + Catalogs + Pe_*.
// [S57bis] +Pe_* (Duyệt NCC) — semantics riêng read+create xử lý bên dưới. // [S57bis] +Pe_* (Duyệt NCC) — semantics riêng read+create xử lý bên dưới.
// Loại trừ tự nhiên (không match prefix): PeWf_* (4th char 'W' ≠ '_'), // [S58] BỎ Hrm*/Off*/Personal khỏi grant — sếp yêu cầu TẠM ẨN HRM + Văn phòng
// AwV2_*, Ct_*, Bg_*, Wf_*, System keys. // số + Cá nhân với user thường (chưa golive các module này). Revoke tương ứng
// ở RevokeTemporarilyHiddenModulesAsync (chạy sau). Loại trừ tự nhiên (không
// match prefix): PeWf_* (ký tự thứ 3 'W' ≠ '_'), AwV2_*, Ct_*, Bg_*, Wf_*, System.
static bool InReviewScope(string key) => static bool InReviewScope(string key) =>
key.StartsWith("Hrm") || key.StartsWith("Off") || key == MenuKeys.Personal ||
key.StartsWith("Catalog") || key == MenuKeys.Master || key.StartsWith("Catalog") || key == MenuKeys.Master ||
key == MenuKeys.Suppliers || key == MenuKeys.Projects || key == MenuKeys.Departments || key == MenuKeys.Suppliers || key == MenuKeys.Projects || key == MenuKeys.Departments ||
key.StartsWith("Pe_"); key.StartsWith("Pe_");
@ -2151,6 +2163,50 @@ public static class DbInitializer
} }
} }
// [S58 2026-06-11] Thu hồi quyền các module TẠM ẨN (chưa golive — anh yêu cầu từ
// screenshot eoffice) khỏi mọi role non-Admin: HRM (Hrm* gồm Hrm_Config*) +
// Văn phòng số (Off* gồm Off_ChamCong đã re-parent về Cá nhân) + root Cá nhân
// (Personal). Set cả 4 cờ CRUD=false (KHÔNG xóa row — giữ vết, flip lại nhanh
// khi golive). Admin GIỮ nguyên để quản trị/chuẩn bị dữ liệu.
// Lưu ý mức che: ẩn menu (GetMyMenuTree lọc CanRead) + permission matrix; FE
// KHÔNG có PermissionGuard per-route nên gõ URL trực tiếp vẫn render trang
// (API self-service vẫn [Authorize] thường) — chấp nhận cho mức "tạm ẩn".
// Idempotent: lần 2 không row nào còn cờ true → 0 update.
private static async Task RevokeTemporarilyHiddenModulesAsync(
ApplicationDbContext db, RoleManager<Role> roleManager, ILogger logger)
{
var adminRole = await roleManager.FindByNameAsync(AppRoles.Admin);
if (adminRole is null)
{
logger.LogWarning("RevokeTemporarilyHiddenModulesAsync: skip — Admin role chưa seed.");
return;
}
var adminRoleId = adminRole.Id;
var rows = await db.Permissions
.Where(p => p.RoleId != adminRoleId
&& (p.MenuKey.StartsWith("Hrm") || p.MenuKey.StartsWith("Off")
|| p.MenuKey == MenuKeys.Personal)
&& (p.CanRead || p.CanCreate || p.CanUpdate || p.CanDelete))
.ToListAsync();
foreach (var row in rows)
{
row.CanRead = false;
row.CanCreate = false;
row.CanUpdate = false;
row.CanDelete = false;
}
if (rows.Count > 0)
{
await db.SaveChangesAsync();
logger.LogInformation(
"Revoked {Count} permission rows — tạm ẩn HRM/Văn phòng số/Cá nhân khỏi non-Admin (S58)",
rows.Count);
}
}
// [Plan CA S29 2026-05-22] Permission defaults cho role CatalogManager. // [Plan CA S29 2026-05-22] Permission defaults cho role CatalogManager.
// Strategy: full CRUD trên 9 menu key danh mục dùng chung: // Strategy: full CRUD trên 9 menu key danh mục dùng chung:
// - Master (root group) + Suppliers + Projects + Departments // - Master (root group) + Suppliers + Projects + Departments