- Added `priority`-based access logic to restrict role and user management actions. - Introduced `Permission Manager` UI and routes for permission access control. - Updated `RoleService` and `AppRoleService` to include `visible` scope for priority filtering. - Enhanced seeding to assign priorities to default roles and ensure proper hierarchy. - Updated sidebar, routes, and data structure to handle new permission enums and resource segmentation. - Improved UI components to dynamically restrict visibility and actions based on role priority.
129 lines
3.4 KiB
PHP
129 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Data\Role\{CreateRoleData, RoleData, UpdateRolePriorityData};
|
|
use App\Models\Role;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
use InvalidArgumentException;
|
|
use NoDiscard;
|
|
use Spatie\LaravelData\{DataCollection, PaginatedDataCollection};
|
|
use Throwable;
|
|
|
|
final class RoleService
|
|
{
|
|
/**
|
|
* Create a new role.
|
|
* Returns the created role DTO
|
|
*
|
|
* @throws Throwable when an error occurs during the creation.
|
|
*/
|
|
public function create(CreateRoleData $data): RoleData
|
|
{
|
|
$role = DB::transaction(fn () => Role::query()->create([
|
|
'name' => $data->name,
|
|
'priority' => $data->priority,
|
|
'guard_name' => 'web',
|
|
]));
|
|
|
|
return RoleData::from($role);
|
|
}
|
|
|
|
/**
|
|
* @throws InvalidArgumentException when id is invalid.
|
|
* @throws Throwable when an error occurs during the deletion.
|
|
*/
|
|
public function delete(int $id): void
|
|
{
|
|
if ($id <= 0) {
|
|
throw new InvalidArgumentException('Invalid id');
|
|
}
|
|
|
|
DB::transaction(function () use ($id): void {
|
|
Role::query()->findOrFail($id)->delete();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns a Paginated Collection of roles with their connected apps DTO
|
|
*
|
|
* @return PaginatedDataCollection<int, RoleData>
|
|
*/
|
|
#[NoDiscard]
|
|
public function getAll(): PaginatedDataCollection
|
|
{
|
|
$roles = Role::query()
|
|
->visible()
|
|
->with(['apps:id,name', 'users:id,name'])
|
|
->orderBy('id')
|
|
->paginate();
|
|
|
|
return RoleData::collect($roles, PaginatedDataCollection::class);
|
|
}
|
|
|
|
public function searchRolesForSelect(string $search = ''): Collection
|
|
{
|
|
return Role::query()
|
|
->visible()
|
|
->when('' !== $search, fn ($query) => $query->where('name', 'like', "%{$search}%"))
|
|
->select('id', 'name')
|
|
->get();
|
|
}
|
|
|
|
public function getAllRoleIds(): array
|
|
{
|
|
return Role::query()->visible()->pluck('id')->toArray();
|
|
}
|
|
|
|
/**
|
|
* Return all permissions for the given roles, grouped by role name.
|
|
* Each permission is a plain array so Livewire can serialise the property cleanly.
|
|
*
|
|
* @param array<int, int> $roleIds
|
|
*
|
|
* @return DataCollection<int, RoleData>|null
|
|
*/
|
|
#[NoDiscard]
|
|
public function getPermissionsGroupedByRole(array $roleIds): ?DataCollection
|
|
{
|
|
if (empty($roleIds)) {
|
|
return null;
|
|
}
|
|
|
|
$roles = Role::query()
|
|
->visible()
|
|
->with('permissions:id,name')
|
|
->whereIn('id', $roleIds)
|
|
->get(['id', 'name', 'priority']);
|
|
|
|
return RoleData::collect($roles, DataCollection::class);
|
|
}
|
|
|
|
/**
|
|
* Update the priority of a role.
|
|
*
|
|
* @throws InvalidArgumentException when roleId is invalid.
|
|
* @throws Throwable when an error occurs during the update.
|
|
*/
|
|
public function updatePriority(UpdateRolePriorityData $data): RoleData
|
|
{
|
|
if ($data->roleId <= 0) {
|
|
throw new InvalidArgumentException('Invalid role id');
|
|
}
|
|
|
|
$role = DB::transaction(function () use ($data) {
|
|
$role = Role::query()->findOrFail($data->roleId);
|
|
$role->update([
|
|
'priority' => $data->priority,
|
|
]);
|
|
|
|
return $role;
|
|
});
|
|
|
|
return RoleData::from($role);
|
|
}
|
|
}
|