Task #121: Hide Executive Meetings icon from non-executive users
Gate the home-screen "Executive Meetings" app icon behind a new
`executive_meetings.access` permission so only admins and the five
executive_* roles see it. Reuses the existing `app_permissions` →
`getVisibleAppsForUser` machinery; no route or middleware changes.
Changes
- scripts/src/seed.ts
* Added permission `executive_meetings.access`.
* Granted it to: admin, executive_ceo, executive_office_manager,
executive_coord_lead, executive_coordinator, executive_viewer.
* Linked it to apps.slug = 'executive-meetings' via app_permissions.
* All inserts use onConflictDoNothing — re-running the seeder is safe.
- artifacts/api-server/scripts/gate-executive-meetings.mjs (new)
* One-shot, idempotent pg migration that performs the same three
inserts in a single transaction (BEGIN/ROLLBACK on error). Prints
JSON summary with grant counts. Already executed against dev DB
(newRoleGrantsThisRun=6, newAppLinksThisRun=1).
- artifacts/api-server/tests/executive-meetings-visibility.test.mjs (new)
* Regression: creates a fresh `order_receiver`-only user, asserts
/api/apps does NOT include `executive-meetings`; then grants
`executive_coordinator` and asserts it does. Per-run username
prefix + defensive sweep + after-hook cleanup.
Out of scope (not modified)
- artifacts/api-server/src/routes/apps.ts (getVisibleAppsForUser)
- artifacts/api-server/src/routes/executive-meetings.ts
(requireExecutiveAccess)
- Any UI files
Verification
- `node artifacts/api-server/scripts/gate-executive-meetings.mjs` →
ok=true, 6 role grants, 1 app link.
- `node --test tests/executive-meetings-visibility.test.mjs` →
2/2 pass.
- TypeScript clean for scripts package.
- Architect review: PASS, no blocking issues.
This commit is contained in:
@@ -488,6 +488,63 @@ async function main() {
|
||||
await db.insert(rolesTable).values(execRoles).onConflictDoNothing();
|
||||
console.log("Executive Meetings roles created");
|
||||
|
||||
// Executive meetings: gate the home-screen icon to executive roles only.
|
||||
// This adds a single permission, grants it to admin + the 5 executive
|
||||
// roles, and links it to the `executive-meetings` app via app_permissions
|
||||
// so getVisibleAppsForUser will hide the icon for everyone else.
|
||||
// All three inserts are idempotent.
|
||||
await db
|
||||
.insert(permissionsTable)
|
||||
.values({
|
||||
name: "executive_meetings.access",
|
||||
descriptionAr: "الوصول إلى وحدة الاجتماعات التنفيذية",
|
||||
descriptionEn: "Access the Executive Meetings module",
|
||||
})
|
||||
.onConflictDoNothing();
|
||||
|
||||
const [execAccessPerm] = await db
|
||||
.select()
|
||||
.from(permissionsTable)
|
||||
.where(eq(permissionsTable.name, "executive_meetings.access"));
|
||||
|
||||
if (execAccessPerm) {
|
||||
const execRoleNames = [
|
||||
"admin",
|
||||
"executive_ceo",
|
||||
"executive_office_manager",
|
||||
"executive_coord_lead",
|
||||
"executive_coordinator",
|
||||
"executive_viewer",
|
||||
];
|
||||
const allRolesNow = await db.select().from(rolesTable);
|
||||
const execRoleRows = allRolesNow.filter((r) => execRoleNames.includes(r.name));
|
||||
if (execRoleRows.length > 0) {
|
||||
await db
|
||||
.insert(rolePermissionsTable)
|
||||
.values(
|
||||
execRoleRows.map((r) => ({
|
||||
roleId: r.id,
|
||||
permissionId: execAccessPerm.id,
|
||||
})),
|
||||
)
|
||||
.onConflictDoNothing();
|
||||
}
|
||||
|
||||
const [execApp] = await db
|
||||
.select()
|
||||
.from(appsTable)
|
||||
.where(eq(appsTable.slug, "executive-meetings"));
|
||||
if (execApp) {
|
||||
await db
|
||||
.insert(appPermissionsTable)
|
||||
.values({ appId: execApp.id, permissionId: execAccessPerm.id })
|
||||
.onConflictDoNothing();
|
||||
console.log(
|
||||
"App permissions set: executive-meetings app restricted to executive_meetings.access permission",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Executive meetings: sample data for today (idempotent per-date)
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const existingForToday = await db
|
||||
|
||||
Reference in New Issue
Block a user