200 lines
6.3 KiB
PHP
200 lines
6.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Http\Controllers;
|
||
|
|
|
||
|
|
use App\Models\User;
|
||
|
|
use App\Models\Role;
|
||
|
|
use App\Traits\LogsActivity;
|
||
|
|
use Illuminate\Http\Request;
|
||
|
|
use Illuminate\View\View;
|
||
|
|
use Illuminate\Http\RedirectResponse;
|
||
|
|
use Illuminate\Support\Facades\Hash;
|
||
|
|
use Illuminate\Support\Facades\Gate; // WAJIB DIIMPORT
|
||
|
|
use Illuminate\Validation\Rules;
|
||
|
|
use App\Models\ActivityLog;
|
||
|
|
use Maatwebsite\Excel\Facades\Excel;
|
||
|
|
use App\Exports\ActivityLogExport;
|
||
|
|
|
||
|
|
class UserController extends Controller
|
||
|
|
{
|
||
|
|
use LogsActivity;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Menampilkan daftar user.
|
||
|
|
* Izin: users (read)
|
||
|
|
*/
|
||
|
|
public function index(Request $request): View
|
||
|
|
{
|
||
|
|
// GANTI: Otorisasi berdasarkan Matriks Permission
|
||
|
|
Gate::authorize('check-access', ['users', 'read']);
|
||
|
|
|
||
|
|
$users = User::query()
|
||
|
|
->with('role')
|
||
|
|
->when($request->search, function ($query, $search) {
|
||
|
|
$query->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']);
|
||
|
|
ActivityLog::truncate();
|
||
|
|
return back()->with('success', 'Seluruh riwayat aktivitas telah dibersihkan.');
|
||
|
|
}
|
||
|
|
}
|