with('roleModel') ->when($request->search, function ($query, $search) { $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('email', 'like', "%{$search}%"); }); }) ->latest() ->paginate(10); return view('pages.users.index', compact('users')); } /** * Form tambah user baru. * Izin: users (create) */ public function create(): View { Gate::authorize('check-access', ['users', 'create']); $roles = Role::all(); return view('pages.users.create', compact('roles')); } /** * Simpan user baru. * Izin: users (create) */ public function store(Request $request): RedirectResponse { Gate::authorize('check-access', ['users', 'create']); $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|lowercase|email|max:255|unique:users', 'phone' => 'nullable|string|max:15', 'role_id' => 'required|exists:roles,id', 'password' => ['required', 'confirmed', Rules\Password::defaults()], ]); $role = Role::find($validated['role_id']); $user = User::create([ 'name' => $validated['name'], 'email' => $validated['email'], 'phone' => $validated['phone'], 'role_id' => $validated['role_id'], 'role' => $role->slug, 'password' => Hash::make($validated['password']), ]); // Catat aktivitas (Gunakan parameter model untuk log) $this->logAction('CREATED', $user, "Mendaftarkan user baru: {$user->name} sebagai {$role->name}", 'User'); return redirect()->route('admin.users.index')->with('success', "User {$user->name} berhasil ditambahkan."); } /** * Halaman Edit User. * Izin: users (update) */ public function edit(User $user): View { Gate::authorize('check-access', ['users', 'update']); $roles = Role::all(); return view('pages.users.edit', compact('user', 'roles')); } /** * Update Data User. * Izin: users (update) */ public function update(Request $request, User $user): RedirectResponse { Gate::authorize('check-access', ['users', 'update']); $validated = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email,' . $user->id, 'role_id' => 'required|exists:roles,id', 'phone' => 'nullable|string|max:15', ]); $newRole = Role::find($validated['role_id']); // Keamanan Logika: Tetap pertahankan agar user tidak merusak akun sendiri if ($user->id === auth()->id() && $newRole->slug !== 'admin' && auth()->user()->role === 'admin') { return back()->with('error', 'Akses Ditolak! Anda tidak bisa menurunkan otoritas Admin Anda sendiri.'); } $user->update(array_merge($validated, [ 'role' => $newRole->slug ])); $this->logAction('UPDATED', $user, "Memperbarui data profil user: {$user->name}", 'User'); return redirect()->route('admin.users.index')->with('success', "Data {$user->name} berhasil diperbarui."); } /** * Hapus User. * Izin: users (delete) */ public function destroy(User $user): RedirectResponse { Gate::authorize('check-access', ['users', 'delete']); if ($user->id === auth()->id()) { return back()->with('error', 'Akses Ditolak! Anda tidak dapat menghapus akun Anda sendiri.'); } $userName = $user->name; $this->logAction('DELETED', $user, "Menghapus user: {$userName}", 'User'); $user->delete(); return redirect()->route('admin.users.index')->with('success', "User {$userName} telah dihapus."); } /* -------------------------------------------------------------------------- */ /* AUDIT TRAIL / LOGS SECTION */ /* -------------------------------------------------------------------------- */ /** * Daftar Aktivitas. * Izin: logs (read) */ public function activityLogs(Request $request) { Gate::authorize('check-access', ['logs', 'read']); $logs = ActivityLog::with('user') ->when($request->search, function ($query, $search) { $query->where(function ($q) use ($search) { $q->where('description', 'like', "%{$search}%") ->orWhereHas('user', function ($qu) use ($search) { $qu->where('name', 'like', "%{$search}%"); }); }); }) ->when($request->action, function ($query, $action) { $query->where('action', 'like', "%{$action}%"); }) ->latest() ->paginate(20); return view('pages.admin.logs', compact('logs')); } /** * Export Logs ke Excel. * Izin: logs (read) */ public function exportLogs() { Gate::authorize('check-access', ['logs', 'read']); return Excel::download(new ActivityLogExport, 'audit_trail_'.now()->format('Ymd').'.xlsx'); } /** * Bersihkan Logs. * Izin: logs (delete) */ public function clearLogs() { Gate::authorize('check-access', ['logs', 'delete']); return back()->with('error', 'Penghapusan massal audit trail dinonaktifkan untuk menjaga jejak perubahan data. Gunakan kebijakan retensi/arsip bila diperlukan.'); } }