Загрузка данных


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';