From 585d36fe09c1e76fce819d4fd7ca7c28272d37a5 Mon Sep 17 00:00:00 2001 From: micko samawa Date: Mon, 18 May 2026 20:50:22 +0700 Subject: [PATCH] feat: Separate admin and user tables for independent authentication - Create new 'admins' table with role column (admin/super_admin) - Create Admin model for admin authentication - Add AdminSeeder with test data (super_admin, admin) - Update config/auth.php with dual guards (web for users, admin for admins) - Update AdminAuthController to use Admin model and 'admin' guard - Remove role column from users table (users have no role) - Update register validation messages in Indonesian - Now same email can be used by user and admin (separate tables) --- .../Http/Controllers/AdminAuthController.php | 34 +++++++------- .../Http/Controllers/Api/AuthController.php | 27 +++++++++-- spk_kontrakan/app/Models/Admin.php | 47 +++++++++++++++++++ spk_kontrakan/app/Models/User.php | 4 +- spk_kontrakan/config/auth.php | 9 +++- .../2026_05_18_000001_create_admins_table.php | 40 ++++++++++++++++ ...001_fix_email_unique_with_soft_deletes.php | 18 +++++++ ..._000002_remove_soft_deletes_from_users.php | 23 +++++++++ ...26_05_18_000003_remove_role_from_users.php | 29 ++++++++++++ .../database/seeders/AdminSeeder.php | 33 +++++++++++++ 10 files changed, 239 insertions(+), 25 deletions(-) create mode 100644 spk_kontrakan/app/Models/Admin.php create mode 100644 spk_kontrakan/database/migrations/2026_05_18_000001_create_admins_table.php create mode 100644 spk_kontrakan/database/migrations/2026_05_18_000001_fix_email_unique_with_soft_deletes.php create mode 100644 spk_kontrakan/database/migrations/2026_05_18_000002_remove_soft_deletes_from_users.php create mode 100644 spk_kontrakan/database/migrations/2026_05_18_000003_remove_role_from_users.php create mode 100644 spk_kontrakan/database/seeders/AdminSeeder.php diff --git a/spk_kontrakan/app/Http/Controllers/AdminAuthController.php b/spk_kontrakan/app/Http/Controllers/AdminAuthController.php index 4e9a25a..740592d 100644 --- a/spk_kontrakan/app/Http/Controllers/AdminAuthController.php +++ b/spk_kontrakan/app/Http/Controllers/AdminAuthController.php @@ -4,7 +4,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; -use App\Models\User; +use App\Models\Admin; use Illuminate\Support\Facades\Hash; class AdminAuthController extends Controller @@ -23,16 +23,8 @@ public function login(Request $request) 'password' => 'required' ]); - // FIXED: Hapus guard('admin'), pakai default Auth - if (Auth::attempt($credentials)) { - // Cek role - hanya admin dan super_admin yang boleh login - $user = Auth::user(); - if (!in_array($user->role, ['admin', 'super_admin'])) { - Auth::logout(); - $request->session()->invalidate(); - return back()->with('error', 'Akses ditolak. Halaman ini khusus untuk pemilik bisnis.'); - } - + // Gunakan guard 'admin' - ambil dari tabel admins + if (Auth::guard('admin')->attempt($credentials)) { $request->session()->regenerate(); return redirect()->intended(route('dashboard')); } @@ -51,16 +43,25 @@ public function register(Request $request) { $request->validate([ 'name' => 'required|string|max:50', - 'email' => 'required|email|unique:users,email', + 'email' => 'required|email|unique:admins,email', 'password' => 'required|min:6|confirmed' + ], [ + 'name.required' => 'Nama wajib diisi', + 'name.max' => 'Nama maksimal 50 karakter', + 'email.required' => 'Email wajib diisi', + 'email.email' => 'Format email tidak valid', + 'email.unique' => 'Email sudah terdaftar', + 'password.required' => 'Password wajib diisi', + 'password.min' => 'Password minimal 6 karakter', + 'password.confirmed' => 'Konfirmasi password tidak cocok' ]); - // Simpan ke tabel users (ROLE SELALU admin - tidak bisa diubah user) - User::create([ + // Simpan ke tabel admins (ROLE SELALU admin) + Admin::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), - 'role' => 'admin' // PAKSA SELALU ADMIN - tidak bisa jadi super_admin lewat register + 'role' => 'admin' // Hanya admin, tidak bisa super_admin ]); return redirect()->route('admin.login')->with('success', 'Akun admin berhasil dibuat!'); @@ -69,8 +70,7 @@ public function register(Request $request) // Logout Admin public function logout(Request $request) { - // FIXED: Hapus guard('admin'), pakai default Auth - Auth::logout(); + Auth::guard('admin')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); diff --git a/spk_kontrakan/app/Http/Controllers/Api/AuthController.php b/spk_kontrakan/app/Http/Controllers/Api/AuthController.php index 09b779c..86fb717 100644 --- a/spk_kontrakan/app/Http/Controllers/Api/AuthController.php +++ b/spk_kontrakan/app/Http/Controllers/Api/AuthController.php @@ -19,6 +19,8 @@ class AuthController extends Controller public function register(RegisterRequest $request) { try { + Log::info('Register attempt', ['email' => $request->email, 'name' => $request->name]); + $user = User::create([ 'name' => $request->name, 'email' => $request->email, @@ -29,6 +31,8 @@ public function register(RegisterRequest $request) $token = $user->createToken('mobile-app-token')->plainTextToken; + Log::info('Registration successful', ['user_id' => $user->id]); + return response()->json([ 'success' => true, 'message' => 'Registrasi berhasil', @@ -37,11 +41,28 @@ public function register(RegisterRequest $request) 'token' => $token ] ], 201); - } catch (\Exception $e) { - Log::error('Registration error: ' . $e->getMessage()); + } catch (\Illuminate\Database\QueryException $e) { + Log::error('Database error during registration', [ + 'email' => $request->email, + 'message' => $e->getMessage(), + 'sql' => $e->getSql() ?? 'N/A', + 'bindings' => $e->getBindings() ?? [] + ]); return response()->json([ 'success' => false, - 'message' => 'Terjadi kesalahan saat registrasi', + 'message' => 'Database error: ' . $e->getMessage(), + 'error_code' => 'DB_ERROR', + ], 500); + } catch (\Exception $e) { + Log::error('Registration error', [ + 'email' => $request->email, + 'exception' => get_class($e), + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + return response()->json([ + 'success' => false, + 'message' => 'Terjadi kesalahan saat registrasi: ' . $e->getMessage(), 'error_code' => 'REGISTRATION_FAILED', ], 500); } diff --git a/spk_kontrakan/app/Models/Admin.php b/spk_kontrakan/app/Models/Admin.php new file mode 100644 index 0000000..d8bbe72 --- /dev/null +++ b/spk_kontrakan/app/Models/Admin.php @@ -0,0 +1,47 @@ + + */ + protected $fillable = [ + 'name', + 'email', + 'password', + 'role', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var array + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } +} diff --git a/spk_kontrakan/app/Models/User.php b/spk_kontrakan/app/Models/User.php index 49d17ec..942675d 100644 --- a/spk_kontrakan/app/Models/User.php +++ b/spk_kontrakan/app/Models/User.php @@ -4,7 +4,6 @@ // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; @@ -12,7 +11,7 @@ class User extends Authenticatable { /** @use HasFactory<\Database\Factories\UserFactory> */ - use HasFactory, Notifiable, SoftDeletes, HasApiTokens; + use HasFactory, Notifiable, HasApiTokens; /** * The attributes that are mass assignable. @@ -23,7 +22,6 @@ class User extends Authenticatable 'name', 'email', 'password', - 'role', 'phone', ]; diff --git a/spk_kontrakan/config/auth.php b/spk_kontrakan/config/auth.php index bcc64b7..702b623 100644 --- a/spk_kontrakan/config/auth.php +++ b/spk_kontrakan/config/auth.php @@ -3,7 +3,7 @@ return [ 'defaults' => [ - 'guard' => 'admin', + 'guard' => 'web', 'passwords' => 'users', ], @@ -15,7 +15,7 @@ 'admin' => [ 'driver' => 'session', - 'provider' => 'users', // ← PENTING!! + 'provider' => 'admins', // ← Guard terpisah untuk admin ], ], @@ -24,6 +24,11 @@ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], + + 'admins' => [ + 'driver' => 'eloquent', + 'model' => App\Models\Admin::class, + ], ], 'passwords' => [ diff --git a/spk_kontrakan/database/migrations/2026_05_18_000001_create_admins_table.php b/spk_kontrakan/database/migrations/2026_05_18_000001_create_admins_table.php new file mode 100644 index 0000000..2b1822a --- /dev/null +++ b/spk_kontrakan/database/migrations/2026_05_18_000001_create_admins_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->enum('role', ['admin', 'super_admin'])->default('admin'); // Pembeda admin vs super_admin + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('admin_password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('admins'); + Schema::dropIfExists('admin_password_reset_tokens'); + } +}; diff --git a/spk_kontrakan/database/migrations/2026_05_18_000001_fix_email_unique_with_soft_deletes.php b/spk_kontrakan/database/migrations/2026_05_18_000001_fix_email_unique_with_soft_deletes.php new file mode 100644 index 0000000..abee792 --- /dev/null +++ b/spk_kontrakan/database/migrations/2026_05_18_000001_fix_email_unique_with_soft_deletes.php @@ -0,0 +1,18 @@ +whereNotNull('deleted_at')->delete(); + } + + public function down(): void + { + // Cannot restore deleted records + } +}; diff --git a/spk_kontrakan/database/migrations/2026_05_18_000002_remove_soft_deletes_from_users.php b/spk_kontrakan/database/migrations/2026_05_18_000002_remove_soft_deletes_from_users.php new file mode 100644 index 0000000..925f030 --- /dev/null +++ b/spk_kontrakan/database/migrations/2026_05_18_000002_remove_soft_deletes_from_users.php @@ -0,0 +1,23 @@ +dropSoftDeletes(); + }); + } + + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->softDeletes(); + }); + } +}; diff --git a/spk_kontrakan/database/migrations/2026_05_18_000003_remove_role_from_users.php b/spk_kontrakan/database/migrations/2026_05_18_000003_remove_role_from_users.php new file mode 100644 index 0000000..e8e3cff --- /dev/null +++ b/spk_kontrakan/database/migrations/2026_05_18_000003_remove_role_from_users.php @@ -0,0 +1,29 @@ +dropColumn('role'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->enum('role', ['super_admin', 'admin', 'user'])->default('user')->nullable(); + }); + } +}; diff --git a/spk_kontrakan/database/seeders/AdminSeeder.php b/spk_kontrakan/database/seeders/AdminSeeder.php new file mode 100644 index 0000000..c55b55f --- /dev/null +++ b/spk_kontrakan/database/seeders/AdminSeeder.php @@ -0,0 +1,33 @@ + 'Super Admin', + 'email' => 'super@admin.com', + 'password' => Hash::make('password123'), + 'role' => 'super_admin' + ]); + + // Buat admin biasa + Admin::create([ + 'name' => 'Admin', + 'email' => 'admin@admin.com', + 'password' => Hash::make('password123'), + 'role' => 'admin' + ]); + } +}