add permissions and fix issues

This commit is contained in:
Marshal
2026-07-23 20:24:20 +00:00
parent 40f16f3cec
commit 668b5e1c9d
40 changed files with 18634 additions and 342 deletions

View File

@@ -57,7 +57,6 @@ export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [
perm('a1000001-0001-4000-8000-000000000021', 'edr_freight_app:bookings:upload_clearance_output', 'Upload customs output documents'),
perm('a1000001-0001-4000-8000-000000000022', 'edr_freight_app:bookings:finalize_clearance', 'Finalize document clearance'),
perm('a1000001-0001-4000-8000-00000000000f', 'edr_freight_app:train_scheduling:view', 'View train scheduling'),
perm('a1000001-0001-4000-8000-000000000010', 'edr_freight_app:train_scheduling:manage', 'Manage train scheduling'),
perm('a1000001-0001-4000-8000-000000000011', 'edr_freight_app:fleet:view', 'View fleet'),
perm('a1000001-0001-4000-8000-000000000012', 'edr_freight_app:fleet:manage', 'Manage fleet'),
perm('a1000001-0001-4000-8000-000000000013', 'edr_freight_app:admin', 'Freight administration'),
@@ -83,7 +82,10 @@ export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [
perm('a3000001-0001-4000-8000-000000000006', 'edr_freight_app:contracts:approve_director', 'Approve contract as director'),
perm('a3000001-0001-4000-8000-000000000007', 'edr_freight_app:contracts:approve_ceo', 'Approve contract as CEO'),
perm('a3000001-0001-4000-8000-000000000008', 'edr_freight_app:contracts:generate_contract', 'Generate contract document'),
perm('a3000001-0001-4000-8000-000000000009', 'edr_freight_app:contracts:sign_staff', 'Staff contract signature'),
// Staff counter-signature is split per freight type too — fresh ids for the
// same reason as the intake keys above.
perm('a3000001-0001-4000-8000-000000000017', 'edr_freight_app:contracts:sign_staff:bulk', 'Staff contract signature: bulk'),
perm('a3000001-0001-4000-8000-000000000018', 'edr_freight_app:contracts:sign_staff:container', 'Staff contract signature: container'),
perm('a3000001-0001-4000-8000-00000000000a', 'edr_freight_app:contracts:clearance_review', 'Review pre-booking clearance docs'),
perm('a3000001-0001-4000-8000-00000000000b', 'edr_freight_app:contracts:finalize_clearance', 'Finalize pre-booking clearance'),
perm('a3000001-0001-4000-8000-00000000000c', 'edr_freight_app:contracts:create_booking', 'GL ET create booking under contract'),
@@ -93,24 +95,42 @@ export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [
perm('a3000001-0001-4000-8000-000000000010', 'edr_freight_app:contracts:clearance_duty_advise', 'Advise contract duty/tax'),
];
const RULE_ENGINE_PERMISSION_IDS: Record<RuleEngineResourceSlug, { view: string; manage: string }> = {
'cargo-types': { view: 'b2000001-0001-4000-8000-000000000001', manage: 'b2000001-0001-4000-8000-000000000002' },
'container-types': { view: 'b2000001-0001-4000-8000-000000000003', manage: 'b2000001-0001-4000-8000-000000000004' },
'wagon-types': { view: 'b2000001-0001-4000-8000-000000000015', manage: 'b2000001-0001-4000-8000-000000000016' },
'service-types': { view: 'b2000001-0001-4000-8000-000000000005', manage: 'b2000001-0001-4000-8000-000000000006' },
yards: { view: 'b2000001-0001-4000-8000-000000000007', manage: 'b2000001-0001-4000-8000-000000000008' },
'shipping-lines': { view: 'b2000001-0001-4000-8000-000000000009', manage: 'b2000001-0001-4000-8000-00000000000a' },
'weight-limit-rules': { view: 'b2000001-0001-4000-8000-00000000000b', manage: 'b2000001-0001-4000-8000-00000000000c' },
'priority-configs': { view: 'b2000001-0001-4000-8000-00000000000f', manage: 'b2000001-0001-4000-8000-000000000010' },
rates: { view: 'b2000001-0001-4000-8000-000000000011', manage: 'b2000001-0001-4000-8000-000000000012' },
'approval-rules': { view: 'b2000001-0001-4000-8000-000000000013', manage: 'b2000001-0001-4000-8000-000000000014' },
'yard-distances': { view: 'b2000001-0001-4000-8000-000000000018', manage: 'b2000001-0001-4000-8000-000000000019' },
// Existing per-slug view ids are kept as-is: position-type grants reference
// them by id, so re-minting would orphan those rows.
const RULE_ENGINE_VIEW_IDS: Record<RuleEngineResourceSlug, string> = {
'cargo-types': 'b2000001-0001-4000-8000-000000000001',
'container-types': 'b2000001-0001-4000-8000-000000000003',
'wagon-types': 'b2000001-0001-4000-8000-000000000015',
'service-types': 'b2000001-0001-4000-8000-000000000005',
yards: 'b2000001-0001-4000-8000-000000000007',
'shipping-lines': 'b2000001-0001-4000-8000-000000000009',
'weight-limit-rules': 'b2000001-0001-4000-8000-00000000000b',
'priority-configs': 'b2000001-0001-4000-8000-00000000000f',
rates: 'b2000001-0001-4000-8000-000000000011',
'approval-rules': 'b2000001-0001-4000-8000-000000000013',
'yard-distances': 'b2000001-0001-4000-8000-000000000018',
};
// CRUD replaces the retired coarse `:manage`. New ids live in a fresh block
// (b2000002-…) so a stale `:manage` grant can never silently confer a CRUD
// action — the migration re-grants create/update/delete explicitly.
const RULE_ENGINE_CRUD_ACTIONS = ['create', 'update', 'delete'] as const;
type RuleEngineCrudAction = (typeof RULE_ENGINE_CRUD_ACTIONS)[number];
const ruleEngineCrudId = (
slug: RuleEngineResourceSlug,
action: RuleEngineCrudAction,
): string => {
const n =
RULE_ENGINE_RESOURCE_SLUGS.indexOf(slug) * 3 +
RULE_ENGINE_CRUD_ACTIONS.indexOf(action) +
1; // 1..33
return `b2000002-0001-4000-8000-${n.toString(16).padStart(12, '0')}`;
};
/**
* Slugs whose changes go through a separate approver. `manage` lets a staff
* member propose a change; only `approve` lets someone put it into effect.
* Only listed slugs get the permission — the rest are manage-only.
* Slugs whose changes go through a separate approver. CRUD lets a staff member
* propose a change; only `approve` lets someone put it into effect. Only listed
* slugs get the permission.
*/
const RULE_ENGINE_APPROVE_PERMISSION_IDS: Partial<Record<RuleEngineResourceSlug, string>> = {
rates: 'b2000001-0001-4000-8000-000000000017',
@@ -121,11 +141,12 @@ export type RuleEngineApprovableSlug = 'rates';
export const RULE_ENGINE_PERMISSIONS: FreightPermissionSeed[] = RULE_ENGINE_RESOURCE_SLUGS.flatMap(
(slug) => {
const resource = slugToResourceKey(slug);
const ids = RULE_ENGINE_PERMISSION_IDS[slug];
const approveId = RULE_ENGINE_APPROVE_PERMISSION_IDS[slug];
return [
perm(ids.view, `edr_freight_app:rule_engine:${resource}:view`, `View ${slug}`),
perm(ids.manage, `edr_freight_app:rule_engine:${resource}:manage`, `Manage ${slug}`),
perm(RULE_ENGINE_VIEW_IDS[slug], `edr_freight_app:rule_engine:${resource}:view`, `View ${slug}`),
perm(ruleEngineCrudId(slug, 'create'), `edr_freight_app:rule_engine:${resource}:create`, `Create ${slug}`),
perm(ruleEngineCrudId(slug, 'update'), `edr_freight_app:rule_engine:${resource}:update`, `Update ${slug}`),
perm(ruleEngineCrudId(slug, 'delete'), `edr_freight_app:rule_engine:${resource}:delete`, `Delete ${slug}`),
...(approveId
? [perm(approveId, `edr_freight_app:rule_engine:${resource}:approve`, `Approve ${slug} changes`)]
: []),
@@ -395,7 +416,10 @@ export const FREIGHT_PERMS = {
approveDirector: 'edr_freight_app:contracts:approve_director',
approveCeo: 'edr_freight_app:contracts:approve_ceo',
generateContract: 'edr_freight_app:contracts:generate_contract',
signStaff: 'edr_freight_app:contracts:sign_staff',
signStaff: {
bulk: 'edr_freight_app:contracts:sign_staff:bulk',
container: 'edr_freight_app:contracts:sign_staff:container',
},
clearanceReview: 'edr_freight_app:contracts:clearance_review',
finalizeClearance: 'edr_freight_app:contracts:finalize_clearance',
createBooking: 'edr_freight_app:contracts:create_booking',
@@ -406,7 +430,6 @@ export const FREIGHT_PERMS = {
},
trainScheduling: {
view: 'edr_freight_app:train_scheduling:view',
manage: 'edr_freight_app:train_scheduling:manage',
create: 'edr_freight_app:train_scheduling:create',
update: 'edr_freight_app:train_scheduling:update',
cancel: 'edr_freight_app:train_scheduling:cancel',
@@ -421,8 +444,12 @@ export const FREIGHT_PERMS = {
ruleEngine: {
view: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:view`,
manage: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:manage`,
create: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:create`,
update: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:update`,
delete: (slug: RuleEngineResourceSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:delete`,
approve: (slug: RuleEngineApprovableSlug) =>
`edr_freight_app:rule_engine:${slugToResourceKey(slug)}:approve`,
},
@@ -751,7 +778,11 @@ export const ROLE_PERMISSION_PRESETS = {
FREIGHT_PERMS.bookings.view,
FREIGHT_PERMS.bookings.operations,
FREIGHT_PERMS.trainScheduling.view,
FREIGHT_PERMS.trainScheduling.manage,
FREIGHT_PERMS.trainScheduling.create,
FREIGHT_PERMS.trainScheduling.update,
FREIGHT_PERMS.trainScheduling.cancel,
FREIGHT_PERMS.trainScheduling.reschedule,
FREIGHT_PERMS.trainScheduling.rulesManage,
FREIGHT_PERMS.fleet.view,
FREIGHT_PERMS.fleet.manage,
...FLEET_GRANULAR_KEYS,
@@ -836,7 +867,7 @@ export const ROLE_PERMISSION_PRESETS = {
...bothFreightTypes(FREIGHT_PERMS.contracts.reject),
FREIGHT_PERMS.contracts.approveLineStaff,
FREIGHT_PERMS.contracts.generateContract,
FREIGHT_PERMS.contracts.signStaff,
...bothFreightTypes(FREIGHT_PERMS.contracts.signStaff),
],
orgManager: [...BOOKING_RULE_ENGINE_PERMISSION_KEYS],
} as const;