first init

This commit is contained in:
ISMAIL MASSERAN
2026-06-08 11:37:14 +08:00
commit 94ecbe5887
1058 changed files with 87732 additions and 0 deletions
@@ -0,0 +1,181 @@
<?php
namespace Modules\Role\Http\Controllers;
use App\Http\Controllers\BaseCrudController;
use App\Services\ActivityLogger;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Modules\Role\Entities\Role;
use Modules\Role\Http\Requests\RoleRequest;
use Modules\Role\Repositories\Contracts\RoleRepositoryInterface;
use Modules\Role\Transformers\RoleResource;
use App\Models\Permission;
use Illuminate\Validation\Rule;
class RoleController extends BaseCrudController
{
protected $modelClass = Role::class;
protected $resourceClass = RoleResource::class;
protected $requestClass = RoleRequest::class;
protected $resourceName = 'role';
protected $resourceNamePlural = 'roles';
public function __construct(RoleRepositoryInterface $repository)
{
parent::__construct($repository);
}
/**
* Prepare data for store method
*/
protected function prepareStoreData(array $validated): array
{
return $validated;
}
/**
* Prepare data for update method
*/
protected function prepareUpdateData(array $validated, $role): array
{
return $validated;
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id): JsonResponse
{
$this->authorize('update', $this->modelClass);
try {
$item = $this->repository->findById($id);
if (! $item) {
return $this->errorResponse($this->getNotFoundMessage(), 404);
}
$validated = $this->validateRequest($request);
$data = $this->prepareUpdateData($validated, $item);
// Use repository update method to handle permissions
$updatedItem = $this->repository->update($id, $data);
ActivityLogger::log("Updated {$this->resourceName}: {$this->getItemName($updatedItem)}", $updatedItem);
return response()->json([
'success' => true,
'data' => new $this->resourceClass($updatedItem),
'message' => $this->getSuccessMessage('update'),
]);
} catch (Exception $e) {
Log::error("Error updating {$this->resourceName}: ".$e->getMessage());
return $this->errorResponse($this->getErrorMessage('update').': '.$e->getMessage(), 500);
}
}
/**
* Check dependencies before deletion
*/
protected function checkDependencies($role): ?JsonResponse
{
// Check if role has users assigned
if ($role->users()->count() > 0) {
return response()->json([
'success' => false,
'message' => 'Cannot delete role. It has users assigned to it.',
], 422);
}
return null;
}
/**
* Get all permissions for role assignment
*/
public function permissions(): JsonResponse
{
$permissions = Permission::all();
return response()->json([
'success' => true,
'data' => $permissions->map(function ($permission) {
return [
'id' => $permission->id,
'name' => $permission->name,
'guard_name' => $permission->guard_name,
'route_name' => $permission->route_name,
];
}),
]);
}
/**
* Assign permissions to a role
*/
public function assignPermissions(Request $request, string $id): JsonResponse
{
$request->validate([
'permissions' => 'required|array',
'permissions.*' => ['required', 'uuid', Rule::exists('permissions', 'id')],
]);
$role = $this->repository->find($id);
$this->repository->syncPermissions($role, $request->permissions);
return response()->json([
'success' => true,
'message' => 'Permissions assigned successfully.',
'data' => new RoleResource($role->load('permissions')),
]);
}
/**
* Get role with permissions
*/
public function show(string $id): JsonResponse
{
$role = $this->repository->find($id);
return response()->json([
'success' => true,
'data' => new RoleResource($role->load('permissions')),
]);
}
/**
* Get all roles with permissions
*/
public function index(Request $request): JsonResponse
{
$search = $request->get('search', '');
$roles = $this->repository->withPermissions($search);
return response()->json([
'success' => true,
'data' => RoleResource::collection($roles),
]);
}
/**
* Public endpoint for registration form (no auth required)
*/
public function publicRole(): JsonResponse
{
$roles = $this->repository->all();
return response()->json([
'success' => true,
'data' => RoleResource::collection($roles),
]);
}
}
@@ -0,0 +1,101 @@
<?php
namespace Modules\Role\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Modules\Role\Entities\Role;
class RoleRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'name' => [
'required',
'string',
'max:255'
],
'guard_name' => [
'required',
'string',
'in:api,web'
],
'permissions' => [
'sometimes',
'array'
],
'permissions.*' => [
'required',
'uuid',
Rule::exists('permissions', 'id'),
],
'fullname' => [
'required',
'string',
'max:255',
],
'context' => [
'required',
'string',
Rule::in(['member', 'admin']),
],
];
}
/**
* Configure the validator instance.
*/
public function withValidator($validator)
{
$validator->after(function ($validator) {
$roleId = $this->route('role');
$name = $this->input('name');
$guardName = $this->input('guard_name', 'api');
// Check for unique name within the same guard
$query = Role::where('name', $name)
->where('guard_name', $guardName);
if ($roleId) {
$query->where('id', '!=', $roleId);
}
if ($query->exists()) {
$validator->errors()->add('name', 'This role name already exists for the selected guard.');
}
});
}
/**
* Get custom messages for validator errors.
*/
public function messages(): array
{
return [
'name.required' => 'Role name is required.',
'name.unique' => 'This role name already exists for the selected guard.',
'guard_name.required' => 'Guard name is required.',
'guard_name.in' => 'Guard name must be either api or web.',
'permissions.array' => 'Permissions must be an array.',
'permissions.*.uuid' => 'Each permission id must be a valid UUID.',
'permissions.*.exists' => 'One or more selected permissions do not exist.',
'fullname.required' => 'Fullname is required.',
'fullname.string' => 'Fullname must be a string.',
'fullname.max' => 'Fullname must be less than 255 characters.',
'context.required' => 'Konteks peranan diperlukan.',
'context.in' => 'Konteks peranan mestilah ahli atau pentadbir.',
];
}
}