Skip to content

Instantly share code, notes, and snippets.

@r01010010
Last active May 24, 2020 12:25
Show Gist options
  • Save r01010010/250ef5379abb589e453a8fccd551177b to your computer and use it in GitHub Desktop.
Save r01010010/250ef5379abb589e453a8fccd551177b to your computer and use it in GitHub Desktop.

Role Management

// Source of true data
const actions = {
  d: 'delete',
  w: 'write/edit',
  c: 'create',
  r: 'read',
  l: 'list'
}

const roles = {
	'superadmin': 'superadmin',
	'center_user': 'center_user'
}

const rules = [
  {
    target: 'request.list', // target ids are composed by `identity.field` or `identity.list`
    dynamicPermissions: () = {},
    permissions: [
      { 'superadmin': 'cwrdl' },		
      { 'center_user': 'rl' },
    ],
    filter: () => {} // When user can list but only some
  },
  {
    target: 'request.aprovalStatus',
    dynamicPermissions: () = {},
    permissions: [
      { 'superadmin': 'cwrdl' },
      { 'center_user': 'rl' },
    ]
  },
]

/**
 * Check if user can perform an action over a target 
 * Returns true/false
 * Ex: User 'superadmin' can({ role: 'superadmin' }, 'models', 'r') will return true
 */
const can = (user, target, action) => {
  // if action exist in matrix
  const rule = matrix.find(({ id } => id === action))

  // if user.role is 'superadmin' allow it
  if (user.role === 'superadmin') {
    return true
  }

  // if user.role is not in list, forbid it and `console.log` or `console.debug` it
  if (!rule.permissions[user.role]) {
    console.debug('User not in rule', rule, user)
    return false
  }

  // if user.role is in matrix list, check for permission 
  if (rule.permission[user.role].split().includes(action))
}


/**
 * Returns rule given a target id
 */
const rule = (target) => rules.find(rule => rule.target === target)

/**
 * Returns permission matrix for given user and target
 * Ex: for user `superadmin` on target `model` will return 'cevdl'
 */
const permissions = (user, target) => {
  const rule = rules.find((rule) => target === rule.target)
  return rule.permissions[user.role].split()
}

Permissions Hook

function usePermissions (target, action) {
  const [user, setUser] = useState()

  useEffect(() => {
    new User.getLoggedUser().then((user) => setUser(user))
  }, []) 

  const rule        = rules(target)
  const permissions = permissions(user, target)

  const canCreate   = () => { per	missions.includes('c') }
  const canEdit     = () => { permissions.includes('w') }
  const canRead     = () => { permissions.includes('r') }
  const canDelete   = () => { permissions.includes('d') }
  const canList     = () => { permissions.includes('l') }

  // others
  const constcanOnlyRead  = () => { canRead && !canEdit } 

  return () => {

    // if (!target || !rules.find(( { id } ) => id === target)) {

    //   const noRuleMsg = 'Target name not provided or found in permissions rule list'

    //   return {
    //     can:          () => console.error(noRuleMsg),
    //     permissions:  () => console.error(noRuleMsg),
    //   }
    // }

    return {
      can:          (action) => can(user, target, action),
      permissions:  (action) => permissions(user, target, action),

      // permissions shortcuts for semantic convenience
      canCreate, canEdit, canRead, canDelete, canList, canOnlyRead,

      cannotCreate: () => !canCreate(),
      cannotEdit:   () => !canEdit(),
      cannotRead:   () => !canRead(),
      cannotDelete: () => !canDelete(),
      canList:      () => !canList(),
    }
  }
}

Use Permissions Hook

const FooComponent = () => {
  const { permissions, canOnlyRead } = usePermissions("request.aprovalStatus")
  
  // in a form field
  <Select ... isDisabled={canOnlyRead} />
  
  // or ..
  <Select ... disabled={!permissions.includes('w') && permissions.includes('r')} />
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment