adds access modifiers for each role

This commit is contained in:
Satyam-Rastogi
2026-05-12 21:08:19 +05:30
parent e85ecd2571
commit 7598f8982a
7 changed files with 517 additions and 119 deletions
+57 -43
View File
@@ -1,21 +1,18 @@
import { ROLES } from '../context/AuthContext';
// ─── Legacy static permissions (preserved for MaskedData, etc.) ───
export const PERMISSIONS = {
// Admin / Owner Capabilities
VIEW_ALL_PROJECTS: 'VIEW_ALL_PROJECTS',
VIEW_ALL_PERSONNEL: 'VIEW_ALL_PERSONNEL',
VIEW_FINANCIALS: 'VIEW_FINANCIALS',
VIEW_SENSITIVE_DATA: 'VIEW_SENSITIVE_DATA', // SSN, Bank Accounts
VIEW_SENSITIVE_DATA: 'VIEW_SENSITIVE_DATA',
MANAGE_USERS: 'MANAGE_USERS',
APPROVE_DOCUMENTS: 'APPROVE_DOCUMENTS',
// Contractor / Vendor Capabilities
VIEW_ASSIGNED_PROJECTS: 'VIEW_ASSIGNED_PROJECTS',
UPLOAD_DOCUMENTS: 'UPLOAD_DOCUMENTS',
SUBMIT_INVOICES: 'SUBMIT_INVOICES',
MANAGE_OWN_CREW: 'MANAGE_OWN_CREW',
// Subcontractor Capabilities
VIEW_ASSIGNED_TASKS: 'VIEW_ASSIGNED_TASKS',
UPDATE_TASK_STATUS: 'UPDATE_TASK_STATUS'
};
@@ -35,7 +32,6 @@ const ROLE_PERMISSIONS = {
PERMISSIONS.VIEW_FINANCIALS,
PERMISSIONS.MANAGE_USERS,
PERMISSIONS.APPROVE_DOCUMENTS
// Note: Admin might NOT have VIEW_SENSITIVE_DATA by default without extra auth
],
[ROLES.CONTRACTOR]: [
PERMISSIONS.VIEW_ASSIGNED_PROJECTS,
@@ -47,55 +43,73 @@ const ROLE_PERMISSIONS = {
PERMISSIONS.VIEW_ASSIGNED_TASKS,
PERMISSIONS.UPDATE_TASK_STATUS
],
[ROLES.FIELD_AGENT]: [
// Standard CRM permissions
],
[ROLES.CUSTOMER]: [
// Portal permissions
]
[ROLES.FIELD_AGENT]: [],
[ROLES.CUSTOMER]: []
};
/**
* Checks if a user has a specific permission.
* @param {Object} user - The user object from AuthContext
* @param {String} permission - The permission key to check
* @returns {Boolean}
*/
export const hasPermission = (user, permission) => {
if (!user || !user.role) return false;
const userPermissions = ROLE_PERMISSIONS[user.role] || [];
return userPermissions.includes(permission);
};
/**
* Filters a list of projects based on user role.
* @param {Object} user - The user object
* @param {Array} projects - Array of project objects
* @returns {Array} - Filtered projects
*/
export const filterProjectsForUser = (user, projects) => {
if (!user) return [];
if (user.role === ROLES.OWNER || user.role === ROLES.ADMIN) {
return projects;
}
if (user.role === ROLES.CONTRACTOR) {
return projects.filter(p => p.contractorId === user.id);
}
if (user.role === ROLES.SUBCONTRACTOR) {
return projects.filter(p => p.subcontractorIds?.includes(user.id));
}
if (user.role === ROLES.OWNER || user.role === ROLES.ADMIN) return projects;
if (user.role === ROLES.CONTRACTOR) return projects.filter(p => p.contractorId === user.id);
if (user.role === ROLES.SUBCONTRACTOR) return projects.filter(p => p.subcontractorIds?.includes(user.id));
return [];
};
/**
* Determines if sensitive data should be masked.
* @param {Object} user - The viewer
* @returns {Boolean} - True if data should be visible (NOT masked), False if it should be masked.
*/
export const canViewSensitiveData = (user) => {
return hasPermission(user, PERMISSIONS.VIEW_SENSITIVE_DATA);
};
// ─── Dynamic org-permission system ───
const AUTH_ROLE_TO_ORG_KEY = {
OWNER: 'OWNER',
ADMIN: 'ADMIN',
FIELD_AGENT: 'CANVASSER',
SUBCONTRACTOR: 'SUBCONTRACTOR',
};
/**
* Resolve the org-level role key for a user.
* Priority: orgMembers lookup (exact userId match) → auth-role fallback map.
*/
export const resolveOrgRoleKey = (user, orgMembers = []) => {
if (!user) return null;
const member = orgMembers.find(
m => m.userId === user.id || m.userId === user.empId,
);
if (member) return member.roleKey;
return AUTH_ROLE_TO_ORG_KEY[user.role] || null;
};
/**
* Check a single module+action against the orgPermissions matrix.
* Owner always returns true.
*/
export const checkOrgPermission = (orgRoleKey, orgPermissions, moduleKey, action) => {
if (!orgRoleKey) return false;
if (orgRoleKey === 'OWNER') return true;
const actions = orgPermissions?.[moduleKey]?.[orgRoleKey] || [];
return actions.includes(action);
};
/**
* Compute summary stats for a role across the permission matrix.
*/
export const computeRolePermissionStats = (roleKey, orgPermissions, permissionModules) => {
let granted = 0;
let total = 0;
for (const [moduleKey, mod] of Object.entries(permissionModules)) {
total += mod.actions.length;
const roleActions = orgPermissions[moduleKey]?.[roleKey] || [];
granted += roleActions.length;
}
return { granted, total };
};