From bd9b0873a3a922963483aee2669360bd03422f54 Mon Sep 17 00:00:00 2001 From: althaf Date: Thu, 9 Jul 2026 17:42:55 +0700 Subject: [PATCH] refinement registrasi-verifikasi role & rbac --- .../Api/Konfigurasi/AuthController.php | 36 +- .../Web/Dashboard/SummaryController.php | 4 +- .../Web/Konfigurasi/AuthController.php | 9 +- .../Web/Konfigurasi/UserController.php | 35 +- app/Models/User.php | 3 +- ...145_add_status_and_role_to_users_table.php | 30 ++ .../views/konfigurasi/user/index.blade.php | 108 ++-- resources/views/layout/sidebar.blade.php | 487 +++++++----------- routes/web.php | 1 + 9 files changed, 349 insertions(+), 364 deletions(-) create mode 100644 database/migrations/2026_07_09_110145_add_status_and_role_to_users_table.php diff --git a/app/Http/Controllers/Api/Konfigurasi/AuthController.php b/app/Http/Controllers/Api/Konfigurasi/AuthController.php index d9e6ff0..b38d507 100644 --- a/app/Http/Controllers/Api/Konfigurasi/AuthController.php +++ b/app/Http/Controllers/Api/Konfigurasi/AuthController.php @@ -13,7 +13,7 @@ use App\Http\Resources\UserResource; class AuthController extends Controller { - public function login(Request $request): JSONResponse + public function login(Request $request): JsonResponse { $credentials = $request->validate([ 'email' => ['required', 'email'], @@ -27,6 +27,13 @@ class AuthController extends Controller } $user = Auth::user(); + + if ($user->status === 'pending') { + return response()->json([ + 'message' => 'Akun Anda masih berstatus pending. Silakan tunggu verifikasi dari Super Admin.' + ], 403); + } + $user->tokens()->delete(); $token = $user->createToken('mobile-token')->plainTextToken; @@ -37,14 +44,13 @@ class AuthController extends Controller ]); } - public function signup(Request $request): JSONResponse + public function signup(Request $request): JsonResponse { $credentials = $request->validate([ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], 'username' => ['required', 'string', 'max:255'], - 'role' => ['string'], 'uid' => ['required','string', 'unique:users'], ]); @@ -53,35 +59,27 @@ class AuthController extends Controller 'email' => $credentials['email'], 'password' => Hash::make($credentials['password']), 'username' => $credentials['username'], - 'role' => $credentials['role'], 'uid' => $credentials['uid'], + 'role' => null, + 'status' => 'pending', ]); $profile = Profile::create([ 'nama' => $credentials['name'], 'email' => $credentials['email'], - 'role' => $credentials['role'], 'user_uid' => $credentials['uid'], 'user_id' => $user->id, 'created_by' => $user->id, 'updated_by' => $user->id, + + + 'role' => null, ]); - if (!Auth::attempt($credentials)) { - return response()->json([ - 'message' => 'Email dan/atau password tidak sesuai' - ], 401); - } - - $user = Auth::user(); - $user->tokens()->delete(); - - $token = $user->createToken('mobile-token')->plainTextToken; - + return response()->json([ - 'access_token' => $token, - 'token_type' => 'Bearer', - ]); + 'message' => 'Registrasi berhasil. Akun Anda berstatus pending dan sedang menunggu verifikasi Super Admin.' + ], 201); } public function me(Request $request): JSONResponse diff --git a/app/Http/Controllers/Web/Dashboard/SummaryController.php b/app/Http/Controllers/Web/Dashboard/SummaryController.php index 9326b5b..43a0eee 100644 --- a/app/Http/Controllers/Web/Dashboard/SummaryController.php +++ b/app/Http/Controllers/Web/Dashboard/SummaryController.php @@ -25,8 +25,8 @@ class SummaryController extends Controller public function produktivitas(Request $request) { - if (!Gate::allows('super_admin') && !Gate::allows('admin')) { - abort(403); + if (!Gate::allows('super_admin') && !Gate::allows('admin') && !Gate::allows('fasilitator')) { + abort(403); } $title = 'Produktivitas Dashboard'; diff --git a/app/Http/Controllers/Web/Konfigurasi/AuthController.php b/app/Http/Controllers/Web/Konfigurasi/AuthController.php index ec89fc6..67f2662 100644 --- a/app/Http/Controllers/Web/Konfigurasi/AuthController.php +++ b/app/Http/Controllers/Web/Konfigurasi/AuthController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Web\Konfigurasi; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Models\User; +use Illuminate\Support\Str; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; @@ -34,15 +35,19 @@ class AuthController extends Controller User::create([ 'name' => $request->name, + 'username' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), + 'uid' => Str::uuid(), + 'status' => 'pending', + 'role' => null, 'email_verified_at' => null, 'created_by' => null, 'updated_by' => null, 'deleted_by' => null, ]); - - return redirect()->route('auth.login')->with('success', 'Account created successfully. Please login.'); + + return redirect('/login')->with('success', 'Account created successfully. Please login.'); } public function verify(User $user) diff --git a/app/Http/Controllers/Web/Konfigurasi/UserController.php b/app/Http/Controllers/Web/Konfigurasi/UserController.php index d9bfc73..68cc751 100644 --- a/app/Http/Controllers/Web/Konfigurasi/UserController.php +++ b/app/Http/Controllers/Web/Konfigurasi/UserController.php @@ -49,23 +49,42 @@ class UserController extends Controller return view('konfigurasi.user.index', compact('users', 'totalUsers', 'activeUsers', 'pendingUsers', 'roles', 'tab')); } - public function verify($id) + public function verify(Request $request, $id) { + $request->validate([ + 'role' => ['required', 'string'], + ]); + try { $user = User::findOrFail($id); + $user->email_verified_at = now(); + $user->status = 'verified'; + $user->role = $request->role; $user->save(); - return response()->json([ - 'status' => 'success', - 'message' => 'User berhasil diverifikasi dan diaktifkan.' + Profile::where('user_id', $user->id)->update([ + 'role' => $request->role ]); + + if ($request->expectsJson()) { + return response()->json([ + 'status' => 'success', + 'message' => 'User ' . $user->name . ' berhasil diverifikasi sebagai ' . $request->role . '.' + ]); + } + + return redirect()->back()->with('success', 'User ' . $user->name . ' berhasil diverifikasi sebagai ' . $request->role . '.'); } catch (\Exception $e) { - return response()->json([ - 'status' => 'error', - 'message' => 'Gagal verifikasi user.' - ], 500); + if ($request->expectsJson()) { + return response()->json([ + 'status' => 'error', + 'message' => 'Gagal verifikasi user: ' . $e->getMessage() + ], 500); + } + + return back()->with('error', 'Gagal verifikasi user: ' . $e->getMessage()); } } diff --git a/app/Models/User.php b/app/Models/User.php index ae21e48..0fb0634 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -22,7 +22,8 @@ class User extends Authenticatable 'email_verified_at', 'role', 'username', - 'uid' + 'uid', + 'status' ]; protected $hidden = [ diff --git a/database/migrations/2026_07_09_110145_add_status_and_role_to_users_table.php b/database/migrations/2026_07_09_110145_add_status_and_role_to_users_table.php new file mode 100644 index 0000000..1999ccd --- /dev/null +++ b/database/migrations/2026_07_09_110145_add_status_and_role_to_users_table.php @@ -0,0 +1,30 @@ +string('status')->default('pending')->after('password'); + + if (!Schema::hasColumn('users', 'role')) { + $table->string('role')->nullable()->after('status'); + } + }); + } + + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('status'); + $table->dropColumn('role'); + }); + } +}; diff --git a/resources/views/konfigurasi/user/index.blade.php b/resources/views/konfigurasi/user/index.blade.php index 1b7cd67..c4405ef 100644 --- a/resources/views/konfigurasi/user/index.blade.php +++ b/resources/views/konfigurasi/user/index.blade.php @@ -178,20 +178,30 @@ Verified @else Pending -
- @csrf - @method('PATCH') - -
- + + @endif - -
- - -
- + +
+ + + + + + + + + @if(!$user->email_verified_at) + + @endif +
+ @empty No users found. @@ -216,34 +226,54 @@ $(document).ready(function () { $(document).on('click', '.btn-verify', function (e) { e.preventDefault(); - - const form = $(this).closest('form'); - const url = form.attr('action'); - const formData = new FormData(form[0]); + const url = $(this).data('url'); Swal.fire({ - title: 'Verifikasi User?', - text: "User ini akan diaktifkan dan dapat login ke dalam sistem.", - icon: 'question', + title: 'Verifikasi Akun', + icon: 'info', + iconColor: '#696cff', + width: '28em', + html: ` +

Tentukan role akses untuk pengguna ini agar dapat masuk ke dalam sistem AgroMonev.

+ +
+ +
+ `, showCancelButton: true, - confirmButtonText: 'Ya, Verifikasi!', + confirmButtonText: ' Simpan', cancelButtonText: 'Batal', customClass: { - confirmButton: 'btn btn-success me-3', - cancelButton: 'btn btn-label-secondary' + popup: 'rounded-4', + confirmButton: 'btn btn-primary me-3 waves-effect waves-light', + cancelButton: 'btn btn-label-secondary waves-effect' }, - buttonsStyling: false + buttonsStyling: false, + preConfirm: () => { + const role = Swal.getPopup().querySelector('#role-select').value; + if (!role) { + Swal.showValidationMessage('Silakan pilih role terlebih dahulu!'); + } + return { role: role }; + } }).then(function (result) { - if (result.value) { + if (result.isConfirmed) { + const payload = { + _token: csrfToken, + _method: 'PUT', + role: result.value.role + }; + $.ajax({ url: url, - type: 'POST', - data: formData, - processData: false, - contentType: false, - headers: { - 'Accept': 'application/json' - }, + type: 'POST', + data: payload, success: function (res) { if (res.status === 'success') { Swal.fire({ @@ -251,17 +281,18 @@ title: 'Berhasil!', text: res.message, showConfirmButton: false, - timer: 1500 + timer: 1500, + customClass: { popup: 'rounded-4' } }).then(() => { window.location.reload(); }); } else { - Swal.fire({ icon: 'error', title: 'Gagal!', text: res.message }); + Swal.fire({ icon: 'error', title: 'Gagal!', text: res.message, customClass: { popup: 'rounded-4' } }); } }, error: function (xhr) { let errorMsg = xhr.responseJSON ? xhr.responseJSON.message : 'Terjadi kesalahan pada server.'; - Swal.fire({ icon: 'error', title: 'Error!', text: errorMsg }); + Swal.fire({ icon: 'error', title: 'Error!', text: errorMsg, customClass: { popup: 'rounded-4' } }); } }); } @@ -276,10 +307,7 @@ $(document).on('click', '.edit-record', function (e) { e.preventDefault(); - const id = $(this).data('id'); - const offcanvasEditEl = document.getElementById('offcanvasEdit'); - if (!id) return; $(this).html(''); @@ -290,10 +318,8 @@ type: 'GET', success: function (res) { btn.html(''); - if (res.status === 'success') { const user = res.data; - $('#editUserName').text(user.name); $('#editEmail').text(user.email); $('#formEdit').attr('action', `/users/${user.id}`); @@ -355,7 +381,7 @@ }).then(function (result) { if (result.value) { $.ajax({ - url: `/users/${id}`, // Sesuaikan dengan route destroy kamu + url: `/users/${id}`, type: 'DELETE', headers: { 'X-CSRF-TOKEN': csrfToken }, success: function (res) { @@ -369,4 +395,4 @@ }); }); -@endpush +@endpush \ No newline at end of file diff --git a/resources/views/layout/sidebar.blade.php b/resources/views/layout/sidebar.blade.php index 4d350a3..0398ce0 100644 --- a/resources/views/layout/sidebar.blade.php +++ b/resources/views/layout/sidebar.blade.php @@ -1,144 +1,114 @@ + \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index ef59acf..b92f5ad 100644 --- a/routes/web.php +++ b/routes/web.php @@ -3,6 +3,7 @@ use Illuminate\Support\Facades\Route; //Auth +Route::put('/users/{id}/verify', [App\Http\Controllers\Web\Konfigurasi\UserController::class, 'verify'])->name('users.verify'); Route::get('/login', [App\Http\Controllers\Web\Konfigurasi\AuthController::class, 'login'])->name('login'); Route::get('/register', [App\Http\Controllers\Web\Konfigurasi\AuthController::class, 'register'])->name('register'); Route::post('/create-account', [App\Http\Controllers\Web\Konfigurasi\AuthController::class, 'createAccount'])->name('auth.createAccount');