PSA/server/migrations/20250611165040_add_client_role.cjs
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

146 lines
4.3 KiB
JavaScript

/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = async function(knex) {
// Get all tenants
const tenants = await knex('tenants').select('tenant');
if (!tenants.length) return;
// For each tenant, add the roles if they don't exist
for (const { tenant } of tenants) {
// --- Role Definitions ---
const rolesToCreate = [
{ role_name: 'Client', description: 'Client user role' },
{ role_name: 'Client_Admin', description: 'Client administrator role' },
{ role_name: 'Dispatcher', description: 'Role for users who can dispatch and schedule for other users' }
];
for (const role of rolesToCreate) {
const existingRole = await knex('roles')
.where({ tenant })
.whereRaw('LOWER(role_name) = ?', [role.role_name.toLowerCase()])
.first();
if (!existingRole) {
await knex('roles').insert({
tenant,
role_id: knex.raw('gen_random_uuid()'),
...role
});
}
}
// --- Permission Definitions ---
const getPermissions = async (permissionMap) => {
const permissions = await knex('permissions')
.where({ tenant })
.where(function() {
for (const resource in permissionMap) {
this.orWhere(function() {
this.where('resource', resource).whereIn('action', permissionMap[resource]);
});
}
});
return permissions;
};
const clientPermissionMap = {
'project': ['read'],
'profile': ['read', 'update'],
'asset': ['read'],
'ticket': ['create', 'read', 'update']
};
const clientAdminPermissionMap = {
...clientPermissionMap,
'user': ['create', 'read', 'update', 'delete'],
'billing': ['read'],
'contact': ['create', 'read', 'update', 'delete'],
'company': ['read', 'update'],
'document': ['create', 'read', 'update', 'delete']
};
const dispatcherPermissionMap = {
'schedule': ['create', 'read', 'update', 'delete'],
'user': ['read'],
'ticket': ['read', 'update'],
'company': ['read'],
'contact': ['read']
};
// --- Role-Permission Assignment ---
const assignPermissionsToRole = async (roleName, permissions) => {
const role = await knex('roles')
.where({ tenant })
.whereRaw('LOWER(role_name) = ?', [roleName.toLowerCase()])
.first();
if (role) {
for (const perm of permissions) {
const exists = await knex('role_permissions')
.where({
tenant,
role_id: role.role_id,
permission_id: perm.permission_id
})
.first();
if (!exists) {
await knex('role_permissions').insert({
tenant,
role_id: role.role_id,
permission_id: perm.permission_id
});
}
}
}
};
const clientPermissions = await getPermissions(clientPermissionMap);
const clientAdminPermissions = await getPermissions(clientAdminPermissionMap);
const dispatcherPermissions = await getPermissions(dispatcherPermissionMap);
await assignPermissionsToRole('Client', clientPermissions);
await assignPermissionsToRole('Client_Admin', clientAdminPermissions);
await assignPermissionsToRole('Dispatcher', dispatcherPermissions);
}
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = async function(knex) {
// Get all tenants
const tenants = await knex('tenants').select('tenant');
if (!tenants.length) return;
const roleNames = ['Client', 'Client_Admin', 'Dispatcher'];
for (const { tenant } of tenants) {
// Get the role IDs for the roles we are removing
const rolesToDelete = await knex('roles')
.where({ tenant })
.whereIn('role_name', roleNames)
.select('role_id');
const roleIdsToDelete = rolesToDelete.map(r => r.role_id);
if (roleIdsToDelete.length > 0) {
// Remove role permissions
await knex('role_permissions')
.where({ tenant })
.whereIn('role_id', roleIdsToDelete)
.delete();
// Remove roles
await knex('roles')
.where({ tenant })
.whereIn('role_id', roleIdsToDelete)
.delete();
}
}
};