feat: Tambahkan fitur pengecekan izin pengguna

main
marszayn 2025-03-10 14:03:38 +07:00
parent 9579f140eb
commit a61eb18e42
7 changed files with 224 additions and 30 deletions

View File

@ -5,11 +5,24 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Requests\RoleRequest; use App\Http\Requests\RoleRequest;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;
use Spatie\Permission\Models\Permission; use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Role;
class RoleController extends Controller class RoleController extends Controller
{ {
public function __invoke(Request $request)
{
try {
$kategori = Role::latest()->get();
return Inertia::render('admin/kategori/index_kategori', ['kategori' => $kategori]);
} catch (\Exception $e) {
Log::error('Error fetching Kategori: ' . $e->getMessage());
return back()->with('error', 'Something went wrong.');
}
}
public function index() public function index()
{ {
$roles = Role::with('permissions') $roles = Role::with('permissions')
@ -17,7 +30,7 @@ class RoleController extends Controller
->paginate(10); ->paginate(10);
// Kembalikan data ke komponen Inertia 'Admin/Roles/Index' // Kembalikan data ke komponen Inertia 'Admin/Roles/Index'
return inertia('Admin/Roles/Index', compact('roles')); return Inertia::render('admin/roles/index_roles', compact('roles'));
} }
public function create() public function create()
{ {
@ -25,7 +38,7 @@ class RoleController extends Controller
$permissions = Permission::all(); $permissions = Permission::all();
// Kembalikan ke Inertia 'Admin/Roles/Create' dengan data permissions // Kembalikan ke Inertia 'Admin/Roles/Create' dengan data permissions
return inertia('Admin/Roles/Create', [ return Inertia::render('admin/roles/create_roles', [
'permissions' => $permissions, 'permissions' => $permissions,
]); ]);
} }
@ -66,7 +79,7 @@ class RoleController extends Controller
}); });
// Kembalikan data ke Inertia 'Admin/Roles/Edit' dengan data role, permissions, dan rolePermissions // Kembalikan data ke Inertia 'Admin/Roles/Edit' dengan data role, permissions, dan rolePermissions
return inertia('Admin/Roles/Edit', [ return Inertia::render('admin/roles/edit_roles', [
'permissions' => $permissions, 'permissions' => $permissions,
'role' => $role, 'role' => $role,
'rolePermissions' => $rolePermissions, 'rolePermissions' => $rolePermissions,

View File

@ -15,17 +15,82 @@ class PermissionsTableSeeder extends Seeder
{ {
$resources = [ $resources = [
'users' => ['index', 'create', 'edit', 'delete'], 'Dashboard' => [
'roles' => ['index', 'create', 'edit', 'delete'], 'index' => 'Lihat Dashboard',
'kategori' => ['index', 'create', 'edit', 'delete'], ],
'subkategori' => ['index', 'create', 'edit', 'delete'], 'Pelaporan' => [
'index' => 'Melihat Daftar Pelaporan',
],
'Verifikasi' => [
'index' => 'Mengakses Verifikasi Pelaporan',
],
'Hukum' => [
'index' => 'Melihat Data Penegakan Hukum',
],
'Perizinan' => [
'index' => 'Melihat Data Perizinan Lingkungan',
],
'History' => [
'index' => 'Melihat History Perusahaan',
],
'Post' => [
'index' => 'Mengakses Data Postingan',
],
'Kategori' => [
'index' => 'Melihat Kategori Post',
],
'SubKategori' => [
'index' => 'Melihat Sub Kategori Post',
],
'Verifikator' => [
'index' => 'Mengakses Data Dinas LH / Verifikator',
],
'JenisKegiatan' => [
'index' => 'Melihat Daftar Jenis Kegiatan',
],
'JenisDokil' => [
'index' => 'Melihat Daftar Jenis Dokumen Izin',
],
'Perusahaan' => [
'index' => 'Mengakses Data Perusahaan',
],
'HistoryKegiatan' => [
'index' => 'Melihat History Kegiatan',
],
'JenisSanksi' => [
'index' => 'Melihat Jenis Sanksi',
],
'Penaatan' => [
'index' => 'Melihat Status Penaatan',
],
'Pengguna' => [
'index' => 'Melihat Daftar Pengguna',
],
'Role' => [
'index' => 'Melihat Kelompok Pengguna',
],
'Tentang' => [
'index' => 'Melihat Informasi Tentang Aplikasi',
],
'Catatan' => [
'index' => 'Melihat Catatan Sistem',
],
'Backup' => [
'index' => 'Mengakses Fitur Backup Data',
],
'Restore' => [
'index' => 'Mengakses Fitur Restore Data',
],
]; ];
foreach ($resources as $resource => $actions) { foreach ($resources as $resource => $actions) {
foreach ($actions as $action) { foreach ($actions as $action => $description) {
$permissionName = "{$resource}.{$action}"; $permissionName = "{$resource}.{$action}";
Permission::firstOrCreate(['name' => $permissionName, 'guard_name' => 'web']); Permission::updateOrCreate(
['name' => $permissionName, 'guard_name' => 'web'],
['description' => $description]
);
} }
} }
}
} }
}

View File

@ -15,13 +15,23 @@ class RolesTableSeeder extends Seeder
public function run(): void public function run(): void
{ {
$admin = Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']); $admin = Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
$user = Role::firstOrCreate(['name' => 'user', 'guard_name' => 'web']); // $user = Role::firstOrCreate(['name' => 'user', 'guard_name' => 'web']);
// Assign permissions ke role // // Assign permissions ke role
$admin->syncPermissions(Permission::all()); // Admin mendapatkan semua akses $admin->syncPermissions(Permission::all()); // Admin mendapatkan semua akses
// Assign role `admin` ke user // // Assign role `admin` ke user
$user->assignRole($admin); // $user->assignRole($admin);
Role::firstOrCreate(['name' => 'Admin']);
Role::firstOrCreate(['name' => 'Verifikator']);
Role::firstOrCreate(['name' => 'Perusahaan']);
Role::firstOrCreate(['name' => 'Admin Suku Dinas LH']);
Role::firstOrCreate(['name' => 'Pedal']);
Role::firstOrCreate(['name' => 'Admin Bidang']);
Role::firstOrCreate(['name' => 'Admin PPU']);
Role::firstOrCreate(['name' => 'Kajian Dampak Lingkungan']);
Role::firstOrCreate(['name' => 'Instansi Umum']);
Role::firstOrCreate(['name' => 'Gakkum']);
} }
} }

View File

@ -36,6 +36,7 @@ import {
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { Link, usePage } from "@inertiajs/react"; import { Link, usePage } from "@inertiajs/react";
import { PageProps } from "@/types"; import { PageProps } from "@/types";
import hasAnyPermission from "@/utils/hasAnyPermission";
const data = { const data = {
user: { user: {
@ -47,36 +48,43 @@ const data = {
{ {
title: "Dashboard", title: "Dashboard",
url: "/dashboard", url: "/dashboard",
permissions: ["Dashboard.index"],
icon: Home, icon: Home,
}, },
{ {
title: "Pelaporan", title: "Pelaporan",
url: "/admin/pelaporan", url: "/admin/pelaporan",
permissions: ["Pelaporan.index"],
icon: BookMarked, icon: BookMarked,
}, },
{ {
title: "Verifikasi Pelaporan", title: "Verifikasi Pelaporan",
url: "/admin/verifikasi", url: "/admin/verifikasi",
permissions: ["Verifikasi.index"],
icon: BookCheck, icon: BookCheck,
}, },
{ {
title: "Penegakan Hukum", title: "Penegakan Hukum",
url: "/admin/hukum", url: "/admin/hukum",
permissions: ["Hukum.index"],
icon: Scale, icon: Scale,
}, },
{ {
title: "Perizinan Lingkungan", title: "Perizinan Lingkungan",
url: "/admin/perizinan-lingkungan", url: "/admin/perizinan_lingkungan",
permissions: ["Perizinan.index"],
icon: FileKey2, icon: FileKey2,
}, },
{ {
title: "History Perusahaan", title: "History Perusahaan",
url: "/admin/history-perusahaan", url: "/admin/history_perusahaan",
permissions: ["History.index"],
icon: GalleryVertical, icon: GalleryVertical,
}, },
{ {
title: "Post", title: "Post",
url: "/admin/post", url: "/admin/post",
permissions: ["Post.index"],
icon: Frame, icon: Frame,
}, },
{ {
@ -116,38 +124,47 @@ const data = {
{ {
title: "Kategori Post", title: "Kategori Post",
url: "/admin/kategori", url: "/admin/kategori",
permissions: ["Kategori.index"],
}, },
{ {
title: "Sub Kategori Post", title: "Sub Kategori Post",
url: "/admin/subkategori", url: "/admin/subkategori",
permissions: ["SubKategori.index"],
}, },
{ {
title: "Dinas LH", title: "Dinas LH",
url: "/admin/verifikator", url: "/admin/verifikator",
permissions: ["Verifikator.index"],
}, },
{ {
title: "Jenis Kegiatan", title: "Jenis Kegiatan",
url: "/admin/jeniskegiatan", url: "/admin/jeniskegiatan",
permissions: ["JenisKegiatan.index"],
}, },
{ {
title: "Jenis Dokumen Izin", title: "Jenis Dokumen Izin",
url: "/admin/jenisdokil", url: "/admin/jenisdokil",
permissions: ["JenisDokil.index"],
}, },
{ {
title: "Perusahaan", title: "Data Perusahaan",
url: "/admin/perusahaan", url: "/admin/perusahaan",
permissions: ["Perusahaan.index"],
}, },
{ {
title: "History Kegiatan", title: "History Kegiatan",
url: "/admin/historykegiatan", url: "/admin/historykegiatan",
permissions: ["HistoryKegiatan.index"],
}, },
{ {
title: "Jenis Sanksi", title: "Jenis Sanksi",
url: "/admin/jenissanksi", url: "/admin/jenissanksi",
permissions: ["JenisSanksi.index"],
}, },
{ {
title: "Status Penaatan", title: "Status Penaatan",
url: "/admin/penaatan", url: "/admin/penaatan",
permissions: ["Penaatan.index"],
}, },
], ],
}, },
@ -160,10 +177,12 @@ const data = {
{ {
title: "Pengguna", title: "Pengguna",
url: "/admin/pengguna", url: "/admin/pengguna",
permissions: ["Pengguna.index"],
}, },
{ {
title: "Role", title: "Kelompok Pengguna",
url: "/admin/role", url: "/admin/roles",
permissions: ["Role.index"],
}, },
], ],
}, },
@ -173,27 +192,71 @@ const data = {
title: "Tentang", title: "Tentang",
url: "/admin/tentang", url: "/admin/tentang",
icon: LifeBuoy, icon: LifeBuoy,
permissions: ["Tentang.index"],
}, },
{ {
title: "Catatan Sistem", title: "Catatan Sistem",
url: "#", url: "#",
icon: NotepadText, icon: NotepadText,
permissions: ["Catatan.index"],
}, },
{ {
title: "Backup", title: "Backup",
url: "#", url: "#",
icon: Archive, icon: Archive,
permissions: ["Backup.index"],
}, },
{ {
title: "Restore", title: "Restore",
url: "#", url: "#",
icon: DatabaseBackup, icon: DatabaseBackup,
permissions: ["Restore.index"],
}, },
], ],
}; };
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) { export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const { auth } = usePage<PageProps>().props; const { auth } = usePage<PageProps>().props;
const userPermissions = auth?.user?.permissions ?? [];
const filterMenu = (menu) => {
return menu
.map((item) => {
if (item.items) {
const filteredItems = item.items.filter((subItem) =>
subItem.permissions
? hasAnyPermission(
Array.isArray(subItem.permissions)
? subItem.permissions
: Object.keys(subItem.permissions) // Pastikan selalu array
)
: true
);
if (filteredItems.length > 0) {
return { ...item, items: filteredItems };
}
return null;
}
if (item.permissions) {
// **PERBAIKAN UTAMA**: Pastikan item.permissions selalu dalam bentuk array
const permissionsArray = Array.isArray(item.permissions)
? item.permissions
: Object.keys(item.permissions);
const hasPermission = hasAnyPermission(permissionsArray);
return hasPermission ? item : null;
}
return item;
})
.filter(Boolean);
};
const navMain = filterMenu(data.navMain);
const navSecondary = filterMenu(data.navSecondary);
return ( return (
<Sidebar variant="inset" {...props}> <Sidebar variant="inset" {...props}>
@ -201,6 +264,7 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton size="lg" asChild> <SidebarMenuButton size="lg" asChild>
{/* {hasAnyPermission(["Dashboard.index"]) && ( */}
<Link href={route("dashboard")}> <Link href={route("dashboard")}>
<div className="flex aspect-square size-8 items-center justify-center rounded-lg text-sidebar-primary-foreground"> <div className="flex aspect-square size-8 items-center justify-center rounded-lg text-sidebar-primary-foreground">
{/* <Command className="size-4" /> */} {/* <Command className="size-4" /> */}
@ -219,13 +283,14 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
</span> </span>
</div> </div>
</Link> </Link>
{/* )} */}
</SidebarMenuButton> </SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
</SidebarMenu> </SidebarMenu>
</SidebarHeader> </SidebarHeader>
<SidebarContent> <SidebarContent>
<NavMain items={data.navMain} /> <NavMain items={navMain} />
<NavSecondary items={data.navSecondary} className="mt-auto" /> <NavSecondary items={navSecondary} className="mt-auto" />
</SidebarContent> </SidebarContent>
<SidebarFooter> <SidebarFooter>
<NavUser user={auth.user} /> <NavUser user={auth.user} />

View File

@ -19,6 +19,7 @@ import {
SidebarMenuSubItem, SidebarMenuSubItem,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { Link } from "@inertiajs/react"; import { Link } from "@inertiajs/react";
import hasAnyPermission from "@/utils/hasAnyPermission";
export function NavMain({ export function NavMain({
items, items,
@ -28,6 +29,7 @@ export function NavMain({
url: string; url: string;
icon: LucideIcon; icon: LucideIcon;
isActive?: boolean; isActive?: boolean;
permissions?: string[];
items?: { items?: {
title: string; title: string;
url: string; url: string;
@ -46,10 +48,19 @@ export function NavMain({
> >
<SidebarMenuItem> <SidebarMenuItem>
<SidebarMenuButton asChild tooltip={item.title}> <SidebarMenuButton asChild tooltip={item.title}>
<Link href={item.url}> {item.permissions ? (
<item.icon /> hasAnyPermission(item.permissions) ? (
<div>{item.title}</div> <Link href={item.url}>
</Link> <item.icon />
<div>{item.title}</div>
</Link>
) : null
) : (
<Link href={item.url}>
<item.icon />
<div>{item.title}</div>
</Link>
)}
</SidebarMenuButton> </SidebarMenuButton>
{item.items?.length ? ( {item.items?.length ? (
<> <>

View File

@ -9,6 +9,7 @@ import {
SidebarMenuItem, SidebarMenuItem,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { Link } from "@inertiajs/react"; import { Link } from "@inertiajs/react";
import hasAnyPermission from "@/utils/hasAnyPermission";
export function NavSecondary({ export function NavSecondary({
items, items,
@ -18,6 +19,7 @@ export function NavSecondary({
title: string; title: string;
url: string; url: string;
icon: LucideIcon; icon: LucideIcon;
permissions?: string[];
}[]; }[];
} & React.ComponentPropsWithoutRef<typeof SidebarGroup>) { } & React.ComponentPropsWithoutRef<typeof SidebarGroup>) {
return ( return (
@ -27,10 +29,19 @@ export function NavSecondary({
{items.map((item) => ( {items.map((item) => (
<SidebarMenuItem key={item.title}> <SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild size="sm"> <SidebarMenuButton asChild size="sm">
<Link href={item.url}> {item.permissions ? (
<item.icon /> hasAnyPermission(item.permissions) ? (
<span>{item.title}</span> <Link href={item.url}>
</Link> <item.icon />
<div>{item.title}</div>
</Link>
) : null
) : (
<Link href={item.url}>
<item.icon />
<div>{item.title}</div>
</Link>
)}
</SidebarMenuButton> </SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
))} ))}

View File

@ -0,0 +1,19 @@
import { usePage } from "@inertiajs/react";
export default function hasAnyPermission(permissions = []) {
const { auth } = usePage().props;
const allPermissions = auth?.user?.permissions ?? {};
if (typeof allPermissions !== "object" || allPermissions === null) {
return false;
}
if (!Array.isArray(permissions) || permissions.length === 0) {
return false;
}
const result = permissions.some(
(permission) => allPermissions?.[permission] === true
);
return result;
}