PSA/server/migrations/20250716144947_update_client_portal_permissions.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

553 lines
30 KiB
JavaScript

exports.up = async function(knex) {
// Get all tenants
const tenants = await knex('tenants').pluck('tenant');
console.log(`Updating permissions for ${tenants.length} tenants`);
for (const tenant of tenants) {
// Step 1: Delete all role permissions for this tenant
console.log(`Removing all role permissions for tenant ${tenant}`);
await knex('role_permissions').where({ tenant }).delete();
// Step 2: Delete all permissions for this tenant
console.log(`Removing all permissions for tenant ${tenant}`);
await knex('permissions').where({ tenant }).delete();
// Step 3: Remove user assignments for roles that will be deleted
console.log(`Removing user role assignments for unwanted roles in tenant ${tenant}`);
const rolesToDelete = await knex('roles')
.where({ tenant })
.where(function() {
this.where({ role_name: 'Manager', msp: true });
})
.select('role_id');
if (rolesToDelete.length > 0) {
const roleIds = rolesToDelete.map(r => r.role_id);
await knex('user_roles')
.where({ tenant })
.whereIn('role_id', roleIds)
.delete();
console.log(`Removed user role assignments for ${roleIds.length} roles`);
}
// Step 4: Remove unwanted roles
console.log(`Removing unwanted roles for tenant ${tenant}`);
await knex('roles')
.where({ tenant })
.where(function() {
this.where({ role_name: 'Manager', msp: true });
})
.delete();
// Step 5: Create all permissions from permissions_list.md
console.log(`Creating permissions for tenant ${tenant}`);
const allPermissions = [
// MSP permissions
// Asset permissions
{ tenant, resource: 'asset', action: 'create', msp: true, client: false, description: 'Create assets' },
{ tenant, resource: 'asset', action: 'read', msp: true, client: false, description: 'View assets' },
{ tenant, resource: 'asset', action: 'update', msp: true, client: false, description: 'Update assets' },
{ tenant, resource: 'asset', action: 'delete', msp: true, client: false, description: 'Delete assets' },
// Billing permissions
{ tenant, resource: 'billing', action: 'create', msp: true, client: false, description: 'Create billing records' },
{ tenant, resource: 'billing', action: 'read', msp: true, client: false, description: 'View billing information' },
{ tenant, resource: 'billing', action: 'update', msp: true, client: false, description: 'Update billing records' },
{ tenant, resource: 'billing', action: 'delete', msp: true, client: false, description: 'Delete billing records' },
// Client permissions
{ tenant, resource: 'client', action: 'create', msp: true, client: false, description: 'Create clients' },
{ tenant, resource: 'client', action: 'read', msp: true, client: false, description: 'View clients' },
{ tenant, resource: 'client', action: 'update', msp: true, client: false, description: 'Update clients' },
{ tenant, resource: 'client', action: 'delete', msp: true, client: false, description: 'Delete clients' },
// Contact permissions
{ tenant, resource: 'contact', action: 'create', msp: true, client: false, description: 'Create contacts' },
{ tenant, resource: 'contact', action: 'read', msp: true, client: false, description: 'View contacts' },
{ tenant, resource: 'contact', action: 'update', msp: true, client: false, description: 'Update contacts' },
{ tenant, resource: 'contact', action: 'delete', msp: true, client: false, description: 'Delete contacts' },
// Credit permissions
{ tenant, resource: 'credit', action: 'create', msp: true, client: false, description: 'Create credits' },
{ tenant, resource: 'credit', action: 'read', msp: true, client: false, description: 'View credits' },
{ tenant, resource: 'credit', action: 'update', msp: true, client: false, description: 'Update credits' },
{ tenant, resource: 'credit', action: 'delete', msp: true, client: false, description: 'Delete credits' },
{ tenant, resource: 'credit', action: 'transfer', msp: true, client: false, description: 'Transfer credits' },
{ tenant, resource: 'credit', action: 'reconcile', msp: true, client: false, description: 'Reconcile credits' },
// Document permissions
{ tenant, resource: 'document', action: 'create', msp: true, client: false, description: 'Create documents' },
{ tenant, resource: 'document', action: 'read', msp: true, client: false, description: 'View documents' },
{ tenant, resource: 'document', action: 'update', msp: true, client: false, description: 'Update documents' },
{ tenant, resource: 'document', action: 'delete', msp: true, client: false, description: 'Delete documents' },
// Invoice permissions
{ tenant, resource: 'invoice', action: 'create', msp: true, client: false, description: 'Create invoices' },
{ tenant, resource: 'invoice', action: 'read', msp: true, client: false, description: 'View invoices' },
{ tenant, resource: 'invoice', action: 'update', msp: true, client: false, description: 'Update invoices' },
{ tenant, resource: 'invoice', action: 'delete', msp: true, client: false, description: 'Delete invoices' },
{ tenant, resource: 'invoice', action: 'generate', msp: true, client: false, description: 'Generate invoices' },
{ tenant, resource: 'invoice', action: 'finalize', msp: true, client: false, description: 'Finalize invoices' },
{ tenant, resource: 'invoice', action: 'send', msp: true, client: false, description: 'Send invoices' },
{ tenant, resource: 'invoice', action: 'void', msp: true, client: false, description: 'Void invoices' },
// Profile permissions
{ tenant, resource: 'profile', action: 'create', msp: true, client: false, description: 'Create profiles' },
{ tenant, resource: 'profile', action: 'read', msp: true, client: false, description: 'View profiles' },
{ tenant, resource: 'profile', action: 'update', msp: true, client: false, description: 'Update profiles' },
{ tenant, resource: 'profile', action: 'delete', msp: true, client: false, description: 'Delete profiles' },
// Project permissions
{ tenant, resource: 'project', action: 'create', msp: true, client: false, description: 'Create projects' },
{ tenant, resource: 'project', action: 'read', msp: true, client: false, description: 'View projects' },
{ tenant, resource: 'project', action: 'update', msp: true, client: false, description: 'Update projects' },
{ tenant, resource: 'project', action: 'delete', msp: true, client: false, description: 'Delete projects' },
// Project task permissions
{ tenant, resource: 'project_task', action: 'create', msp: true, client: false, description: 'Create project tasks' },
{ tenant, resource: 'project_task', action: 'read', msp: true, client: false, description: 'View project tasks' },
{ tenant, resource: 'project_task', action: 'update', msp: true, client: false, description: 'Update project tasks' },
{ tenant, resource: 'project_task', action: 'delete', msp: true, client: false, description: 'Delete project tasks' },
// Tag permissions
{ tenant, resource: 'tag', action: 'create', msp: true, client: false, description: 'Create tags' },
{ tenant, resource: 'tag', action: 'read', msp: true, client: false, description: 'View tags' },
{ tenant, resource: 'tag', action: 'update', msp: true, client: false, description: 'Update tags' },
{ tenant, resource: 'tag', action: 'delete', msp: true, client: false, description: 'Delete tags' },
// Technician dispatch permissions
{ tenant, resource: 'technician_dispatch', action: 'create', msp: true, client: false, description: 'Create dispatch entries' },
{ tenant, resource: 'technician_dispatch', action: 'read', msp: true, client: false, description: 'View dispatch entries' },
{ tenant, resource: 'technician_dispatch', action: 'update', msp: true, client: false, description: 'Update dispatch entries' },
{ tenant, resource: 'technician_dispatch', action: 'delete', msp: true, client: false, description: 'Delete dispatch entries' },
// Ticket permissions
{ tenant, resource: 'ticket', action: 'create', msp: true, client: false, description: 'Create tickets' },
{ tenant, resource: 'ticket', action: 'read', msp: true, client: false, description: 'View tickets' },
{ tenant, resource: 'ticket', action: 'update', msp: true, client: false, description: 'Update tickets' },
{ tenant, resource: 'ticket', action: 'delete', msp: true, client: false, description: 'Delete tickets' },
// Time entry permissions
{ tenant, resource: 'timeentry', action: 'create', msp: true, client: false, description: 'Create time entries' },
{ tenant, resource: 'timeentry', action: 'read', msp: true, client: false, description: 'View time entries' },
{ tenant, resource: 'timeentry', action: 'update', msp: true, client: false, description: 'Update time entries' },
{ tenant, resource: 'timeentry', action: 'delete', msp: true, client: false, description: 'Delete time entries' },
// Timesheet permissions
{ tenant, resource: 'timesheet', action: 'create', msp: true, client: false, description: 'Create timesheets' },
{ tenant, resource: 'timesheet', action: 'read', msp: true, client: false, description: 'View timesheets' },
{ tenant, resource: 'timesheet', action: 'update', msp: true, client: false, description: 'Update timesheets' },
{ tenant, resource: 'timesheet', action: 'delete', msp: true, client: false, description: 'Delete timesheets' },
{ tenant, resource: 'timesheet', action: 'read_all', msp: true, client: false, description: 'View all timesheets' },
{ tenant, resource: 'timesheet', action: 'submit', msp: true, client: false, description: 'Submit timesheets' },
{ tenant, resource: 'timesheet', action: 'approve', msp: true, client: false, description: 'Approve timesheets' },
{ tenant, resource: 'timesheet', action: 'reverse', msp: true, client: false, description: 'Reverse timesheet approvals' },
// User permissions
{ tenant, resource: 'user', action: 'create', msp: true, client: false, description: 'Create users' },
{ tenant, resource: 'user', action: 'read', msp: true, client: false, description: 'View users' },
{ tenant, resource: 'user', action: 'update', msp: true, client: false, description: 'Update users' },
{ tenant, resource: 'user', action: 'delete', msp: true, client: false, description: 'Delete users' },
{ tenant, resource: 'user', action: 'invite', msp: true, client: false, description: 'Invite users' },
{ tenant, resource: 'user', action: 'reset_password', msp: true, client: false, description: 'Reset user passwords' },
// User schedule permissions
{ tenant, resource: 'user_schedule', action: 'create', msp: true, client: false, description: 'Create user schedules' },
{ tenant, resource: 'user_schedule', action: 'read', msp: true, client: false, description: 'View user schedules' },
{ tenant, resource: 'user_schedule', action: 'update', msp: true, client: false, description: 'Update user schedules' },
{ tenant, resource: 'user_schedule', action: 'delete', msp: true, client: false, description: 'Delete user schedules' },
// Settings permissions
{ tenant, resource: 'ticket_settings', action: 'create', msp: true, client: false, description: 'Create ticket settings' },
{ tenant, resource: 'ticket_settings', action: 'read', msp: true, client: false, description: 'View ticket settings' },
{ tenant, resource: 'ticket_settings', action: 'update', msp: true, client: false, description: 'Update ticket settings' },
{ tenant, resource: 'ticket_settings', action: 'delete', msp: true, client: false, description: 'Delete ticket settings' },
{ tenant, resource: 'user_settings', action: 'create', msp: true, client: false, description: 'Create user settings' },
{ tenant, resource: 'user_settings', action: 'read', msp: true, client: false, description: 'View user settings' },
{ tenant, resource: 'user_settings', action: 'update', msp: true, client: false, description: 'Update user settings' },
{ tenant, resource: 'user_settings', action: 'delete', msp: true, client: false, description: 'Delete user settings' },
{ tenant, resource: 'system_settings', action: 'create', msp: true, client: false, description: 'Create system settings' },
{ tenant, resource: 'system_settings', action: 'read', msp: true, client: false, description: 'View system settings' },
{ tenant, resource: 'system_settings', action: 'update', msp: true, client: false, description: 'Update system settings' },
{ tenant, resource: 'system_settings', action: 'delete', msp: true, client: false, description: 'Delete system settings' },
{ tenant, resource: 'security_settings', action: 'create', msp: true, client: false, description: 'Create security settings' },
{ tenant, resource: 'security_settings', action: 'read', msp: true, client: false, description: 'View security settings' },
{ tenant, resource: 'security_settings', action: 'update', msp: true, client: false, description: 'Update security settings' },
{ tenant, resource: 'security_settings', action: 'delete', msp: true, client: false, description: 'Delete security settings' },
{ tenant, resource: 'timeentry_settings', action: 'create', msp: true, client: false, description: 'Create time entry settings' },
{ tenant, resource: 'timeentry_settings', action: 'read', msp: true, client: false, description: 'View time entry settings' },
{ tenant, resource: 'timeentry_settings', action: 'update', msp: true, client: false, description: 'Update time entry settings' },
{ tenant, resource: 'timeentry_settings', action: 'delete', msp: true, client: false, description: 'Delete time entry settings' },
{ tenant, resource: 'billing_settings', action: 'create', msp: true, client: false, description: 'Create billing settings' },
{ tenant, resource: 'billing_settings', action: 'read', msp: true, client: false, description: 'View billing settings' },
{ tenant, resource: 'billing_settings', action: 'update', msp: true, client: false, description: 'Update billing settings' },
{ tenant, resource: 'billing_settings', action: 'delete', msp: true, client: false, description: 'Delete billing settings' },
// Client portal permissions
{ tenant, resource: 'billing', action: 'read', msp: false, client: true, description: 'View billing information in client portal' },
{ tenant, resource: 'billing', action: 'create', msp: false, client: true, description: 'Create billing entries in client portal' },
{ tenant, resource: 'billing', action: 'update', msp: false, client: true, description: 'Update billing entries in client portal' },
{ tenant, resource: 'client', action: 'read', msp: false, client: true, description: 'View client information' },
{ tenant, resource: 'client', action: 'create', msp: false, client: true, description: 'Create client information' },
{ tenant, resource: 'client', action: 'update', msp: false, client: true, description: 'Update client information' },
{ tenant, resource: 'client', action: 'delete', msp: false, client: true, description: 'Delete client information' },
{ tenant, resource: 'project', action: 'read', msp: false, client: true, description: 'View projects in client portal' },
{ tenant, resource: 'project', action: 'create', msp: false, client: true, description: 'Create projects in client portal' },
{ tenant, resource: 'project', action: 'update', msp: false, client: true, description: 'Update projects in client portal' },
{ tenant, resource: 'project', action: 'delete', msp: false, client: true, description: 'Delete projects in client portal' },
{ tenant, resource: 'ticket', action: 'read', msp: false, client: true, description: 'View tickets in client portal' },
{ tenant, resource: 'ticket', action: 'create', msp: false, client: true, description: 'Create tickets in client portal' },
{ tenant, resource: 'ticket', action: 'update', msp: false, client: true, description: 'Update tickets in client portal' },
{ tenant, resource: 'time_management', action: 'read', msp: false, client: true, description: 'View time management in client portal' },
{ tenant, resource: 'time_management', action: 'create', msp: false, client: true, description: 'Create time entries in client portal' },
{ tenant, resource: 'time_management', action: 'update', msp: false, client: true, description: 'Update time entries in client portal' },
{ tenant, resource: 'time_management', action: 'delete', msp: false, client: true, description: 'Delete time entries in client portal' },
{ tenant, resource: 'user', action: 'read', msp: false, client: true, description: 'View users in client portal' },
{ tenant, resource: 'user', action: 'create', msp: false, client: true, description: 'Create users in client portal' },
{ tenant, resource: 'user', action: 'update', msp: false, client: true, description: 'Update users in client portal' },
{ tenant, resource: 'user', action: 'delete', msp: false, client: true, description: 'Delete users in client portal' },
{ tenant, resource: 'user', action: 'reset_password', msp: false, client: true, description: 'Reset passwords in client portal' },
{ tenant, resource: 'settings', action: 'read', msp: false, client: true, description: 'View settings in client portal' },
{ tenant, resource: 'settings', action: 'create', msp: false, client: true, description: 'Create settings in client portal' },
{ tenant, resource: 'settings', action: 'update', msp: false, client: true, description: 'Update settings in client portal' },
{ tenant, resource: 'settings', action: 'delete', msp: false, client: true, description: 'Delete settings in client portal' },
{ tenant, resource: 'document', action: 'read', msp: false, client: true, description: 'View documents in client portal' },
{ tenant, resource: 'document', action: 'create', msp: false, client: true, description: 'Create documents in client portal' },
{ tenant, resource: 'document', action: 'update', msp: false, client: true, description: 'Update documents in client portal' }
];
// Insert all permissions
await knex('permissions').insert(allPermissions);
console.log(`Created ${allPermissions.length} permissions for tenant ${tenant}`);
// Step 6: Get all roles for mapping
const roles = await knex('roles').where({ tenant });
const roleMap = {};
roles.forEach(role => {
const key = `${role.msp ? 'msp' : 'client'}_${role.role_name.toLowerCase()}`;
roleMap[key] = role;
});
// Step 7: Assign permissions to roles according to permissions_list.md
// MSP Admin gets all MSP permissions
if (roleMap.msp_admin) {
const mspPermissions = await knex('permissions')
.where({ tenant, msp: true })
.pluck('permission_id');
const adminRolePerms = mspPermissions.map(permission_id => ({
tenant,
role_id: roleMap.msp_admin.role_id,
permission_id
}));
if (adminRolePerms.length > 0) {
await knex('role_permissions').insert(adminRolePerms);
console.log(`Assigned ${adminRolePerms.length} permissions to MSP Admin role`);
}
}
// MSP Finance permissions
if (roleMap.msp_finance) {
const financePermissions = {
asset: ['read'],
billing: ['create', 'read', 'update', 'delete'],
client: ['create', 'read', 'update', 'delete'],
contact: ['create', 'read', 'update', 'delete'],
credit: ['create', 'read', 'update', 'delete', 'transfer', 'reconcile'],
document: ['create', 'read', 'update', 'delete'],
invoice: ['create', 'read', 'update', 'delete', 'generate', 'finalize', 'send', 'void'],
profile: ['create', 'read', 'update'],
project: ['read', 'update'],
project_task: ['read', 'update'],
tag: ['create', 'read'],
technician_dispatch: ['read'],
ticket: ['read', 'update'],
timeentry: ['create', 'read', 'update', 'delete'],
timesheet: ['read', 'read_all', 'submit'],
user: ['read'],
user_schedule: ['read'],
billing_settings: ['create', 'read', 'update', 'delete']
};
const financeRolePerms = [];
for (const [resource, actions] of Object.entries(financePermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: true })
.first();
if (permission) {
financeRolePerms.push({
tenant,
role_id: roleMap.msp_finance.role_id,
permission_id: permission.permission_id
});
}
}
}
if (financeRolePerms.length > 0) {
await knex('role_permissions').insert(financeRolePerms);
console.log(`Assigned ${financeRolePerms.length} permissions to MSP Finance role`);
}
}
// MSP Technician permissions
if (roleMap.msp_technician) {
const technicianPermissions = {
asset: ['create', 'read', 'update'],
client: ['read', 'delete'],
contact: ['read', 'delete'],
document: ['create', 'read', 'update'],
profile: ['read', 'update'],
project: ['read'],
project_task: ['create', 'read', 'update'],
tag: ['create', 'read', 'update'],
technician_dispatch: ['read'],
ticket: ['create', 'read', 'update'],
timeentry: ['create', 'read', 'update'],
timesheet: ['read', 'update', 'read_all', 'submit'],
user_schedule: ['read'],
ticket_settings: ['read']
};
const technicianRolePerms = [];
for (const [resource, actions] of Object.entries(technicianPermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: true })
.first();
if (permission) {
technicianRolePerms.push({
tenant,
role_id: roleMap.msp_technician.role_id,
permission_id: permission.permission_id
});
}
}
}
if (technicianRolePerms.length > 0) {
await knex('role_permissions').insert(technicianRolePerms);
console.log(`Assigned ${technicianRolePerms.length} permissions to MSP Technician role`);
}
}
// MSP Project Manager permissions
if (roleMap.msp_project_manager) {
const projectManagerPermissions = {
asset: ['read'],
billing: ['read'],
client: ['create', 'read', 'update'],
contact: ['create', 'read', 'update'],
document: ['create', 'read', 'update'],
invoice: ['read'],
profile: ['read', 'update'],
project: ['create', 'read', 'update', 'delete'],
project_task: ['create', 'read', 'update', 'delete'],
tag: ['create', 'read', 'update'],
technician_dispatch: ['read'],
ticket: ['create', 'read', 'update'],
timeentry: ['create', 'read', 'update'],
timesheet: ['read', 'update', 'read_all', 'submit', 'approve', 'reverse'],
user: ['read', 'invite'],
user_schedule: ['read'],
user_settings: ['read'],
billing_settings: ['read']
};
const pmRolePerms = [];
for (const [resource, actions] of Object.entries(projectManagerPermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: true })
.first();
if (permission) {
pmRolePerms.push({
tenant,
role_id: roleMap.msp_project_manager.role_id,
permission_id: permission.permission_id
});
}
}
}
if (pmRolePerms.length > 0) {
await knex('role_permissions').insert(pmRolePerms);
console.log(`Assigned ${pmRolePerms.length} permissions to MSP Project Manager role`);
}
}
// MSP Dispatcher permissions
if (roleMap.msp_dispatcher) {
const dispatcherPermissions = {
asset: ['read'],
client: ['read'],
contact: ['read'],
document: ['read'],
profile: ['read'],
project: ['read'],
project_task: ['read'],
tag: ['create', 'read', 'update'],
technician_dispatch: ['create', 'read', 'update'],
ticket: ['create', 'read', 'update'],
timeentry: ['read'],
timesheet: ['read'],
user: ['read'],
user_schedule: ['create', 'read', 'update'],
user_settings: ['read']
};
const dispatcherRolePerms = [];
for (const [resource, actions] of Object.entries(dispatcherPermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: true })
.first();
if (permission) {
dispatcherRolePerms.push({
tenant,
role_id: roleMap.msp_dispatcher.role_id,
permission_id: permission.permission_id
});
}
}
}
if (dispatcherRolePerms.length > 0) {
await knex('role_permissions').insert(dispatcherRolePerms);
console.log(`Assigned ${dispatcherRolePerms.length} permissions to MSP Dispatcher role`);
}
}
// Client Portal Admin permissions (role name is 'Admin' with client=true)
const clientAdminRole = roles.find(r => r.role_name === 'Admin' && r.client === true && r.msp === false);
if (clientAdminRole) {
const clientAdminPermissions = {
billing: ['create', 'read', 'update'],
client: ['create', 'read', 'update', 'delete'],
project: ['create', 'read', 'update', 'delete'],
ticket: ['create', 'read', 'update'],
time_management: ['create', 'read', 'update', 'delete'],
user: ['create', 'read', 'update', 'delete', 'reset_password'],
settings: ['create', 'read', 'update', 'delete'],
document: ['create', 'read', 'update']
};
const clientAdminRolePerms = [];
for (const [resource, actions] of Object.entries(clientAdminPermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: false, client: true })
.first();
if (permission) {
clientAdminRolePerms.push({
tenant,
role_id: clientAdminRole.role_id,
permission_id: permission.permission_id
});
}
}
}
if (clientAdminRolePerms.length > 0) {
await knex('role_permissions').insert(clientAdminRolePerms);
console.log(`Assigned ${clientAdminRolePerms.length} permissions to Client Admin role`);
}
}
// Client Finance permissions
const clientFinanceRole = roles.find(r => r.role_name === 'Finance' && r.client === true && r.msp === false);
if (clientFinanceRole) {
const clientFinancePermissions = {
billing: ['read'],
client: ['create', 'read', 'update'],
project: ['read'],
ticket: ['create', 'read', 'update'],
time_management: ['read'],
user: ['read'],
settings: ['read'],
document: ['create', 'read', 'update']
};
const clientFinanceRolePerms = [];
for (const [resource, actions] of Object.entries(clientFinancePermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: false, client: true })
.first();
if (permission) {
clientFinanceRolePerms.push({
tenant,
role_id: clientFinanceRole.role_id,
permission_id: permission.permission_id
});
}
}
}
if (clientFinanceRolePerms.length > 0) {
await knex('role_permissions').insert(clientFinanceRolePerms);
console.log(`Assigned ${clientFinanceRolePerms.length} permissions to Client Finance role`);
}
}
// Client User permissions
const clientUserRole = roles.find(r => r.role_name === 'User' && r.client === true && r.msp === false);
if (clientUserRole) {
const clientUserPermissions = {
client: ['create', 'read', 'update'],
project: ['read'],
ticket: ['create', 'read', 'update'],
time_management: ['read'],
document: ['create', 'read', 'update']
};
const clientUserRolePerms = [];
for (const [resource, actions] of Object.entries(clientUserPermissions)) {
for (const action of actions) {
const permission = await knex('permissions')
.where({ tenant, resource, action, msp: false, client: true })
.first();
if (permission) {
clientUserRolePerms.push({
tenant,
role_id: clientUserRole.role_id,
permission_id: permission.permission_id
});
}
}
}
if (clientUserRolePerms.length > 0) {
await knex('role_permissions').insert(clientUserRolePerms);
console.log(`Assigned ${clientUserRolePerms.length} permissions to Client User role`);
}
}
}
console.log('Permission updates completed');
};
exports.down = async function() {
// This is a complete reset migration, so the down migration
// cannot restore the exact previous state. It will just log a warning.
console.log('WARNING: This migration performed a complete permissions reset.');
console.log('The down migration cannot restore the previous state.');
console.log('Manual intervention may be required to restore permissions.');
};