All files / modules/20-rbac/hooks usePermission.ts

100% Statements 29/29
95.24% Branches 20/21
100% Functions 7/7
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107              498x   498x 498x 498x         498x                                       498x 13283x 13283x               498x 7947x 7947x 7947x 7947x 7947x   7947x   2741x     2789x               2789x     2741x   2414x     2458x             2458x             7947x 7752x 8035x 2x   8033x             8033x       195x    
/*
 * Copyright 2021 Harness Inc. All rights reserved.
 * Use of this source code is governed by the PolyForm Shield 1.0.0 license
 * that can be found in the licenses directory at the root of this repository, also available at
 * https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt.
 */
 
import { identity, pick, pickBy } from 'lodash-es'
 
import { useParams } from 'react-router-dom'
import { useDeepCompareEffect } from '@common/hooks'
import { usePermissionsContext, PermissionRequestOptions } from 'framework/rbac/PermissionsContext'
import type { PermissionCheck, ResourceScope } from 'services/rbac'
import type { PermissionIdentifier } from '@rbac/interfaces/PermissionIdentifier'
import type { ResourceType } from '@rbac/interfaces/ResourceType'
import type { ProjectPathProps } from '@common/interfaces/RouteInterfaces'
import { isCDCommunity, useLicenseStore } from 'framework/LicenseStore/LicenseStoreContext'
 
export interface Resource {
  resourceType: ResourceType
  resourceIdentifier?: string
}
 
export interface PermissionRequest {
  resourceScope?: ResourceScope
  resource: Resource
  permission: PermissionIdentifier
}
 
export interface PermissionsRequest {
  resourceScope?: ResourceScope
  resource: Resource
  permissions: PermissionIdentifier[]
  options?: PermissionRequestOptions
}
 
export function getDTOFromRequest(permissionRequest: PermissionRequest, defaultScope: ResourceScope): PermissionCheck {
  const { resource, resourceScope, permission } = permissionRequest
  return {
    // pickBy(obj, identity) removes keys with undefined values
    resourceScope: pickBy(resourceScope || defaultScope, identity),
    ...pickBy(resource, identity),
    permission
  }
}
 
export function usePermission(permissionsRequest?: PermissionsRequest, deps: Array<any> = []): Array<boolean> {
  const { requestPermission, checkPermission, cancelRequest } = usePermissionsContext()
  const { accountId: accountIdentifier, orgIdentifier, projectIdentifier } = useParams<ProjectPathProps>()
  const defaultScope = { accountIdentifier, orgIdentifier, projectIdentifier }
  const { licenseInformation } = useLicenseStore()
  const isCommunity = isCDCommunity(licenseInformation)
 
  useDeepCompareEffect(() => {
    // generate PermissionRequest for every action user requested
    permissionsRequest &&
      !isCommunity &&
      permissionsRequest.permissions.forEach(permission => {
        const permissionCheckDto = getDTOFromRequest(
          {
            permission,
            ...pick(permissionsRequest, ['resourceScope', 'resource'])
          } as PermissionRequest,
          defaultScope
        )
        // register request in the context
        requestPermission(permissionCheckDto, permissionsRequest?.options)
      })
 
    return () => {
      // cancel above request when this hook instance is unmounting
      permissionsRequest &&
        !isCommunity &&
        permissionsRequest.permissions.forEach(permission => {
          const permissionCheckDto = getDTOFromRequest(
            {
              permission,
              ...pick(permissionsRequest, ['resourceScope', 'resource'])
            } as PermissionRequest,
            defaultScope
          )
          cancelRequest(permissionCheckDto)
        })
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [permissionsRequest?.options, ...deps])
 
  // hook should return boolean for every action requested, in same order
  if (permissionsRequest !== undefined) {
    return permissionsRequest.permissions.map(permission => {
      if (isCommunity) {
        return true
      }
      const permissionCheckDto = getDTOFromRequest(
        {
          permission,
          ...pick(permissionsRequest, ['resourceScope', 'resource'])
        } as PermissionRequest,
        defaultScope
      )
      return checkPermission(permissionCheckDto)
    })
  }
  // hook will return true if there are no parameters passed to it.
  return [true]
}