feat(roles): tambah fitur relasi posisi pada role

- Tambahkan relasi posisi dengan menambahkan kolom `position_id` pada tabel roles melalui migrasi.
- Perbarui fungsi pada `RolesController` untuk menyertakan posisi dalam proses CRUD.
  - Gunakan model `Position` untuk mendapatkan daftar posisi baik saat membuat maupun mengedit role.
  - Sesuaikan nama permission dari `roles.view` ke `roles.read`, `roles.store` ke `roles.create`, dan `roles.edit` ke `roles.update` agar konsisten.
- Perbarui validasi di `RoleRequest` untuk mendukung input `position_id`.
- Tambahkan properti `position_id` ke atribut `fillable` di model Role untuk mendukung mass assignment.
- Buat fungsi relasi `position()` pada model Role untuk mereferensikan ke model Position.
- Perbarui tampilan form role (`create.blade.php`):
  - Tambahkan dropdown untuk memilih posisi dalam form input.
  - Tampilkan informasi level posisi bersama dengan nama posisi dalam dropdown.
  - Sinkronisasi validasi dan nilai default sesuai dengan pengaturan posisi.
- Perbaikan minor pada query pencarian data roles, menggunakan `whereRaw` untuk pencarian case-insensitive.
This commit is contained in:
Daeng Deni Mardaeni
2025-05-17 14:12:48 +07:00
parent 1007515faa
commit e9fa45a808
5 changed files with 161 additions and 81 deletions

View File

@@ -10,6 +10,7 @@
use Modules\Usermanagement\Http\Requests\RoleRequest; use Modules\Usermanagement\Http\Requests\RoleRequest;
use Modules\Usermanagement\Models\Permission; use Modules\Usermanagement\Models\Permission;
use Modules\Usermanagement\Models\PermissionGroup; use Modules\Usermanagement\Models\PermissionGroup;
use Modules\Usermanagement\Models\Position;
use Modules\Usermanagement\Models\Role; use Modules\Usermanagement\Models\Role;
/** /**
@@ -48,7 +49,7 @@
public function index() public function index()
{ {
// Check if the authenticated user has the required permission to view roles // Check if the authenticated user has the required permission to view roles
if (is_null($this->user) || !$this->user->can('roles.view')) { if (is_null($this->user) || !$this->user->can('roles.read')) {
//abort(403, 'Sorry! You are not allowed to view roles.'); //abort(403, 'Sorry! You are not allowed to view roles.');
} }
@@ -70,7 +71,7 @@
public function store(RoleRequest $request) public function store(RoleRequest $request)
{ {
// Check if the authenticated user has the required permission to store roles // Check if the authenticated user has the required permission to store roles
if (is_null($this->user) || !$this->user->can('roles.store')) { if (is_null($this->user) || !$this->user->can('roles.create')) {
//abort(403, 'Sorry! You are not allowed to store roles.'); //abort(403, 'Sorry! You are not allowed to store roles.');
} }
@@ -115,8 +116,9 @@
} }
$permissiongroups = PermissionGroup::all(); $permissiongroups = PermissionGroup::all();
$positions = Position::all();
// Return the view for creating a new role // Return the view for creating a new role
return view('usermanagement::roles.create',compact('permissiongroups')); return view('usermanagement::roles.create', compact('permissiongroups', 'positions'));
} }
/** /**
@@ -130,7 +132,7 @@
public function show($id) public function show($id)
{ {
// Check if the authenticated user has the required permission to view roles // Check if the authenticated user has the required permission to view roles
if (is_null($this->user) || !$this->user->can('roles.view')) { if (is_null($this->user) || !$this->user->can('roles.read')) {
abort(403, 'Sorry! You are not allowed to view roles.'); abort(403, 'Sorry! You are not allowed to view roles.');
} }
@@ -154,7 +156,7 @@
public function edit($id) public function edit($id)
{ {
// Check if the authenticated user has the required permission to edit roles // Check if the authenticated user has the required permission to edit roles
if (is_null($this->user) || !$this->user->can('roles.edit')) { if (is_null($this->user) || !$this->user->can('roles.update')) {
//abort(403, 'Sorry! You are not allowed to edit roles.'); //abort(403, 'Sorry! You are not allowed to edit roles.');
} }
@@ -162,8 +164,9 @@
$role = Role::find($id); $role = Role::find($id);
$permissions = Permission::all(); $permissions = Permission::all();
$permissiongroups = PermissionGroup::all(); $permissiongroups = PermissionGroup::all();
$positions = Position::all();
// Return the view for editing the role // Return the view for editing the role
return view('usermanagement::roles.create', compact('role','permissions','permissiongroups')); return view('usermanagement::roles.create', compact('role', 'permissions', 'permissiongroups', 'positions'));
} }
@@ -272,7 +275,7 @@
*/ */
public function dataForDatatables(Request $request) public function dataForDatatables(Request $request)
{ {
if (is_null($this->user) || !$this->user->can('roles.view')) { if (is_null($this->user) || !$this->user->can('roles.read')) {
//abort(403, 'Sorry! You are not allowed to view users.'); //abort(403, 'Sorry! You are not allowed to view users.');
} }
@@ -283,7 +286,7 @@
if ($request->has('search') && !empty($request->get('search'))) { if ($request->has('search') && !empty($request->get('search'))) {
$search = $request->get('search'); $search = $request->get('search');
$query->where(function ($q) use ($search) { $query->where(function ($q) use ($search) {
$q->where('name', 'LIKE', "%$search%"); $q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%']);
}); });
} }

View File

@@ -23,6 +23,7 @@
$rules = [ $rules = [
'guard_names' => 'required|string|in:web,api', 'guard_names' => 'required|string|in:web,api',
'position_id' => 'nullable|exists:positions,id',
]; ];
if ($this->method() === 'PUT') { if ($this->method() === 'PUT') {
@@ -41,6 +42,3 @@
]); ]);
} }
} }

View File

@@ -11,6 +11,17 @@
{ {
use softDeletes, LogsActivity; use softDeletes, LogsActivity;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'guard_name',
'position_id',
];
/** /**
* Retrieve the activity log options for this role. * Retrieve the activity log options for this role.
* *
@@ -22,4 +33,11 @@
return LogOptions::defaults()->logAll()->useLogName('User Management|Roles : '); return LogOptions::defaults()->logAll()->useLogName('User Management|Roles : ');
} }
/**
* Get the position that owns the role.
*/
public function position()
{
return $this->belongsTo(Position::class);
}
} }

View File

@@ -0,0 +1,45 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
}
Schema::table($tableNames['roles'], function (Blueprint $table) {
$table->unsignedBigInteger('position_id')->nullable()->after('guard_name');
$table->foreign('position_id')
->references('id')
->on('positions')
->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$tableNames = config('permission.table_names');
if (empty($tableNames)) {
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
}
Schema::table($tableNames['roles'], function (Blueprint $table) {
$table->dropForeign(['position_id']);
$table->dropColumn('position_id');
});
}
};

View File

@@ -6,14 +6,12 @@
@section('content') @section('content')
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto"> <div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
<form action="{{ isset($role->id) ? route('users.roles.update', $role->id) : route('users.roles.store') }}" method="POST" id="role_form">
@csrf
@if(isset($role->id)) @if(isset($role->id))
<form action="{{ route('users.roles.update', $role->id) }}" method="POST" id="role_form">
<input type="hidden" name="id" value="{{ $role->id }}"> <input type="hidden" name="id" value="{{ $role->id }}">
@method('PUT') @method('PUT')
@else
<form method="POST" action="{{ route('users.roles.store') }}">
@endif @endif
@csrf
<div class="card pb-2.5"> <div class="card pb-2.5">
<div class="card-header" id="basic_settings"> <div class="card-header" id="basic_settings">
<h3 class="card-title"> <h3 class="card-title">
@@ -35,6 +33,24 @@
@enderror @enderror
</div> </div>
</div> </div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56">
Position
</label>
<div class="flex flex-wrap items-baseline w-full">
<select class="select @error('position_id') border-danger @enderror" name="position_id">
<option value="">Select Position</option>
@foreach($positions as $position)
<option value="{{ $position->id }}" {{ (isset($role) && $role->position_id == $position->id) ? 'selected' : '' }}>
{{ $position->name }} (Level: {{ $position->level }})
</option>
@endforeach
</select>
@error('position_id')
<em class="alert text-danger text-sm">{{ $message }}</em>
@enderror
</div>
</div>
<div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5"> <div class="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
<label class="form-label max-w-56"> <label class="form-label max-w-56">
Administrator/Superuser Access Administrator/Superuser Access