Загрузка данных
export const UserRoles = {
guest: 'guest',
agent: 'agent',
root: 'root',
admin: 'admin',
changeAdmin: 'change_admin',
dutyShift: 'duty_shift',
user: 'user',
contractor: 'contractor',
localEngineer: 'local_engineer',
} as const;
export type UserRole = (typeof UserRoles)[keyof typeof UserRoles];
export const Permissions = {
// location
locationCreate: 'location:create',
locationRead: 'location:read',
locationUpdate: 'location:update',
locationDelete: 'location:delete',
locationCommonStatusUpdate: 'locationCommonStatus:update',
locationStructureCreate: 'locationStructure:create',
locationStructureRead: 'locationStructure:read',
locationStructureUpdate: 'locationStructure:update',
locationStructureDelete: 'locationStructure:delete',
locationTicketCreate: 'locationTicket:create',
locationTicketRead: 'locationTicket:read',
locationTicketUpdate: 'locationTicket:update',
locationStatusRead: 'locationStatus:read',
locationStatusUpdate: 'locationStatus:update',
locationOwnerCreate: 'locationOwner:create',
locationOwnerRead: 'locationOwner:read',
locationOwnerDelete: 'locationOwner:delete',
locationNoteCreate: 'locationNote:create',
locationNoteRead: 'locationNote:read',
locationNoteUpdate: 'locationNote:update',
locationNoteDelete: 'locationNote:delete',
locationFavouriteCreate: 'locationFavourite:create',
locationFavouriteRead: 'locationFavourite:read',
locationFavouriteDelete: 'locationFavourite:delete',
// monitoring
monitoringCreate: 'monitoring:create',
monitoringRead: 'monitoring:read',
monitoringUpdate: 'monitoring:update',
monitoringDelete: 'monitoring:delete',
monitoringTicketCreate: 'monitoringTicket:create',
monitoringTicketRead: 'monitoringTicket:read',
monitoringTicketUpdate: 'monitoringTicket:update',
monitoringServiceStatusRead: 'monitoringServiceStatus:read',
monitoringServiceStatusUpdate: 'monitoringServiceStatus:update',
monitoringOwnerCreate: 'monitoringOwner:create',
monitoringOwnerRead: 'monitoringOwner:read',
monitoringOwnerDelete: 'monitoringOwner:delete',
monitoringNoteCreate: 'monitoringNote:create',
monitoringNoteRead: 'monitoringNote:read',
monitoringNoteUpdate: 'monitoringNote:update',
monitoringNoteDelete: 'monitoringNote:delete',
monitoringEquipmentCreate: 'monitoringEquipment:create',
monitoringEquipmentRead: 'monitoringEquipment:read',
monitoringEquipmentUpdate: 'monitoringEquipment:update',
monitoringEquipmentDelete: 'monitoringEquipment:delete',
statCollectorRead: 'statCollector:read',
// equipment
equipmentRead: 'equipment:read',
equipmentBlacklistRead: 'equipmentBlacklist:read',
controllerCreate: 'controller:create',
controllerRead: 'controller:read',
controllerUpdate: 'controller:update',
controllerDelete: 'controller:delete',
deviceCreate: 'device:create',
deviceRead: 'device:read',
deviceUpdate: 'device:update',
deviceDelete: 'device:delete',
networkDeviceCreate: 'networkDevice:create',
networkDeviceRead: 'networkDevice:read',
networkDeviceUpdate: 'networkDevice:update',
networkDeviceDelete: 'networkDevice:delete',
offlineDeviceCreate: 'offlineDevice:create',
offlineDeviceRead: 'offlineDevice:read',
offlineDeviceUpdate: 'offlineDevice:update',
offlineDeviceDelete: 'offlineDevice:delete',
padletCreate: 'padlet:create',
padletRead: 'padlet:read',
padletUpdate: 'padlet:update',
padletDelete: 'padlet:delete',
equipmentPingSettingsRead: 'equipmentPingSettings:read',
equipmentPingSettingsUpdate: 'equipmentPingSettings:update',
equipmentTasksRead: 'equipmentTasks:read',
equipmentTasksUpdate: 'equipmentTasks:update',
equipmentTasksReload: 'equipmentTasks:reload',
equipmentProtocolStateRead: 'equipmentProtocolState:read',
equipmentGveMessageRead: 'equipmentGveMessage:read',
secondaryInterfaceNameRead: 'secondaryInterfaceName:read',
secondaryInterfaceValueCreate: 'secondaryInterfaceValue:create',
secondaryInterfaceValueRead: 'secondaryInterfaceValue:read',
secondaryInterfaceValueUpdate: 'secondaryInterfaceValue:update',
secondaryInterfaceValueDelete: 'secondaryInterfaceValue:delete',
equipmentWindowsCreate: 'equipmentWindows:create',
equipmentWindowsRead: 'equipmentWindows:read',
// users
usersCreate: 'users:create',
usersRead: 'users:read',
usersUpdate: 'users:update',
usersDelete: 'users:delete',
// dashboard
dashboardsRead: 'dashboards:read',
// notifications
notificationsRead: 'notifications:read',
notificationsArchive: 'notifications:archive',
// audit
auditRead: 'audit:read',
// tasks
tasksRead: 'tasks:read',
taskDetailsRead: 'taskDetails:read',
// settings
controllerSettingsCreate: 'controllerSettings:create',
controllerSettingsRead: 'controllerSettings:read',
controllerSettingsUpdate: 'controllerSettings:update',
controllerSettingsDelete: 'controllerSettings:delete',
deviceSettingsCreate: 'deviceSettings:create',
deviceSettingsRead: 'deviceSettings:read',
deviceSettingsUpdate: 'deviceSettings:update',
deviceSettingsDelete: 'deviceSettings:delete',
padletSettingsCreate: 'padletSettings:create',
padletSettingsRead: 'padletSettings:read',
padletSettingsUpdate: 'padletSettings:update',
padletSettingsDelete: 'padletSettings:delete',
contractorSettingsCreate: 'contractorSettings:create',
contractorSettingsRead: 'contractorSettings:read',
contractorSettingsUpdate: 'contractorSettings:update',
contractorSettingsDelete: 'contractorSettings:delete',
commonSettingsCreate: 'commonSettings:create',
commonSettingsRead: 'commonSettings:read',
commonSettingsUpdate: 'commonSettings:update',
commonSettingsDelete: 'commonSettings:delete',
equipmentTokensCreate: 'equipmentTokens:create',
equipmentTokensRead: 'equipmentTokens:read',
equipmentTokensUpdate: 'equipmentTokens:update',
equipmentTokensDelete: 'equipmentTokens:delete',
} as const;
export type Permission = (typeof Permissions)[keyof typeof Permissions];
export type PermissionCheckMode = 'some' | 'every';
import { Permission, Permissions } from './permissions';
import { UserRole, UserRoles } from './roles';
const {
guest,
agent,
root,
admin,
changeAdmin,
dutyShift,
user,
contractor,
localEngineer,
} = UserRoles;
const fullAdminRoles = [root, admin, changeAdmin];
const readRoles = [
agent,
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
];
const monitoringReadRoles = [
agent,
root,
admin,
changeAdmin,
dutyShift,
user,
contractor,
localEngineer,
];
const technicalEditRoles = [
root,
admin,
changeAdmin,
user,
localEngineer,
];
const adminAndUserRoles = [
root,
admin,
changeAdmin,
user,
];
const settingsReadRoles = [
agent,
root,
admin,
changeAdmin,
user,
localEngineer,
];
export const permissionMatrix: Record<Permission, UserRole[]> = {
// location
[Permissions.locationCreate]: technicalEditRoles,
[Permissions.locationRead]: readRoles,
[Permissions.locationUpdate]: technicalEditRoles,
[Permissions.locationDelete]: adminAndUserRoles,
[Permissions.locationCommonStatusUpdate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.locationStructureCreate]: adminAndUserRoles,
[Permissions.locationStructureRead]: readRoles,
[Permissions.locationStructureUpdate]: adminAndUserRoles,
[Permissions.locationStructureDelete]: adminAndUserRoles,
[Permissions.locationTicketCreate]: technicalEditRoles,
[Permissions.locationTicketRead]: readRoles,
[Permissions.locationTicketUpdate]: technicalEditRoles,
[Permissions.locationStatusRead]: readRoles,
[Permissions.locationStatusUpdate]: technicalEditRoles,
[Permissions.locationOwnerCreate]: adminAndUserRoles,
[Permissions.locationOwnerRead]: readRoles,
[Permissions.locationOwnerDelete]: adminAndUserRoles,
[Permissions.locationNoteCreate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.locationNoteRead]: readRoles,
[Permissions.locationNoteUpdate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.locationNoteDelete]: adminAndUserRoles,
[Permissions.locationFavouriteCreate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.locationFavouriteRead]: readRoles,
[Permissions.locationFavouriteDelete]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
// monitoring
[Permissions.monitoringCreate]: technicalEditRoles,
[Permissions.monitoringRead]: monitoringReadRoles,
[Permissions.monitoringUpdate]: technicalEditRoles,
[Permissions.monitoringDelete]: adminAndUserRoles,
[Permissions.monitoringTicketCreate]: technicalEditRoles,
[Permissions.monitoringTicketRead]: monitoringReadRoles,
[Permissions.monitoringTicketUpdate]: technicalEditRoles,
[Permissions.monitoringServiceStatusRead]: monitoringReadRoles,
[Permissions.monitoringServiceStatusUpdate]: technicalEditRoles,
[Permissions.monitoringOwnerCreate]: adminAndUserRoles,
[Permissions.monitoringOwnerRead]: monitoringReadRoles,
[Permissions.monitoringOwnerDelete]: adminAndUserRoles,
[Permissions.monitoringNoteCreate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.monitoringNoteRead]: monitoringReadRoles,
[Permissions.monitoringNoteUpdate]: [
root,
admin,
changeAdmin,
user,
contractor,
localEngineer,
],
[Permissions.monitoringNoteDelete]: adminAndUserRoles,
[Permissions.monitoringEquipmentCreate]: technicalEditRoles,
[Permissions.monitoringEquipmentRead]: monitoringReadRoles,
[Permissions.monitoringEquipmentUpdate]: technicalEditRoles,
[Permissions.monitoringEquipmentDelete]: fullAdminRoles,
[Permissions.statCollectorRead]: [
agent,
root,
admin,
changeAdmin,
dutyShift,
user,
localEngineer,
],
// equipment
[Permissions.equipmentRead]: readRoles,
[Permissions.equipmentBlacklistRead]: readRoles,
[Permissions.controllerCreate]: technicalEditRoles,
[Permissions.controllerRead]: readRoles,
[Permissions.controllerUpdate]: technicalEditRoles,
[Permissions.controllerDelete]: adminAndUserRoles,
[Permissions.deviceCreate]: technicalEditRoles,
[Permissions.deviceRead]: readRoles,
[Permissions.deviceUpdate]: technicalEditRoles,
[Permissions.deviceDelete]: adminAndUserRoles,
[Permissions.networkDeviceCreate]: technicalEditRoles,
[Permissions.networkDeviceRead]: readRoles,
[Permissions.networkDeviceUpdate]: technicalEditRoles,
[Permissions.networkDeviceDelete]: adminAndUserRoles,
[Permissions.offlineDeviceCreate]: technicalEditRoles,
[Permissions.offlineDeviceRead]: readRoles,
[Permissions.offlineDeviceUpdate]: technicalEditRoles,
[Permissions.offlineDeviceDelete]: adminAndUserRoles,
[Permissions.padletCreate]: technicalEditRoles,
[Permissions.padletRead]: readRoles,
[Permissions.padletUpdate]: technicalEditRoles,
[Permissions.padletDelete]: adminAndUserRoles,
[Permissions.equipmentPingSettingsRead]: readRoles,
[Permissions.equipmentPingSettingsUpdate]: adminAndUserRoles,
[Permissions.equipmentTasksRead]: readRoles,
[Permissions.equipmentTasksUpdate]: technicalEditRoles,
[Permissions.equipmentTasksReload]: technicalEditRoles,
[Permissions.equipmentProtocolStateRead]: readRoles,
[Permissions.equipmentGveMessageRead]: readRoles,
[Permissions.secondaryInterfaceNameRead]: [
agent,
root,
admin,
changeAdmin,
user,
],
[Permissions.secondaryInterfaceValueCreate]: technicalEditRoles,
[Permissions.secondaryInterfaceValueRead]: readRoles,
[Permissions.secondaryInterfaceValueUpdate]: technicalEditRoles,
[Permissions.secondaryInterfaceValueDelete]: technicalEditRoles,
[Permissions.equipmentWindowsCreate]: fullAdminRoles,
[Permissions.equipmentWindowsRead]: fullAdminRoles,
// users
[Permissions.usersCreate]: fullAdminRoles,
[Permissions.usersRead]: settingsReadRoles,
[Permissions.usersUpdate]: fullAdminRoles,
[Permissions.usersDelete]: fullAdminRoles,
// dashboard
[Permissions.dashboardsRead]: monitoringReadRoles,
// notifications
[Permissions.notificationsRead]: monitoringReadRoles,
[Permissions.notificationsArchive]: adminAndUserRoles,
// audit
[Permissions.auditRead]: adminAndUserRoles,
// tasks
[Permissions.tasksRead]: [
agent,
root,
admin,
changeAdmin,
user,
],
[Permissions.taskDetailsRead]: adminAndUserRoles,
// settings
[Permissions.controllerSettingsCreate]: fullAdminRoles,
[Permissions.controllerSettingsRead]: settingsReadRoles,
[Permissions.controllerSettingsUpdate]: fullAdminRoles,
[Permissions.controllerSettingsDelete]: fullAdminRoles,
[Permissions.deviceSettingsCreate]: fullAdminRoles,
[Permissions.deviceSettingsRead]: settingsReadRoles,
[Permissions.deviceSettingsUpdate]: fullAdminRoles,
[Permissions.deviceSettingsDelete]: fullAdminRoles,
[Permissions.padletSettingsCreate]: fullAdminRoles,
[Permissions.padletSettingsRead]: settingsReadRoles,
[Permissions.padletSettingsUpdate]: fullAdminRoles,
[Permissions.padletSettingsDelete]: fullAdminRoles,
[Permissions.contractorSettingsCreate]: fullAdminRoles,
[Permissions.contractorSettingsRead]: settingsReadRoles,
[Permissions.contractorSettingsUpdate]: fullAdminRoles,
[Permissions.contractorSettingsDelete]: fullAdminRoles,
[Permissions.commonSettingsCreate]: fullAdminRoles,
[Permissions.commonSettingsRead]: settingsReadRoles,
[Permissions.commonSettingsUpdate]: fullAdminRoles,
[Permissions.commonSettingsDelete]: fullAdminRoles,
[Permissions.equipmentTokensCreate]: [root],
[Permissions.equipmentTokensRead]: [
agent,
root,
admin,
user,
localEngineer,
],
[Permissions.equipmentTokensUpdate]: [root],
[Permissions.equipmentTokensDelete]: [root],
};
import { permissionMatrix } from './permissionMatrix';
import { Permission } from './permissions';
import { UserRole } from './roles';
export const rolePermissions = Object.entries(permissionMatrix).reduce(
(acc, [permission, allowedRoles]) => {
allowedRoles.forEach((role) => {
if (!acc[role]) {
acc[role] = new Set<Permission>();
}
acc[role].add(permission as Permission);
});
return acc;
},
{} as Partial<Record<UserRole, Set<Permission>>>,
);
import { Permission } from '../model/permissions';
import { rolePermissions } from '../model/rolePermissions';
import { UserRole } from '../model/roles';
export const getUserPermissionSet = (roles: UserRole[]): Set<Permission> => {
const result = new Set<Permission>();
roles.forEach((role) => {
const permissions = rolePermissions[role];
if (!permissions) {
return;
}
permissions.forEach((permission) => {
result.add(permission);
});
});
return result;
};
import { Permission, PermissionCheckMode } from '../model/permissions';
type CheckPermissionsParams = {
permissionSet: Set<Permission>;
permissions: Permission | Permission[];
checkMode?: PermissionCheckMode;
};
export const checkPermissions = ({
permissionSet,
permissions,
checkMode = 'every',
}: CheckPermissionsParams): boolean => {
const permissionList = Array.isArray(permissions)
? permissions
: [permissions];
if (permissionList.length === 0) {
return false;
}
if (checkMode === 'some') {
return permissionList.some((permission) => permissionSet.has(permission));
}
return permissionList.every((permission) => permissionSet.has(permission));
};
import {
createContext,
ReactNode,
useContext,
useMemo,
} from 'react';
import { useAppSelector } from '@/shared/store';
import { getUserPermissionSet } from '../lib/getUserPermissionSet';
import {
Permission,
PermissionCheckMode,
} from '../model/permissions';
import { UserRole } from '../model/roles';
type AccessContextValue = {
permissionSet: Set<Permission>;
can: (permission: Permission) => boolean;
canAny: (permissions: Permission[]) => boolean;
canAll: (permissions: Permission[]) => boolean;
canCheck: (
permissions: Permission | Permission[],
checkMode?: PermissionCheckMode,
) => boolean;
};
const AccessContext = createContext<AccessContextValue | null>(null);
type AccessProviderProps = {
children: ReactNode;
};
export const AccessProvider = ({ children }: AccessProviderProps) => {
const userRoles = useAppSelector((state) => {
return state.auth.user?.roles ?? [];
}) as UserRole[];
const permissionSet = useMemo(() => {
return getUserPermissionSet(userRoles);
}, [userRoles]);
const value = useMemo<AccessContextValue>(() => {
return {
permissionSet,
can: (permission) => {
return permissionSet.has(permission);
},
canAny: (permissions) => {
return permissions.some((permission) => permissionSet.has(permission));
},
canAll: (permissions) => {
return permissions.every((permission) => permissionSet.has(permission));
},
canCheck: (permissions, checkMode = 'every') => {
const permissionList = Array.isArray(permissions)
? permissions
: [permissions];
if (permissionList.length === 0) {
return false;
}
if (checkMode === 'some') {
return permissionList.some((permission) =>
permissionSet.has(permission),
);
}
return permissionList.every((permission) =>
permissionSet.has(permission),
);
},
};
}, [permissionSet]);
return (
<AccessContext.Provider value={value}>
{children}
</AccessContext.Provider>
);
};
export const useAccess = (): AccessContextValue => {
const context = useContext(AccessContext);
if (!context) {
throw new Error('useAccess must be used inside AccessProvider');
}
return context;
};
import { ReactNode } from 'react';
import {
Permission,
PermissionCheckMode,
} from '../model/permissions';
import { useAccess } from './AccessProvider';
type CanProps = {
permissions: Permission | Permission[];
checkMode?: PermissionCheckMode;
children: ReactNode;
fallback?: ReactNode;
};
export const Can = ({
permissions,
checkMode = 'every',
children,
fallback = null,
}: CanProps) => {
const { canCheck } = useAccess();
const isAllowed = canCheck(permissions, checkMode);
if (!isAllowed) {
return <>{fallback}</>;
}
return <>{children}</>;
};
export { getUserPermissionSet } from './lib/getUserPermissionSet';
export { checkPermissions } from './lib/checkPermissions';
export {
Permissions,
type Permission,
type PermissionCheckMode,
} from './model/permissions';
export { permissionMatrix } from './model/permissionMatrix';
export { rolePermissions } from './model/rolePermissions';
export {
UserRoles,
type UserRole,
} from './model/roles';
export {
AccessProvider,
useAccess,
} from './ui/AccessProvider';
export { Can } from './ui/Can';
export { ProtectedRoute } from './ui/ProtectedRoute';