forked from ddrilling/asb_cloud_front
Частично реализовано взаимодействите с правами пользователя;
Для компоненов PrivateContent, PrivateMenuItem и PrivateRoute можно указывать требуемые права и/или роли и способ их совмещения; Добавлена ленивая подгрузка страниц для тестирования;
This commit is contained in:
parent
741449fb99
commit
c6d3814313
@ -1,28 +1,13 @@
|
|||||||
export type Role = string
|
import React from 'react'
|
||||||
|
import { Role, Permissions, hasAccess, PermissionMixingType } from '../../utils/permissions'
|
||||||
const admins: Role[] = ['администратор', 'админ', 'admin']
|
|
||||||
|
|
||||||
export const isInRole = (roles?: Role[]): boolean => {
|
|
||||||
// if (localStorage['login'] === 'dev')
|
|
||||||
// return true
|
|
||||||
if(!roles?.length)
|
|
||||||
return true
|
|
||||||
const role: Role = localStorage['roleName']?.toLowerCase()
|
|
||||||
if(admins.indexOf(role) > -1)
|
|
||||||
return true
|
|
||||||
for(const r of roles)
|
|
||||||
if(r.toLowerCase() === role)
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export const privateContent = <T extends unknown>(roles?: Role[], children?: T): T | null | undefined => {
|
|
||||||
return isInRole(roles) ? children : null
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrivateContentProps = {
|
type PrivateContentProps = {
|
||||||
|
permissions?: Permissions
|
||||||
roles?: Role[]
|
roles?: Role[]
|
||||||
|
mixing?: PermissionMixingType
|
||||||
children?: any
|
children?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrivateContent: React.FC<PrivateContentProps> = ({ roles, children }) => privateContent(roles, children)
|
export const PrivateContent: React.FC<PrivateContentProps> = ({ permissions, roles, mixing, children }) => {
|
||||||
|
return (hasAccess({ permissions, roles, mixing }) && children) || null
|
||||||
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Menu } from 'antd'
|
import { Menu } from 'antd'
|
||||||
import { isInRole, Role } from './PrivateContent'
|
import { hasAccess, Role, Permissions, PermissionMixingType } from '../../utils/permissions'
|
||||||
|
|
||||||
|
|
||||||
type PrivateMenuItemProps = {
|
type PrivateMenuItemProps = {
|
||||||
roles: Role[]
|
roles?: Role[]
|
||||||
|
permissions?: Permissions
|
||||||
|
mixing?: PermissionMixingType
|
||||||
[props: string]: any
|
[props: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrivateMenuItem: React.FC<PrivateMenuItemProps> = ({ roles, ...props }) => {
|
export const PrivateMenuItem: React.FC<PrivateMenuItemProps> = ({ roles, permissions, mixing, ...props }) => {
|
||||||
return isInRole(roles) ? <Menu.Item {...props}/> : null
|
return hasAccess({ permissions, roles, mixing }) ? <Menu.Item {...props}/> : null
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Route, Redirect } from 'react-router-dom'
|
import { Route, Redirect } from 'react-router-dom'
|
||||||
import { isInRole, Role } from './PrivateContent'
|
import { Role, Permissions, hasAccess } from '../../utils/permissions'
|
||||||
|
|
||||||
type PrivateRouteProps = {
|
type PrivateRouteProps = {
|
||||||
children: any
|
permissions?: Permissions
|
||||||
roles: Role[]
|
roles: Role[]
|
||||||
|
component?: any
|
||||||
|
children?: any
|
||||||
[other: string]: any
|
[other: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PrivateRoute: React.FC<PrivateRouteProps> = ({ children, roles, ...other }) => {
|
export const PrivateRoute: React.FC<PrivateRouteProps> = ({ permissions, roles, component, children, ...other }) => {
|
||||||
const token = localStorage['token']
|
const available = localStorage['token'] && hasAccess({ permissions, roles })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route {...other}
|
||||||
{...other}
|
component={available && component}
|
||||||
render={({ location }) => token && isInRole(roles) ? children : (
|
render={({ location }) => available ? children : (
|
||||||
<Redirect to={{ pathname: "/login", state: { from: location } }} />)
|
<Redirect to={{ pathname: '/login', state: { from: location } }} />
|
||||||
}
|
)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export { PrivateRoute } from './PrivateRoute'
|
export { PrivateRoute } from './PrivateRoute'
|
||||||
export { privateContent, PrivateContent } from './PrivateContent'
|
export { PrivateContent } from './PrivateContent'
|
||||||
export { PrivateMenuItem } from './PrivateMenuItem'
|
export { PrivateMenuItem } from './PrivateMenuItem'
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
|
import React, { Suspense } from 'react'
|
||||||
import { Layout, Menu } from 'antd'
|
import { Layout, Menu } from 'antd'
|
||||||
import { Switch, Link, useParams, Redirect, Route } from 'react-router-dom'
|
import { Switch, Link, useParams, Redirect, Route } from 'react-router-dom'
|
||||||
import { PrivateMenuItem, PrivateRoute } from '../../components/Private'
|
import { PrivateMenuItem, PrivateRoute } from '../../components/Private'
|
||||||
import { ClusterController } from './ClusterController'
|
import { PermissionNames, PermissionValue } from '../../utils/permissions'
|
||||||
import { CompanyController } from './CompanyController'
|
|
||||||
import { DepositController } from './DepositController'
|
const ClusterController = React.lazy(() => import('./ClusterController'))
|
||||||
import { UserController } from './UserController'
|
const CompanyController = React.lazy(() => import('./CompanyController'))
|
||||||
import { WellController } from './WellController'
|
const DepositController = React.lazy(() => import('./DepositController'))
|
||||||
|
const UserController = React.lazy(() => import('./UserController'))
|
||||||
|
const WellController = React.lazy(() => import('./WellController'))
|
||||||
|
|
||||||
export const AdminPanel = () => {
|
export const AdminPanel = () => {
|
||||||
const { tab } = useParams()
|
const { tab } = useParams()
|
||||||
@ -18,45 +21,37 @@ export const AdminPanel = () => {
|
|||||||
selectable={true}
|
selectable={true}
|
||||||
selectedKeys={[tab]}
|
selectedKeys={[tab]}
|
||||||
>
|
>
|
||||||
<PrivateMenuItem roles={['deposit_admin']} key={'deposit'}>
|
<PrivateMenuItem key={'deposit'} permissions={[[PermissionNames.admin.deposit, PermissionValue.Read]]}>
|
||||||
<Link to={`${rootPath}/deposit`}>Месторождения</Link>
|
<Link to={`${rootPath}/deposit`}>Месторождения</Link>
|
||||||
</PrivateMenuItem>
|
</PrivateMenuItem>
|
||||||
<PrivateMenuItem roles={['cluster_admin']} key={'cluster'}>
|
<PrivateMenuItem key={'cluster'} permissions={[[PermissionNames.admin.cluster, PermissionValue.Read]]}>
|
||||||
<Link to={`${rootPath}/cluster`}>Кусты</Link>
|
<Link to={`${rootPath}/cluster`}>Кусты</Link>
|
||||||
</PrivateMenuItem>
|
</PrivateMenuItem>
|
||||||
<PrivateMenuItem roles={['well_admin']} key={'well'}>
|
<PrivateMenuItem key={'well'} permissions={[[PermissionNames.admin.well, PermissionValue.Read]]}>
|
||||||
<Link to={`${rootPath}/well`}>Скважины</Link>
|
<Link to={`${rootPath}/well`}>Скважины</Link>
|
||||||
</PrivateMenuItem>
|
</PrivateMenuItem>
|
||||||
<PrivateMenuItem roles={['user_admin']} key={'user'}>
|
<PrivateMenuItem key={'user'} permissions={[[PermissionNames.admin.user, PermissionValue.Read]]}>
|
||||||
<Link to={`${rootPath}/user`}>Пользователи</Link>
|
<Link to={`${rootPath}/user`}>Пользователи</Link>
|
||||||
</PrivateMenuItem>
|
</PrivateMenuItem>
|
||||||
<PrivateMenuItem roles={['company_admin']} key={'company'}>
|
<PrivateMenuItem key={'company'} permissions={[[PermissionNames.admin.company, PermissionValue.Read]]}>
|
||||||
<Link to={`${rootPath}/company`}>Компании</Link>
|
<Link to={`${rootPath}/company`}>Компании</Link>
|
||||||
</PrivateMenuItem>
|
</PrivateMenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Layout.Content className={'site-layout-background'}>
|
<Layout.Content className={'site-layout-background'}>
|
||||||
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<PrivateRoute roles={['deposit_admin']} path={`${rootPath}/deposit`}>
|
<PrivateRoute roles={['deposit_admin']} path={`${rootPath}/deposit`} component={DepositController} />
|
||||||
<DepositController />
|
<PrivateRoute roles={['cluster_admin']} path={`${rootPath}/cluster`} component={ClusterController} />
|
||||||
</PrivateRoute>
|
<PrivateRoute roles={[ 'well_admin']} path={`${rootPath}/well` } component={ WellController} />
|
||||||
<PrivateRoute roles={['cluster_admin']} path={`${rootPath}/cluster`}>
|
<PrivateRoute roles={[ 'user_admin']} path={`${rootPath}/user` } component={ UserController} />
|
||||||
<ClusterController />
|
<PrivateRoute roles={['company_admin']} path={`${rootPath}/company`} component={CompanyController} />
|
||||||
</PrivateRoute>
|
|
||||||
<PrivateRoute roles={['well_admin']} path={`${rootPath}/well`}>
|
|
||||||
<WellController />
|
|
||||||
</PrivateRoute>
|
|
||||||
<PrivateRoute roles={['user_admin']} path={`${rootPath}/user`}>
|
|
||||||
<UserController />
|
|
||||||
</PrivateRoute>
|
|
||||||
<PrivateRoute roles={['company_admin']} path={`${rootPath}/company`}>
|
|
||||||
<CompanyController />
|
|
||||||
</PrivateRoute>
|
|
||||||
<Route path={'/'}>
|
<Route path={'/'}>
|
||||||
<Redirect to={`${rootPath}/deposit`}/>
|
<Redirect to={`${rootPath}/deposit`}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
</Suspense>
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
140
src/utils/permissions.ts
Normal file
140
src/utils/permissions.ts
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
export type Role = string
|
||||||
|
export type PermissionName = string
|
||||||
|
export enum PermissionValue {
|
||||||
|
Nothing = 0,
|
||||||
|
Read = 1 << 0,
|
||||||
|
Write = 1 << 1,
|
||||||
|
Aprove = 1 << 1,
|
||||||
|
Update = 1 << 1,
|
||||||
|
Insert = 1 << 2,
|
||||||
|
Delete = 1 << 3,
|
||||||
|
}
|
||||||
|
export type PermissionMixingType = 'and' | 'or'
|
||||||
|
export type Permissions = [PermissionName, PermissionValue][]
|
||||||
|
|
||||||
|
export const PermissionNames = {
|
||||||
|
deposit: 'deposit',
|
||||||
|
cluster: 'cluster',
|
||||||
|
well: {
|
||||||
|
_self: 'well',
|
||||||
|
archive: 'well/archive',
|
||||||
|
measure: 'well/measure',
|
||||||
|
message: 'well/message',
|
||||||
|
report: 'well/report',
|
||||||
|
drillingProgram: 'well/drillingProgram',
|
||||||
|
telemetry: {
|
||||||
|
_self: 'well/telemetry',
|
||||||
|
status: 'well/telemetry/status',
|
||||||
|
rop: 'well/telemetry/rop',
|
||||||
|
},
|
||||||
|
operations: {
|
||||||
|
_self: 'well/operations',
|
||||||
|
tvd: 'well/operations/tvd',
|
||||||
|
sections: 'well/operations/sections',
|
||||||
|
plan: 'well/operations/plan',
|
||||||
|
fact: 'well/operations/fact',
|
||||||
|
drillProccesFlow: 'well/operations/drillProccesFlow',
|
||||||
|
params: 'well/operations/params',
|
||||||
|
composite: {
|
||||||
|
_self: 'well/operations/composite',
|
||||||
|
wells: 'well/operations/composite/wells',
|
||||||
|
sections: 'well/operations/composite/sections',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
document: {
|
||||||
|
_self: 'well/document',
|
||||||
|
fluidService: 'well/document/fluidService',
|
||||||
|
cementing: 'well/document/cementing',
|
||||||
|
nnb: 'well/document/nnb',
|
||||||
|
gti: 'well/document/gti',
|
||||||
|
documentsForWell: 'well/document/documentsForWell',
|
||||||
|
supervisor: 'well/document/supervisor',
|
||||||
|
master: 'well/document/master'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
admin: {
|
||||||
|
_self: 'admin',
|
||||||
|
deposit: 'admin/deposit',
|
||||||
|
cluster: 'admin/cluster',
|
||||||
|
well: 'admin/well',
|
||||||
|
user: 'admin/user',
|
||||||
|
company: 'admin/company',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const admins: Role[] = ['администратор', 'админ', 'admin']
|
||||||
|
|
||||||
|
export const hasPermissions = (permissions?: Permissions): boolean => {
|
||||||
|
if (!permissions?.length)
|
||||||
|
return true
|
||||||
|
return true // TODO: Написать проверку на доступ через права
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isInRole = (roles?: Role[]): boolean => {
|
||||||
|
if (localStorage['login'] === 'dev') return true // TODO: Удалить строку
|
||||||
|
if (!roles?.length)
|
||||||
|
return true
|
||||||
|
// TODO: Переписать проверку на доступ через роли
|
||||||
|
const role: Role = localStorage['roleName']?.toLowerCase()
|
||||||
|
if (admins.indexOf(role) > -1)
|
||||||
|
return true
|
||||||
|
for (const r of roles)
|
||||||
|
if (r.toLowerCase() === role)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export type hasAccessProps = {
|
||||||
|
permissions?: Permissions
|
||||||
|
roles?: Role[]
|
||||||
|
mixing?: PermissionMixingType
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasAccess = ({permissions, roles, mixing}: hasAccessProps): boolean => {
|
||||||
|
switch (mixing) {
|
||||||
|
case 'or':
|
||||||
|
return hasPermissions(permissions) || isInRole(roles)
|
||||||
|
case 'and':
|
||||||
|
default:
|
||||||
|
return hasPermissions(permissions) && isInRole(roles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
deposit
|
||||||
|
cluster
|
||||||
|
well (R)
|
||||||
|
well/archive (R)
|
||||||
|
well/message (R)
|
||||||
|
well/report (R)
|
||||||
|
well/measure (RW)
|
||||||
|
well/drillingProgram (RU согласовать)
|
||||||
|
well/telemetry (R)
|
||||||
|
well/telemetry:status (RW)
|
||||||
|
well/telemetry:rop (RW)
|
||||||
|
well/operations (R)
|
||||||
|
well/operations/tvd (R)
|
||||||
|
well/operations/sections (R)
|
||||||
|
well/operations/plan (RW)
|
||||||
|
well/operations/fact (RW)
|
||||||
|
well/operations/drillProccesFlow (RW)
|
||||||
|
well/operations/params (RW)
|
||||||
|
well/operations/composite (R)
|
||||||
|
well/operations/composite/wells (R)
|
||||||
|
well/operations/composite/sections (RW)
|
||||||
|
well/document (R)
|
||||||
|
well/document/fluidService (RU)
|
||||||
|
well/document/cementing (RU)
|
||||||
|
well/document/nnb (RU)
|
||||||
|
well/document/gti (RU)
|
||||||
|
well/document/documentsForWell (RU)
|
||||||
|
well/document/supervisor (RU)
|
||||||
|
well/document/master (RU)
|
||||||
|
admin (R)
|
||||||
|
admin/deposit (RAED)
|
||||||
|
admin/cluster (RAED)
|
||||||
|
admin/well (RAED)
|
||||||
|
admin/user (RAED)
|
||||||
|
admin/company (RAED)
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user