From 8e59b1f1f151797530ff501f9c8061dfb6608530 Mon Sep 17 00:00:00 2001 From: timotiabbauftech Date: Mon, 8 Sep 2025 09:48:32 +0700 Subject: [PATCH] [feat RoleMiddleware, update AuthControlller, app.php, BrankasList, TrayList, Login.vue, web.php --- app/Http/Controllers/AuthController.php | 4 + app/Http/Middleware/RoleMiddleware.php | 30 +++++++ bootstrap/app.php | 4 + resources/js/components/BrankasList.vue | 8 +- resources/js/components/TrayList.vue | 10 ++- resources/js/pages/Login.vue | 90 +++++++++++++-------- routes/web.php | 103 +++++++++++++----------- 7 files changed, 163 insertions(+), 86 deletions(-) create mode 100644 app/Http/Middleware/RoleMiddleware.php diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 7847730..e05cca7 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -29,10 +29,14 @@ class AuthController extends Controller // buat token Sanctum $token = $user->createToken('auth_token')->plainTextToken; + $redirectUrl = $user->role === 'owner' ? '/brankas' : '/kasir'; + return response()->json([ 'message' => 'Login berhasil', 'user' => $user, 'token' => $token, + 'redirect' => $redirectUrl, + 'role' => $user->role ]); } diff --git a/app/Http/Middleware/RoleMiddleware.php b/app/Http/Middleware/RoleMiddleware.php new file mode 100644 index 0000000..45363cc --- /dev/null +++ b/app/Http/Middleware/RoleMiddleware.php @@ -0,0 +1,30 @@ +user()) { + return response()->json(['message' => 'Unauthenticated'], 401); + } + + // cek role user + if (!in_array($request->user()->role, $roles)) { + return response()->json(['message' => 'Forbidden'], 403); + } + + return $next($request); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index b82d06f..9e7edfb 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -15,6 +15,10 @@ return Application::configure(basePath: dirname(__DIR__)) $middleware->validateCsrfTokens(except: [ 'api/*' ]); + + $middleware->alias([ + 'role' => \App\Http\Middleware\RoleMiddleware::class, + ]); }) ->withExceptions(function (Exceptions $exceptions): void { // diff --git a/resources/js/components/BrankasList.vue b/resources/js/components/BrankasList.vue index 5532207..958635f 100644 --- a/resources/js/components/BrankasList.vue +++ b/resources/js/components/BrankasList.vue @@ -45,10 +45,14 @@ const error = ref(null); onMounted(async () => { try { - const res = await axios.get("/api/item"); // ganti sesuai URL backend + const res = await axios.get("/api/item",{ + headers:{ + Authorization: `Bearer ${localStorage.getItem("token")}`, + } + }); // ganti sesuai URL backend items.value = res.data; // pastikan backend return array of items console.log(res.data); - + } catch (err) { error.value = err.message || "Gagal mengambil data"; } finally { diff --git a/resources/js/components/TrayList.vue b/resources/js/components/TrayList.vue index cf21122..ba5d68b 100644 --- a/resources/js/components/TrayList.vue +++ b/resources/js/components/TrayList.vue @@ -139,8 +139,14 @@ const saveMove = async () => { if (!selectedTrayId.value || !selectedItem.value) return; try { await axios.put(`/api/item/${selectedItem.value.id}`, { - id_nampan: selectedTrayId.value, - id_produk: selectedItem.value.id_produk, // ikutkan id_produk karena API minta + header:{ + Authorization: `Bearer ${localStorage.getItem("token")}`, + }, + body:{ + id_nampan: selectedTrayId.value, + id_produk: selectedItem.value.id_produk, // ikutkan id_produk karena API minta + + }, }); await refreshData(); diff --git a/resources/js/pages/Login.vue b/resources/js/pages/Login.vue index 4fe460c..c24008c 100644 --- a/resources/js/pages/Login.vue +++ b/resources/js/pages/Login.vue @@ -1,48 +1,72 @@ - - diff --git a/routes/web.php b/routes/web.php index 61eab8c..2f52ab0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,53 +1,37 @@ - group(function () { - // Backend API - Route::apiResource('nampan', NampanController::class); - Route::apiResource('produk', ProdukController::class); - Route::apiResource('item', ItemController::class); - Route::apiResource('sales', SalesController::class); - Route::apiResource('user', UserController::class); - Route::apiResource('transaksi', TransaksiController::class); - Route::apiResource('kategori', KategoriController::class); +group(function () { - Route::apiResource('nampan', NampanController::class); - Route::apiResource('produk', ProdukController::class); - Route::apiResource('item', ItemController::class); - Route::apiResource('sales', SalesController::class); - Route::apiResource('user', UserController::class); - Route::apiResource('transaksi', TransaksiController::class); - Route::apiResource('kategori', KategoriController::class); + // Auth + Route::post('/login', [AuthController::class, 'login'])->middleware('guest')->name('login'); + Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum')->name('logout'); - Route::get('brankas', [ItemController::class, 'brankasItem']); - Route::delete('kosongkan-nampan', [NampanController::class, 'kosongkan']); + Route::middleware(['auth:sanctum', 'role:owner'])->group(function () { + Route::apiResource('nampan', NampanController::class)->except(['index', 'show']); + Route::apiResource('produk', ProdukController::class)->except(['index', 'show']); + Route::apiResource('item', ItemController::class)->except(['index', 'show']); + Route::apiResource('sales', SalesController::class)->except(['index', 'show']); + Route::apiResource('kategori', KategoriController::class)->except(['index', 'show']); + Route::apiResource('user', UserController::class); - // Foto Sementara - Route::post('foto/upload', [FotoSementaraController::class, 'upload']); - Route::delete('foto/hapus/{id}', [FotoSementaraController::class, 'hapus']); - Route::get('foto/{user_id}', [FotoSementaraController::class, 'getAll']); - Route::delete('foto/reset/{user_id}', [FotoSementaraController::class, 'reset']); + // Custom Endpoint - // Laporan - Route::get('laporan', [LaporanController::class, 'ringkasan']); - Route::get('detail-laporan', [LaporanController::class, 'detail']); -}); - - Route::get('brankas', [ItemController::class, 'brankasItem']); Route::delete('kosongkan-nampan', [NampanController::class, 'kosongkan']); // Foto Sementara @@ -56,11 +40,32 @@ Route::prefix('api')->group(function () { Route::get('foto/{user_id}', [FotoSementaraController::class, 'getAll']); Route::delete('foto/reset/{user_id}', [FotoSementaraController::class, 'reset']); - Route::post('/login', [AuthController::class, 'login'])->middleware('guest')->name('login'); - Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:sanctum')->name('logout'); + // Laporan + Route::get('laporan', [LaporanController::class, 'ringkasan']); + Route::get('detail-laporan', [LaporanController::class, 'detail']); }); - // Frontend SPA - Route::get('/{any}', function () { - return view('app'); - })->where('any', '^(?!storage|api).*$'); \ No newline at end of file + Route::middleware(['auth:sanctum', 'role:owner,kasir'])->group(function () { + Route::apiResource('transaksi', TransaksiController::class); + Route::get('produk', [ProdukController::class, 'index']); + Route::get('produk/{id}', [ProdukController::class, 'show']); + Route::get('nampan', [NampanController::class, 'index']); + Route::get('nampan/{id}', [NampanController::class, 'show']); + Route::get('item', [ItemController::class, 'index']); + Route::get('item/{id}', [ItemController::class, 'show']); + Route::get('sales', [SalesController::class, 'index']); + Route::get('sales/{id}', [SalesController::class, 'show']); + Route::get('kategori', [KategoriController::class, 'index']); + Route::get('kategori/{id}', [KategoriController::class, 'show']); + Route::get('brankas', [ItemController::class, 'brankasItem']); + }); + +}); + + +// ============================ +// Frontend SPA (Vue / React dll.) +// ============================ +Route::get('/{any}', function () { + return view('app'); +})->where('any', '^(?!storage|api).*$');