isAllowed()) { return; } $status = $decision->status(); $error = $decision->error() !== '' ? $decision->error() : 'forbidden'; if ($status === 401) { ApiResponse::unauthorized(); } if ($status === 404) { ApiResponse::notFound($error); } if ($status === 403) { ApiResponse::forbidden($error); } ApiResponse::error($error, $status > 0 ? $status : 403); }; $method = $request->method(); if ($method === 'GET') { $decision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_API_USERS_INDEX_GET, [ 'actor_user_id' => ApiAuth::userId(), ]); $apiDeny($decision); $limit = max(1, min(100, $request->queryInt('limit', 25))); $offset = max(0, $request->queryInt('offset', 0)); $allowedOrders = ['id', 'uuid', 'first_name', 'last_name', 'display_name', 'email', 'created', 'modified', 'active', 'last_login_at']; $orderParam = $request->queryString('order'); $order = in_array($orderParam, $allowedOrders, true) ? $orderParam : 'last_name'; $dirParam = strtolower($request->queryString('dir')); $dir = in_array($dirParam, ['asc', 'desc'], true) ? $dirParam : 'asc'; $activeParam = $request->query('active'); if ($activeParam !== null) { $activeParam = in_array($activeParam, ['0', '1', 'true', 'false'], true) ? $activeParam : null; } $options = [ 'limit' => $limit, 'offset' => $offset, 'search' => $request->queryString('search'), 'order' => $order, 'dir' => $dir, 'active' => $activeParam, 'tenantUserId' => ApiAuth::userId(), ]; $scopedTenantId = ApiAuth::scopedTenantId(); if ($scopedTenantId) { $tenant = app(TenantService::class)->findById($scopedTenantId); $tenantUuid = trim((string) ($tenant['uuid'] ?? '')); if ($tenantUuid === '') { ApiResponse::notFound(); } $options['tenant'] = $tenantUuid; } $result = $userAccountService->listPaged($options); $rows = []; foreach ($result['rows'] as $row) { $rows[] = [ 'uuid' => $row['uuid'] ?? '', 'first_name' => $row['first_name'] ?? '', 'last_name' => $row['last_name'] ?? '', 'display_name' => $row['display_name'] ?? '', 'email' => $row['email'] ?? '', 'job_title' => $row['job_title'] ?? '', 'phone' => $row['phone'] ?? '', 'mobile' => $row['mobile'] ?? '', 'active' => (bool) ($row['active'] ?? 1), 'created' => $row['created'] ?? '', 'tenants' => $row['tenant_labels'] ?? [], 'departments' => $row['department_labels'] ?? [], 'roles' => $row['role_labels'] ?? [], ]; } ApiResponse::success([ 'data' => $rows, 'total' => $result['total'] ?? 0, 'limit' => $limit, 'offset' => $offset, ]); } if ($method === 'POST') { $input = $request->bodyAll(); $normalizeResult = app(UserApiWriteInputMapper::class)->normalize($input); if ($normalizeResult['ok'] !== true) { $errors = $normalizeResult['errors'] ?? []; ApiResponse::validationFromFormErrors(formErrorsFrom($errors ?: ['input' => ['invalid_value']])); } $input = $normalizeResult['input'] ?? $input; $decision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_API_USERS_INDEX_POST, [ 'actor_user_id' => ApiAuth::userId(), 'scoped_tenant_id' => ApiAuth::scopedTenantId(), 'input' => $input, ]); $apiDeny($decision); $authorizedInput = $decision->attribute('input', null); if (is_array($authorizedInput)) { $input = $authorizedInput; } $result = $userAccountService->createFromAdmin($input, ApiAuth::userId()); ApiResponse::fromServiceResult($result, 201); } ApiResponse::methodNotAllowed();