Skip to content

Commit

Permalink
feat: add roles and permissions gate
Browse files Browse the repository at this point in the history
  • Loading branch information
phojie committed Dec 3, 2022
1 parent 4d35a89 commit 536001f
Show file tree
Hide file tree
Showing 10 changed files with 54 additions and 24 deletions.
2 changes: 1 addition & 1 deletion app/Http/Controllers/Admin/RoleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RoleController
{
public function index(Request $request)
{
\Gate::authorize('read-role');
abort_unless($request->user()->can('role-list'), 404);

// set query
$query = (new RoleService())->get($request);
Expand Down
3 changes: 2 additions & 1 deletion app/Http/Controllers/Admin/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class UserController extends Controller
{
public function index(Request $request)
{
\Gate::authorize('read-user');
abort_unless($request->user()->can('user-list'), 404);

// set query
$query = (new UserService())->get($request);
Expand Down Expand Up @@ -45,6 +45,7 @@ public function store(UserRequest $userRequest)

public function show(User $user)
{
\Gate::authorize('read-user');
// get user
}

Expand Down
12 changes: 6 additions & 6 deletions app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ public function share(Request $request)

return array_merge(parent::share($request), [
'auth' => [
'signedIn' =>$isAuth,
'user' => $isAuth
? new UserResource(Auth::user())
: null,
'signedIn' => $isAuth,
'user' => $isAuth ? new UserResource(Auth::user()) : null,
'permissions' => $isAuth ? Auth::user()->getAllPermissions()->pluck('name') : null,
'roles' => $isAuth ? Auth::user()->getRoleNames() : null,
],
'flash' => [
'notification' => session('notification'),
],
// csrf token
'csrfToken' => csrf_token(),
// 'ziggy' => function () use ($request) {

// 'ziggy' => function () use ($request) {1
// return array_merge((new Ziggy)->toArray(), [
// 'location' => $request->url(),
// ]);
Expand Down
4 changes: 4 additions & 0 deletions database/seeders/PermissionSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public function run()
{
// Create permissions
$permissions = [
[
'name' => 'user-list',
'description' => 'List all users',
],
[
'name' => 'user-create',
'description' => 'Create user',
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Components/Admin/AdminNavigation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
const { adminItems, miscItems } = useNavigation()
const { adminItemsGuarded: adminItems, miscItemsGuarded: miscItems } = useNavigation()
</script>

<template>
Expand Down
2 changes: 2 additions & 0 deletions resources/js/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ declare global {
const useFps: typeof import('@vueuse/core')['useFps']
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
const useGamepad: typeof import('@vueuse/core')['useGamepad']
const useGate: typeof import('./composables/app/gate')['useGate']
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
Expand Down Expand Up @@ -448,6 +449,7 @@ declare module 'vue' {
readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']>
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
readonly useGate: UnwrapRef<typeof import('./composables/app/gate')['useGate']>
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
Expand Down
12 changes: 0 additions & 12 deletions resources/js/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ declare module '@vue/runtime-core' {
AdminRolesSlideOver: typeof import('./components/Admin/Roles/AdminRolesSlideOver.vue')['default']
AdminRolesTable: typeof import('./components/Admin/Roles/AdminRolesTable.vue')['default']
AdminSettingsGeneralTab: typeof import('./components/Admin/Settings/AdminSettingsGeneralTab.vue')['default']
AdminSettingsPasswordTab: typeof import('./components/Admin/Settings/AdminSettingsPasswordTab.vue')['default']
AdminSettingsSlideOver: typeof import('./components/Admin/Settings/AdminSettingsSlideOver.vue')['default']
AdminSideBar: typeof import('./components/Admin/AdminSideBar.vue')['default']
AdminUsersSlideOver: typeof import('./components/Admin/Users/AdminUsersSlideOver.vue')['default']
Expand Down Expand Up @@ -55,11 +54,9 @@ declare module '@vue/runtime-core' {
HeroiconsCheck: typeof import('~icons/heroicons/check')['default']
HeroiconsChevronDown20Solid: typeof import('~icons/heroicons/chevron-down20-solid')['default']
HeroiconsChevronUpDown: typeof import('~icons/heroicons/chevron-up-down')['default']
HeroiconsLink20Solid: typeof import('~icons/heroicons/link20-solid')['default']
HeroiconsMagnifyingGlass20Solid: typeof import('~icons/heroicons/magnifying-glass20-solid')['default']
HeroiconsOutlineBars3CenterLeft: typeof import('~icons/heroicons-outline/bars3-center-left')['default']
HeroiconsPencilSquare20Solid: typeof import('~icons/heroicons/pencil-square20-solid')['default']
HeroiconsQuestionMarkCircle20Solid: typeof import('~icons/heroicons/question-mark-circle20-solid')['default']
HeroiconsShieldCheckSolid: typeof import('~icons/heroicons/shield-check-solid')['default']
HeroiconsXCircle20Solid: typeof import('~icons/heroicons/x-circle20-solid')['default']
HeroiconsXMark: typeof import('~icons/heroicons/x-mark')['default']
Expand All @@ -76,7 +73,6 @@ declare module '@vue/runtime-core' {
JBtn: typeof import('./j-components/JBtn.vue')['default']
JCheckbox: typeof import('./j-components/JCheckbox.vue')['default']
JFileInput: typeof import('./j-components/JFileInput.vue')['default']
JImageUpload: typeof import('./j-components/JImageUpload.vue')['default']
JLink: typeof import('./j-components/JLink.vue')['default']
JNotification: typeof import('./j-components/JNotification.vue')['default']
JPagination: typeof import('./j-components/JPagination.vue')['default']
Expand All @@ -101,14 +97,6 @@ declare module '@vue/runtime-core' {
MingcuteTwitterFill: typeof import('~icons/mingcute/twitter-fill')['default']
PrimaryButton: typeof import('./components/PrimaryButton.vue')['default']
ResponsiveNavLink: typeof import('./components/ResponsiveNavLink.vue')['default']
Switch: typeof import('@headlessui/vue')['Switch']
SwitchGroup: typeof import('@headlessui/vue')['SwitchGroup']
SwitchLabel: typeof import('@headlessui/vue')['SwitchLabel']
Tab: typeof import('@headlessui/vue')['Tab']
TabGroup: typeof import('@headlessui/vue')['TabGroup']
TabList: typeof import('@headlessui/vue')['TabList']
TabPanel: typeof import('@headlessui/vue')['TabPanel']
TabPanels: typeof import('@headlessui/vue')['TabPanels']
TextInput: typeof import('./components/TextInput.vue')['default']
TransitionChild: typeof import('@headlessui/vue')['TransitionChild']
TransitionRoot: typeof import('@headlessui/vue')['TransitionRoot']
Expand Down
11 changes: 11 additions & 0 deletions resources/js/composables/app/gate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const useGate = () => {
const { roles, permissions } = useAuthStore()

const can = (permission: string) => {
return _.includes(permissions, permission) || _.includes(roles, 'Super Admin')
}

return {
can,
}
}
26 changes: 23 additions & 3 deletions resources/js/composables/app/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface NavigationItem {
href: string
icon: any
exact?: boolean
permission?: string
}

export const useNavigation = () => {
Expand All @@ -25,6 +26,7 @@ export const useNavigation = () => {
name: 'Home',
href: '/admin',
icon: HeroiconsHome,

},
{
name: 'Menus',
Expand Down Expand Up @@ -63,6 +65,7 @@ export const useNavigation = () => {
name: 'Users',
icon: HeroiconsUserGroup,
href: '/admin/users',
permission: 'user-list',
exact: true,
},
{
Expand Down Expand Up @@ -91,11 +94,28 @@ export const useNavigation = () => {
icon: HeroiconsQuestionMarkCircle,
href: '/admin/help',
},

]

const adminItemsGuarded = computed(() => {
return adminItems.filter((item) => {
if (item.permission)
return useGate().can(item.permission)

return true
})
})

const miscItemsGuarded = computed(() => {
return miscItems.filter((item) => {
if (item.permission)
return useGate().can(item.permission)

return true
})
})

return {
adminItems,
miscItems,
adminItemsGuarded,
miscItemsGuarded,
}
}
4 changes: 4 additions & 0 deletions resources/js/store/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { User } from '@/types/user'
export const useAuthStore = defineStore('auth', () => {
const pageProps = computed<any>(() => usePage().props.value)
const user = computed<User>(() => pageProps.value.auth?.user)
const roles = computed<string[]>(() => pageProps.value.auth?.roles)
const permissions = computed<string[]>(() => pageProps.value.auth?.permissions)
const signedIn = computed(() => pageProps.value.auth?.signedIn)

const form = useForm({
Expand Down Expand Up @@ -44,6 +46,8 @@ export const useAuthStore = defineStore('auth', () => {
// states
form,
user,
roles,
permissions,
signedIn,

// actions
Expand Down

0 comments on commit 536001f

Please sign in to comment.