usePermission.ts 2.06 KB
import type { AuthUser } from '~/types'
import type { ButtonPermissionKey } from '~/utils/permission'
import { createSharedComposable } from '@vueuse/core'
import {
  APP_PAGE_PATHS,
  canAccessPageByRoles,
  canUseButtonByRoles,
  getAccessiblePagesForRoles,
  isProtectedPage,
  normalizePagePath,
  toPagePath
} from '~/utils/permission'

function toRoles(user: AuthUser | null) {
  if (!user || !Array.isArray(user.roles)) {
    return []
  }

  return user.roles.filter(role => typeof role === 'string' && role.trim().length > 0)
}

const _usePermission = () => {
  const route = useRoute()
  const { user } = useAuth()

  const roles = computed(() => toRoles(user.value))
  const allowedPages = computed(() => getAccessiblePagesForRoles(roles.value))

  const canAccessPage = (pagePath: string) => {
    return canAccessPageByRoles(roles.value, pagePath)
  }

  const can = (pagePath: string, buttonKey: ButtonPermissionKey) => {
    return canUseButtonByRoles(roles.value, pagePath, buttonKey)
  }

  const canInCurrentPage = (buttonKey: ButtonPermissionKey) => {
    return can(route.path, buttonKey)
  }

  const isAllowedPage = (pagePath: string) => {
    const pageKey = toPagePath(pagePath)
    if (!pageKey) {
      return false
    }

    return allowedPages.value.has(pageKey)
  }

  const getAllowedPages = () => {
    return APP_PAGE_PATHS.filter(pagePath => allowedPages.value.has(pagePath))
  }

  const getDeniedReason = (pagePath: string, buttonKey?: ButtonPermissionKey) => {
    if (!isProtectedPage(pagePath)) {
      return 'permission.pageNotManaged'
    }

    if (!canAccessPage(pagePath)) {
      return 'permission.pageDenied'
    }

    if (buttonKey && !can(pagePath, buttonKey)) {
      return 'permission.buttonDenied'
    }

    return 'permission.denied'
  }

  const normalize = (pagePath: string) => normalizePagePath(pagePath)

  return {
    roles,
    allowedPages,
    canAccessPage,
    can,
    canInCurrentPage,
    isAllowedPage,
    getAllowedPages,
    getDeniedReason,
    normalize
  }
}

export const usePermission = createSharedComposable(_usePermission)