Add role control

This commit is contained in:
Chris Chen
2026-06-23 07:19:08 -07:00
parent deff2264a6
commit 870eeec82a
45 changed files with 1923 additions and 165 deletions
+56
View File
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ROLAC.API.Authorization;
using ROLAC.API.Entities;
namespace ROLAC.API.Data;
@@ -62,6 +63,60 @@ public static class DbSeeder
("visitor", "Visitor — public pages only"),
];
// Default permission matrix — mirrors the hard-coded [Authorize(Roles=...)] rules that
// existed before the configurable RBAC system, so day-one behavior is unchanged.
// super_admin is intentionally absent: it bypasses all checks (see PermissionAuthorizationHandler).
// R=Read, W=Write, D=Delete, A=Approve. Rows are inserted only if missing, so an admin's
// later edits via the Permissions UI are never clobbered on restart.
private static readonly (string Role, string Module, bool R, bool W, bool D, bool A)[] RolePermissionSeed =
[
// Secretary — manages member data.
("secretary", Modules.Members, true, true, true, false),
// Pastor — read-only overview of members and all expenses.
("pastor", Modules.Members, true, false, false, false),
("pastor", Modules.Expenses, true, false, false, false),
// Finance — full control over the finance modules.
("finance", Modules.Givings, true, true, true, false),
("finance", Modules.GivingCategories, true, true, true, false),
("finance", Modules.Expenses, true, true, true, true),
("finance", Modules.ExpenseCategories, true, true, true, false),
("finance", Modules.OfferingSessions, true, true, true, true),
("finance", Modules.FinanceDashboard, true, false, false, false),
("finance", Modules.MonthlyStatements, true, true, false, true),
("finance", Modules.ChurchProfile, true, true, false, false),
("finance", Modules.Disbursements, true, true, true, true),
];
public static async Task SeedRolePermissionsAsync(AppDbContext db)
{
var rolesByName = await db.Roles
.Where(r => r.Name != null)
.ToDictionaryAsync(r => r.Name!, r => r.Id);
foreach (var (role, module, read, write, delete, approve) in RolePermissionSeed)
{
if (!rolesByName.TryGetValue(role, out var roleId))
continue;
var exists = await db.RolePermissions.AnyAsync(p => p.RoleId == roleId && p.Module == module);
if (exists)
continue; // never clobber an admin's edit
db.RolePermissions.Add(new RolePermission
{
RoleId = roleId,
Module = module,
CanRead = read,
CanWrite = write,
CanDelete = delete,
CanApprove = approve,
});
}
await db.SaveChangesAsync();
}
public static async Task SeedRolesAsync(RoleManager<AppRole> roleManager)
{
foreach (var (name, description) in Roles)
@@ -159,6 +214,7 @@ public static class DbSeeder
await SeedRolesAsync(roleManager);
var db = services.GetRequiredService<AppDbContext>();
await SeedRolePermissionsAsync(db);
await SeedGivingCategoriesAsync(db);
await SeedMinistriesAsync(db);
await SeedExpenseCategoriesAsync(db);