all(); Guard::requireLogin(); $request = requestInput(); $returnTarget = requestResolveReturnTarget(); $closeTarget = requestResolveReturnTarget('admin/users'); $createTarget = requestPathWithReturnTarget('admin/users/create', $returnTarget); $authorizationService = app(\MintyPHP\Service\Access\AuthorizationService::class); $decision = $authorizationService->authorize(UserAuthorizationPolicy::ABILITY_ADMIN_USERS_CREATE, [ 'actor_user_id' => (int) ($session['user']['id'] ?? 0), ]); if (!$decision->isAllowed()) { if (Request::wantsJson()) { http_response_code($decision->status()); Router::json(['error' => $decision->error()]); return; } Router::redirect('error/forbidden?url=' . urlencode(Request::pathWithQuery())); return; } $userAccountService = app(\MintyPHP\Service\User\UserAccountService::class); $userAssignmentService = app(\MintyPHP\Service\User\UserAssignmentService::class); $userPasswordPolicyService = app(\MintyPHP\Service\User\UserPasswordPolicyService::class); $userCustomFieldValueService = app(UserCustomFieldValueService::class); $passwordMinLength = $userPasswordPolicyService->minLength(); $passwordHints = $userPasswordPolicyService->hints(); $settingsDefaultsGateway = app(\MintyPHP\Service\Settings\SettingsDefaultsGateway::class); $directoryScopeGateway = app(\MintyPHP\Service\Tenant\TenantScopeService::class); $tenantService = app(\MintyPHP\Service\Tenant\TenantService::class); $roleService = app(\MintyPHP\Service\Access\RoleService::class); $departmentService = app(\MintyPHP\Service\Org\DepartmentService::class); $currentUserId = (int) ($session['user']['id'] ?? 0); $uiAccessService = app(UiAccessService::class); $viewAuth['page'] = $uiAccessService->pageCapabilities($currentUserId, UiCapabilityMap::PAGE_USERS_CREATE); $pageAuth = is_array($viewAuth['page'] ?? null) ? $viewAuth['page'] : []; $canManageAssignments = (bool) ($pageAuth['can_manage_assignments'] ?? false); $canEditCustomFieldValues = (bool) ($pageAuth['can_edit_custom_field_values'] ?? false); $allowedTenantIds = $directoryScopeGateway->getUserTenantIds($currentUserId); $tenants = $tenantService->list(); if ($allowedTenantIds) { $tenants = array_values(array_filter($tenants, static function (array $tenant) use ($allowedTenantIds): bool { $tenantId = (int) ($tenant['id'] ?? 0); return $tenantId > 0 && in_array($tenantId, $allowedTenantIds, true); })); } elseif ($directoryScopeGateway->isStrict()) { $tenants = []; } $roles = $roleService->listActive(); $assignableRoleService = app(\MintyPHP\Service\Access\AssignableRoleService::class); $assignableRoleIds = $assignableRoleService->listAssignableRoleIdsForActor($currentUserId); $assignableRoleIdMap = array_fill_keys($assignableRoleIds, true); $roles = array_values(array_filter($roles, static fn (array $r): bool => isset($assignableRoleIdMap[(int) ($r['id'] ?? 0)]))); $selectedTenantIds = []; $selectedRoleIds = []; $selectedDepartmentIds = []; $departmentOptionsByTenant = []; $customFieldDefinitionsByTenant = []; $customFieldValueMap = []; $customFieldPostedValues = [ 'custom_field_values' => [], 'custom_field_values_multi' => [], ]; $errorBag = formErrors(); $errors = []; $form = [ 'first_name' => '', 'last_name' => '', 'email' => '', 'profile_description' => '', 'job_title' => '', 'phone' => '', 'mobile' => '', 'short_dial' => '', 'address' => '', 'postal_code' => '', 'city' => '', 'country' => '', 'region' => '', 'hire_date' => '', 'totp_secret' => '', 'locale' => I18n::$locale ?? I18n::$defaultLocale, 'active' => 1, ]; if ($request->isMethod('POST') && !actionRequireCsrf($createTarget, $createTarget, 'csrf_expired')) { return; } if ($request->isMethod('POST')) { $post = $request->bodyAll(); $input = $post; $tenantIds = $canManageAssignments ? $userAssignmentService->normalizeIdInput($input['tenant_ids'] ?? []) : []; if ($allowedTenantIds) { $tenantIds = array_values(array_intersect($tenantIds, $allowedTenantIds)); } elseif ($directoryScopeGateway->isStrict()) { $tenantIds = []; } $defaultTenantId = $settingsDefaultsGateway->getDefaultTenantId(); if ( $canManageAssignments && $directoryScopeGateway->isStrict() && !$tenantIds && !$defaultTenantId ) { $errorBag->addGlobal(t('Please select at least one tenant')); } $selectedTenantIds = $tenantIds; $selectedRoleIds = $canManageAssignments ? $userAssignmentService->normalizeIdInput($input['role_ids'] ?? []) : []; $selectedDepartmentIds = $canManageAssignments ? $userAssignmentService->normalizeIdInput($input['department_ids'] ?? []) : []; $departmentOptionsByTenant = $departmentService->groupActiveByTenantIds($selectedTenantIds); $customFieldDefinitionsByTenant = $userCustomFieldValueService->buildDefinitionsByTenant($selectedTenantIds); $customFieldPostedValues = [ 'custom_field_values' => is_array($post['custom_field_values'] ?? null) ? $post['custom_field_values'] : [], 'custom_field_values_multi' => is_array($post['custom_field_values_multi'] ?? null) ? $post['custom_field_values_multi'] : [], ]; if ($canEditCustomFieldValues) { $customFieldValidationResult = $userCustomFieldValueService->validateForTenants( $selectedTenantIds, $post, true ); if (!($customFieldValidationResult['ok'] ?? false)) { $errorBag->merge($customFieldValidationResult['errors'] ?? []); foreach (array_keys($form) as $fieldKey) { if (!array_key_exists($fieldKey, $input)) { continue; } $fieldValue = $input[$fieldKey]; if (is_scalar($fieldValue)) { $form[$fieldKey] = trim((string) $fieldValue); } } $form['active'] = array_key_exists('active', $input) ? 1 : 0; } } $input['tenant_ids'] = $tenantIds; $input['role_ids'] = $selectedRoleIds; $input['department_ids'] = $selectedDepartmentIds; $result = ['ok' => false]; if (!$errorBag->hasAny()) { $result = $userAccountService->createFromAdmin($input, $currentUserId); $form = $result['form'] ?? $form; $errorBag->merge($result['errors'] ?? []); } if (($result['ok'] ?? false) && !$errorBag->hasAny()) { $createdUuid = (string) ($result['uuid'] ?? ''); if ($canEditCustomFieldValues && $createdUuid !== '') { $createdUser = $userAccountService->findByUuid($createdUuid); $createdUserId = (int) ($createdUser['id'] ?? 0); if ($createdUserId > 0) { $customFieldSyncResult = $userCustomFieldValueService->syncForUser( $createdUserId, $selectedTenantIds, $post, true ); if (!($customFieldSyncResult['ok'] ?? false)) { $syncErrors = $customFieldSyncResult['errors'] ?? []; if ($syncErrors) { Flash::error( implode(' | ', $syncErrors), requestPathWithReturnTarget("admin/users/edit/{$createdUuid}", $returnTarget), 'user_custom_field_sync_failed' ); } } } } $action = (string) ($post['action'] ?? 'create'); if ($action === 'create_close') { Flash::success('User created', $closeTarget, 'user_created'); Router::redirect($closeTarget); } else { $uuid = $createdUuid; if ($uuid !== '') { $target = requestPathWithReturnTarget("admin/users/edit/{$uuid}", $returnTarget); Flash::success('User created', $target, 'user_created'); Router::redirect($target); } else { Flash::success('User created', $closeTarget, 'user_created'); Router::redirect($closeTarget); } } } } if (!$departmentOptionsByTenant && $selectedTenantIds) { $departmentOptionsByTenant = $departmentService->groupActiveByTenantIds($selectedTenantIds); } if (!$customFieldDefinitionsByTenant && $selectedTenantIds) { $customFieldDefinitionsByTenant = $userCustomFieldValueService->buildDefinitionsByTenant($selectedTenantIds); } $validationSummaryErrors = $errorBag->toArray(); $errors = $errorBag->toFlatList(); Buffer::set('title', t('Create user')); $breadcrumbs = [ ['label' => t('Home'), 'path' => 'admin'], ['label' => t('Users'), 'path' => 'admin/users'], ['label' => t('Create user')], ];