createSettingGateway(); $settingCacheService = $settingsFactory->createSettingCacheService(); $tenants = directoryServicesFactory()->createTenantService()->list(); $roles = directoryServicesFactory()->createRoleService()->listActive(); $departments = directoryServicesFactory()->createDepartmentService()->list(); $sortByDescription = static function ($a, $b) { return strcmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? '')); }; usort($tenants, $sortByDescription); usort($roles, $sortByDescription); usort($departments, $sortByDescription); $values = [ 'default_tenant_id' => $settingGateway->getDefaultTenantId(), 'default_role_id' => $settingGateway->getDefaultRoleId(), 'default_department_id' => $settingGateway->getDefaultDepartmentId(), // Read raw values for form display so existing DB values are always visible. 'app_title' => $settingGateway->getValue(SettingService::APP_TITLE_KEY), 'app_locale' => $settingGateway->getValue(SettingService::APP_LOCALE_KEY), 'app_theme' => $settingGateway->getValue(SettingService::APP_THEME_KEY), 'app_theme_user' => $settingGateway->isUserThemeAllowed(), 'app_registration' => $settingGateway->isRegistrationEnabled(), 'app_primary_color' => $settingGateway->getValue(SettingService::APP_PRIMARY_COLOR_KEY), 'api_token_default_ttl_days' => $settingGateway->getApiTokenDefaultTtlDays(), 'api_token_max_ttl_days' => $settingGateway->getApiTokenMaxTtlDays(), 'user_inactivity_deactivate_days' => $settingGateway->getUserInactivityDeactivateDays(), 'user_inactivity_delete_days' => $settingGateway->getUserInactivityDeleteDays(), 'api_cors_allowed_origins' => $settingGateway->getApiCorsAllowedOriginsText(), 'microsoft_shared_client_id' => $settingGateway->getValue(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY), 'microsoft_authority' => $settingGateway->getMicrosoftAuthority(), 'smtp_host' => $settingGateway->getValue(SettingService::SMTP_HOST_KEY), 'smtp_port' => $settingGateway->getValue(SettingService::SMTP_PORT_KEY), 'smtp_user' => $settingGateway->getValue(SettingService::SMTP_USER_KEY), 'smtp_secure' => $settingGateway->getSmtpSecure(), 'smtp_from' => $settingGateway->getValue(SettingService::SMTP_FROM_KEY), 'smtp_from_name' => $settingGateway->getValue(SettingService::SMTP_FROM_NAME_KEY), ]; $activeLoginTokens = $rememberTokenRepository->countActive(); $activeApiTokens = $apiTokenRepository->countActive(); $settings = [ 'default_tenant' => $settingGateway->get(SettingService::DEFAULT_TENANT_KEY), 'default_role' => $settingGateway->get(SettingService::DEFAULT_ROLE_KEY), 'default_department' => $settingGateway->get(SettingService::DEFAULT_DEPARTMENT_KEY), 'app_title' => $settingGateway->get(SettingService::APP_TITLE_KEY), 'app_locale' => $settingGateway->get(SettingService::APP_LOCALE_KEY), 'app_theme' => $settingGateway->get(SettingService::APP_THEME_KEY), 'app_theme_user' => $settingGateway->get(SettingService::APP_THEME_USER_KEY), 'app_registration' => $settingGateway->get(SettingService::APP_REGISTRATION_KEY), 'app_primary_color' => $settingGateway->get(SettingService::APP_PRIMARY_COLOR_KEY), 'api_token_default_ttl_days' => $settingGateway->get(SettingService::API_TOKEN_DEFAULT_TTL_DAYS_KEY), 'api_token_max_ttl_days' => $settingGateway->get(SettingService::API_TOKEN_MAX_TTL_DAYS_KEY), 'user_inactivity_deactivate_days' => $settingGateway->get(SettingService::USER_INACTIVITY_DEACTIVATE_DAYS_KEY), 'user_inactivity_delete_days' => $settingGateway->get(SettingService::USER_INACTIVITY_DELETE_DAYS_KEY), 'api_cors_allowed_origins' => $settingGateway->get(SettingService::API_CORS_ALLOWED_ORIGINS_KEY), 'microsoft_shared_client_id' => $settingGateway->get(SettingService::MICROSOFT_SHARED_CLIENT_ID_KEY), 'microsoft_shared_client_secret_enc' => $settingGateway->get(SettingService::MICROSOFT_SHARED_CLIENT_SECRET_ENC_KEY), 'microsoft_authority' => $settingGateway->get(SettingService::MICROSOFT_AUTHORITY_KEY), 'smtp_host' => $settingGateway->get(SettingService::SMTP_HOST_KEY), 'smtp_port' => $settingGateway->get(SettingService::SMTP_PORT_KEY), 'smtp_user' => $settingGateway->get(SettingService::SMTP_USER_KEY), 'smtp_password' => $settingGateway->get(SettingService::SMTP_PASSWORD_KEY), 'smtp_secure' => $settingGateway->get(SettingService::SMTP_SECURE_KEY), 'smtp_from' => $settingGateway->get(SettingService::SMTP_FROM_KEY), 'smtp_from_name' => $settingGateway->get(SettingService::SMTP_FROM_NAME_KEY), ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($_POST['settings_submit'])) { Router::redirect('admin/settings'); } Guard::requirePermission(PermissionService::SETTINGS_UPDATE); $defaultTenantId = (int) ($_POST['default_tenant_id'] ?? 0); $defaultRoleId = (int) ($_POST['default_role_id'] ?? 0); $defaultDepartmentId = (int) ($_POST['default_department_id'] ?? 0); $appTitle = trim((string) ($_POST['app_title'] ?? '')); $appLocale = trim((string) ($_POST['app_locale'] ?? '')); $appTheme = trim((string) ($_POST['app_theme'] ?? '')); $appThemeUser = isset($_POST['app_theme_user']); $appRegistration = isset($_POST['app_registration']); $apiTokenDefaultTtlDays = (int) ($_POST['api_token_default_ttl_days'] ?? 0); $apiTokenMaxTtlDays = (int) ($_POST['api_token_max_ttl_days'] ?? 0); $userInactivityDeactivateDays = (int) ($_POST['user_inactivity_deactivate_days'] ?? 0); $userInactivityDeleteDays = (int) ($_POST['user_inactivity_delete_days'] ?? 0); $apiCorsAllowedOrigins = $_POST['api_cors_allowed_origins'] ?? ''; if (is_array($apiCorsAllowedOrigins)) { $apiCorsAllowedOrigins = ''; } $apiCorsAllowedOrigins = trim((string) $apiCorsAllowedOrigins); $rawPrimaryColor = $_POST['app_primary_color'] ?? ''; if (is_array($rawPrimaryColor)) { $rawPrimaryColor = ''; } $appPrimaryColor = trim((string) $rawPrimaryColor); if (in_array(strtolower($appPrimaryColor), ['null', 'undefined'], true)) { $appPrimaryColor = ''; } $smtpHost = trim((string) ($_POST['smtp_host'] ?? '')); $smtpPort = (int) ($_POST['smtp_port'] ?? 0); $smtpUser = trim((string) ($_POST['smtp_user'] ?? '')); $smtpPassword = (string) ($_POST['smtp_password'] ?? ''); $smtpSecure = trim((string) ($_POST['smtp_secure'] ?? '')); $smtpFrom = trim((string) ($_POST['smtp_from'] ?? '')); $smtpFromName = trim((string) ($_POST['smtp_from_name'] ?? '')); $microsoftSharedClientId = trim((string) ($_POST['microsoft_shared_client_id'] ?? '')); $microsoftSharedClientSecret = (string) ($_POST['microsoft_shared_client_secret'] ?? ''); $microsoftAuthority = trim((string) ($_POST['microsoft_authority'] ?? '')); $settingGateway->setDefaultTenantId($defaultTenantId > 0 ? $defaultTenantId : null); $settingGateway->setDefaultRoleId($defaultRoleId > 0 ? $defaultRoleId : null); $settingGateway->setDefaultDepartmentId($defaultDepartmentId > 0 ? $defaultDepartmentId : null); $settingGateway->setAppTitle($appTitle); $settingGateway->setAppLocale($appLocale); $settingGateway->setAppTheme($appTheme); $settingGateway->setUserThemeAllowed($appThemeUser); $settingGateway->setRegistrationEnabled($appRegistration); $apiTokenMaxTtlOk = $settingGateway->setApiTokenMaxTtlDays($apiTokenMaxTtlDays > 0 ? $apiTokenMaxTtlDays : null); if (!$apiTokenMaxTtlOk) { Flash::error('API token max lifetime is invalid', 'admin/settings', 'api_token_max_ttl_invalid'); } $apiTokenTtlOk = $settingGateway->setApiTokenDefaultTtlDays($apiTokenDefaultTtlDays > 0 ? $apiTokenDefaultTtlDays : null); if (!$apiTokenTtlOk) { Flash::error('API token default lifetime is invalid', 'admin/settings', 'api_token_default_ttl_invalid'); } $userDeactivateOk = $settingGateway->setUserInactivityDeactivateDays($userInactivityDeactivateDays); if (!$userDeactivateOk) { Flash::error( 'User inactivity deactivation period is invalid', 'admin/settings', 'user_inactivity_deactivate_days_invalid' ); } if ($userInactivityDeactivateDays > 0) { $userDeleteOk = $settingGateway->setUserInactivityDeleteDays($userInactivityDeleteDays); if (!$userDeleteOk) { Flash::error( 'User inactivity deletion period is invalid', 'admin/settings', 'user_inactivity_delete_days_invalid' ); } } else { if ($userInactivityDeleteDays > 0) { Flash::error( 'Auto-delete is ignored while auto-deactivate is disabled', 'admin/settings', 'user_inactivity_delete_requires_deactivate' ); } $settingGateway->setUserInactivityDeleteDays(0); } $apiCorsOriginsOk = $settingGateway->setApiCorsAllowedOrigins($apiCorsAllowedOrigins); if (!$apiCorsOriginsOk) { Flash::error('CORS allowed origins are invalid', 'admin/settings', 'api_cors_allowed_origins_invalid'); } $primaryOk = $settingGateway->setAppPrimaryColor($appPrimaryColor); if (!$primaryOk) { $appPrimaryColor = ''; Flash::error('Primary color is invalid', 'admin/settings', 'app_primary_invalid'); } $settingGateway->setSmtpHost($smtpHost); $settingGateway->setSmtpPort($smtpPort > 0 ? $smtpPort : null); $settingGateway->setSmtpUser($smtpUser); if (trim($smtpPassword) !== '') { $settingGateway->setSmtpPassword($smtpPassword); } $settingGateway->setSmtpSecure($smtpSecure); $settingGateway->setSmtpFrom($smtpFrom); $settingGateway->setSmtpFromName($smtpFromName); $msClientIdOk = $settingGateway->setMicrosoftSharedClientId($microsoftSharedClientId); if (!$msClientIdOk) { Flash::error('Microsoft client ID is invalid', 'admin/settings', 'microsoft_client_id_invalid'); } $msAuthorityOk = $settingGateway->setMicrosoftAuthority($microsoftAuthority); if (!$msAuthorityOk) { Flash::error('Microsoft authority is invalid', 'admin/settings', 'microsoft_authority_invalid'); } if (trim($microsoftSharedClientSecret) !== '') { try { $settingGateway->setMicrosoftSharedClientSecret($microsoftSharedClientSecret); } catch (\Throwable $exception) { Flash::error('Microsoft client secret could not be encrypted', 'admin/settings', 'microsoft_client_secret_invalid'); } } $settingCacheService->update([ 'app_title' => $appTitle !== '' ? $appTitle : null, 'app_locale' => $appLocale !== '' ? $appLocale : null, 'app_theme' => $appTheme !== '' ? $appTheme : null, 'app_theme_user' => $appThemeUser ? '1' : '0', 'app_registration' => $appRegistration ? '1' : '0', 'app_primary_color' => $appPrimaryColor !== '' ? $appPrimaryColor : null, 'api_token_default_ttl_days' => (string) $settingGateway->getApiTokenDefaultTtlDays(), 'api_token_max_ttl_days' => (string) $settingGateway->getApiTokenMaxTtlDays(), 'api_cors_allowed_origins' => $settingGateway->getValue(SettingService::API_CORS_ALLOWED_ORIGINS_KEY), ]); Flash::success('Settings updated', 'admin/settings', 'settings_updated'); Router::redirect('admin/settings'); } Buffer::set('title', t('Settings'));