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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
553 lines
30 KiB
JavaScript
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.');
|
|
}; |