diff --git a/lib/Controller/ContactpersonenController.php b/lib/Controller/ContactpersonenController.php index 91ce0220..31f8dd17 100644 --- a/lib/Controller/ContactpersonenController.php +++ b/lib/Controller/ContactpersonenController.php @@ -264,7 +264,6 @@ function ($group) { * * @return JSONResponse Result of user creation. * - * @NoAdminRequired * @NoCSRFRequired * * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -274,21 +273,30 @@ function ($group) { */ public function convertToUser(string $contactpersoonId): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + // Only admins and org-admins may create user accounts. + $isAdmin = $this->groupManager->isAdmin($currentUser->getUID()); + $isOrgAdmin = $this->groupManager->isInGroup($currentUser->getUID(), 'gebruik-beheerder') + || $this->groupManager->isInGroup($currentUser->getUID(), 'aanbod-beheerder'); + if ($isAdmin === false && $isOrgAdmin === false) { + return new JSONResponse(['message' => 'Insufficient permissions'], Http::STATUS_FORBIDDEN); + } + try { // Get object service. $objectService = \OC::$server->get('OCA\OpenRegister\Service\ObjectService'); - // Find the contactpersoon object. + // Find the contactpersoon object — bind to current tenant. $contactpersoonObject = $objectService->find( id: $contactpersoonId, register: 'voorzieningen', schema: 'contactpersoon', - _rbac: false, - _multitenancy: false + _rbac: true, + _multitenancy: true ); if ($contactpersoonObject === null) { @@ -493,8 +501,12 @@ public function convertToUser(string $contactpersoonId): JSONResponse /** * Change user password. * - * @param string $username The username. - * @param string $newPassword The new password. + * Admins may change any user's password. Regular users may only change their + * own password, and must supply the current password for confirmation. + * + * @param string $username The username. + * @param string $newPassword The new password. + * @param string $currentPassword The current password (required for self-service resets). * * @return JSONResponse Result of password change. * @@ -502,12 +514,46 @@ public function convertToUser(string $contactpersoonId): JSONResponse * @NoCSRFRequired * @spec openspec/changes/retrofit-2026-05-26-contactpersonen-api/tasks.md#task-3 */ - public function changePassword(string $username, string $newPassword): JSONResponse + public function changePassword(string $username, string $newPassword, string $currentPassword=''): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + $isAdmin = $this->groupManager->isAdmin($currentUser->getUID()); + $isSelfReset = $currentUser->getUID() === $username; + + // Non-admins may only change their own password. + if ($isAdmin === false && $isSelfReset === false) { + return new JSONResponse(['message' => 'Insufficient permissions'], Http::STATUS_FORBIDDEN); + } + + // Self-service resets require current-password confirmation. + if ($isSelfReset === true && $isAdmin === false) { + if (empty($currentPassword) === true) { + return new JSONResponse( + [ + 'success' => false, + 'message' => 'Current password is required for self-service password reset', + ], + 400 + ); + } + + // Verify current password by checking the user's backend. + $authUser = $this->userManager->checkPassword($username, $currentPassword); + if ($authUser === false) { + return new JSONResponse( + [ + 'success' => false, + 'message' => 'Current password is incorrect', + ], + 403 + ); + } + }//end if + try { $user = $this->userManager->get($username); @@ -1011,20 +1057,29 @@ public function getAvailableGroups(): JSONResponse /** * Disable a user account. * + * Requires admin or organisation-admin (gebruik-beheerder / aanbod-beheerder) role. + * * @param string $contactpersoonId The contactpersoon ID. * * @return JSONResponse Result of the disable operation. * - * @NoAdminRequired * @NoCSRFRequired - * @spec openspec/changes/retrofit-2026-05-26-contactpersonen-api/tasks.md#task-3 + * @spec openspec/changes/retrofit-2026-05-26-contactpersonen-api/tasks.md#task-3 */ public function disableUser(string $contactpersoonId): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + $isAdmin = $this->groupManager->isAdmin($currentUser->getUID()); + $isOrgAdmin = $this->groupManager->isInGroup($currentUser->getUID(), 'gebruik-beheerder') + || $this->groupManager->isInGroup($currentUser->getUID(), 'aanbod-beheerder'); + if ($isAdmin === false && $isOrgAdmin === false) { + return new JSONResponse(['message' => 'Insufficient permissions'], Http::STATUS_FORBIDDEN); + } + try { // Delegate to service. $this->contactSvc->disableUserForContactpersoon($contactpersoonId); @@ -1063,20 +1118,29 @@ public function disableUser(string $contactpersoonId): JSONResponse /** * Enable a user account. * + * Requires admin or organisation-admin (gebruik-beheerder / aanbod-beheerder) role. + * * @param string $contactpersoonId The contactpersoon ID. * * @return JSONResponse Result of the enable operation. * - * @NoAdminRequired * @NoCSRFRequired - * @spec openspec/changes/retrofit-2026-05-26-contactpersonen-api/tasks.md#task-3 + * @spec openspec/changes/retrofit-2026-05-26-contactpersonen-api/tasks.md#task-3 */ public function enableUser(string $contactpersoonId): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + $isAdmin = $this->groupManager->isAdmin($currentUser->getUID()); + $isOrgAdmin = $this->groupManager->isInGroup($currentUser->getUID(), 'gebruik-beheerder') + || $this->groupManager->isInGroup($currentUser->getUID(), 'aanbod-beheerder'); + if ($isAdmin === false && $isOrgAdmin === false) { + return new JSONResponse(['message' => 'Insufficient permissions'], Http::STATUS_FORBIDDEN); + } + try { // Delegate to service. $this->contactSvc->enableUserForContactpersoon($contactpersoonId); diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 00687ba9..57fdab67 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -1344,9 +1344,13 @@ public function render(): string /** * Import ArchiMate file. * + * Only accepts multipart file uploads — the `file_path` JSON body parameter is + * rejected to prevent local filesystem read (path traversal / SSRF). + * The `ini_set('memory_limit')` call has been removed; configure PHP memory via + * php.ini / pool config instead. + * * @return JSONResponse Result of the import operation with progress tracking. * - * @NoAdminRequired * @NoCSRFRequired * * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -1356,20 +1360,16 @@ public function render(): string */ public function importArchiMate(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { - // Increase memory limit for large imports. - ini_set('memory_limit', '4096M'); - $this->logger->info( - 'Memory limit increased for import', - [ - 'old_limit' => ini_get('memory_limit'), - 'new_limit' => '4096M', - ] - ); // Get JSON data from request body. $rawInput = file_get_contents('php://input'); $data = json_decode($rawInput, true); @@ -1377,13 +1377,21 @@ public function importArchiMate(): JSONResponse $contentType = $this->request->getHeader('Content-Type'); $isMultipart = strpos(haystack: $contentType, needle: 'multipart/form-data') !== false; - // Enhanced debug logging. + // Reject file_path from JSON body — only uploaded files are accepted. + if ($data !== null && isset($data['file_path']) === true) { + return new JSONResponse( + [ + 'success' => false, + 'message' => 'The file_path parameter is not accepted. Please upload a file via multipart/form-data.', + 'error' => 'FILE_PATH_NOT_ALLOWED', + ], + 400 + ); + } + $this->logger->info( 'ArchiMate import request received', [ - 'rawInput' => $rawInput, - 'decodedData' => $data, - 'jsonError' => json_last_error_msg(), 'contentType' => $contentType, 'isMultipart' => $isMultipart, 'requestMethod' => $this->request->getMethod(), @@ -1407,8 +1415,6 @@ public function importArchiMate(): JSONResponse $this->logger->info( 'File upload detection detailed', [ - 'uploadedFiles' => $uploadedFiles, - 'filesArray' => $filesArray, 'requestMethod' => $this->request->getMethod(), 'contentType' => $contentType, 'hasUploadedFiles' => $hasUploadedFiles, @@ -1438,42 +1444,15 @@ public function importArchiMate(): JSONResponse ]; $this->logger->info('File upload detected.', ['options' => $options]); - } else if ($data !== null && isset($data['file_path']) === true) { - // Handle file path from JSON payload. - $fileSize = 0; - if (file_exists($data['file_path']) === true) { - } - - $options = [ - 'updateExisting' => $data['updateExisting'] ?? true, - 'deleteOrphaned' => $data['deleteOrphaned'] ?? false, - 'preserveIds' => $data['preserveIds'] ?? true, - 'processingMode' => $data['processingMode'] ?? 'speed', - 'filePath' => $data['file_path'], - 'fileName' => $data['fileName'] ?? basename($data['file_path']), - 'fileSize' => $data['fileSize'] ?? $fileSize, - 'mimeType' => $data['mimeType'] ?? 'text/xml', - ]; - - $this->logger->info('JSON payload detected.', ['options' => $options]); }//end if if (isset($options) === false) { $this->logger->error( - 'No file uploaded or file path provided — DETAILED DEBUG', + 'No ArchiMate file uploaded', [ - 'uploadedFiles' => $uploadedFiles, - 'filesArray' => $filesArray, - 'data' => $data, - 'rawInput' => $rawInput, - 'contentType' => $contentType, - 'isMultipart' => $isMultipart, - 'requestMethod' => $this->request->getMethod(), - '_FILES_DEBUG' => $_FILES, - '_POST_DEBUG' => $_POST, - 'requestParams' => $this->request->getParams(), - 'userAgent' => $this->request->getHeader('User-Agent'), - 'xRequestedWith' => $this->request->getHeader('X-Requested-With'), + 'contentType' => $contentType, + 'isMultipart' => $isMultipart, + 'requestMethod' => $this->request->getMethod(), ] ); @@ -1928,21 +1907,38 @@ public function testEmailConnection(): JSONResponse /** * Get email settings * - * @NoAdminRequired + * Secret fields (passwords / API keys) are redacted in the response; only + * a boolean presence indicator is returned for each secret. + * * @NoCSRFRequired * - * @return JSONResponse Current email settings + * @return JSONResponse Current email settings (secrets redacted) * @spec openspec/changes/retrofit-2026-05-26-settings-admin-controller/tasks.md#task-4 */ public function getEmailSettings(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { $emailSettings = $this->settingsService->getEmailSettings(); + // Redact secret values — return only a masked placeholder when set. + $secretFields = ['smtpPassword', 'sendgridApiKey', 'mailgunApiKey', 'postmarkApiKey', 'sesSecretKey', 'mailjetSecretKey']; + foreach ($secretFields as $field) { + if (empty($emailSettings[$field]) === false) { + $emailSettings[$field] = '••••••••'; + } else { + $emailSettings[$field] = ''; + }//end if + } + return new JSONResponse( [ 'success' => true, @@ -1969,7 +1965,6 @@ public function getEmailSettings(): JSONResponse /** * Update email settings * - * @NoAdminRequired * @NoCSRFRequired * * @return JSONResponse Update result @@ -1977,10 +1972,15 @@ public function getEmailSettings(): JSONResponse */ public function updateEmailSettings(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { $data = $this->request->getParams(); $emailSettings = $data['emailSettings'] ?? $data; @@ -2302,7 +2302,6 @@ public function getGenericUserGroups(): JSONResponse /** * Set generic user groups * - * @NoAdminRequired * @NoCSRFRequired * * @return JSONResponse Update result @@ -2310,10 +2309,15 @@ public function getGenericUserGroups(): JSONResponse */ public function setGenericUserGroups(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { $data = $this->request->getParams(); $groups = $data['groups'] ?? []; @@ -2390,7 +2394,6 @@ public function getOrganizationAdminGroups(): JSONResponse /** * Set organization admin groups * - * @NoAdminRequired * @NoCSRFRequired * * @return JSONResponse Update result @@ -2398,10 +2401,15 @@ public function getOrganizationAdminGroups(): JSONResponse */ public function setOrganizationAdminGroups(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { $data = $this->request->getParams(); $groups = $data['groups'] ?? []; @@ -2478,7 +2486,6 @@ public function getSuperUserGroups(): JSONResponse /** * Set super user groups * - * @NoAdminRequired * @NoCSRFRequired * * @return JSONResponse Update result @@ -2486,10 +2493,15 @@ public function getSuperUserGroups(): JSONResponse */ public function setSuperUserGroups(): JSONResponse { - if ($this->userSession->getUser() === null) { + $currentUser = $this->userSession->getUser(); + if ($currentUser === null) { return new JSONResponse(['message' => 'Not authenticated'], Http::STATUS_UNAUTHORIZED); } + if ($this->groupManager->isAdmin($currentUser->getUID()) === false) { + return new JSONResponse(['message' => 'Admin privileges required'], Http::STATUS_FORBIDDEN); + } + try { $data = $this->request->getParams(); $groups = $data['groups'] ?? []; diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php index a17d07ab..2b2c2f6e 100644 --- a/lib/Service/SettingsService.php +++ b/lib/Service/SettingsService.php @@ -1916,11 +1916,6 @@ public function getEmailSettings(): array 'email_user_creation_enabled', 'true' ) === 'true', - 'userPasswordEnabled' => $this->config->getValueString( - $app, - 'email_user_password_enabled', - 'true' - ) === 'true', 'userOrganisationEnabled' => $this->config->getValueString( $app, 'email_user_organisation_enabled', @@ -2021,7 +2016,6 @@ public function getEmailSettings(): array 'organization_registration' => $this->getEmailTemplate(templateName: 'organization_registration'), 'organization_activation' => $this->getEmailTemplate(templateName: 'organization_activation'), 'user_creation' => $this->getEmailTemplate(templateName: 'user_creation'), - 'user_password' => $this->getEmailTemplate(templateName: 'user_password'), ], ]; @@ -2060,7 +2054,6 @@ public function updateEmailSettings(array $emailSettings): array 'organizationRegistrationEnabled' => 'email_org_registration_enabled', 'organizationActivationEnabled' => 'email_org_activation_enabled', 'userCreationEnabled' => 'email_user_creation_enabled', - 'userPasswordEnabled' => 'email_user_password_enabled', 'userOrganisationEnabled' => 'email_user_organisation_enabled', // Symfony Mailer transport configuration. @@ -2221,20 +2214,6 @@ public function getDefaultEmailTemplate(string $templateName): string

U kunt nu inloggen op het platform en gebruik maken van alle functionaliteiten.

Heeft u vragen over uw account? Neem dan contact met ons op.

-

Met vriendelijke groet,
Het Software Catalogus Team

- ', - 'user_password' => ' -

Uw wachtwoord voor de Software Catalogus

-

Beste {{ user.name }},

-

Uw wachtwoord voor de Software Catalogus is aangepast.

-

Uw logingegevens:

- -

U kunt nu inloggen met uw nieuwe wachtwoord.

-

We raden u aan om uw wachtwoord te wijzigen na het eerste inloggen.

Met vriendelijke groet,
Het Software Catalogus Team

', ]; @@ -2271,13 +2250,6 @@ public function getEmailTemplateVariables(string $templateName): array 'user.username' => 'Username', 'user.organization.name' => 'Organization name (if applicable)', ], - 'user_password' => [ - 'user.name' => 'User display name', - 'user.email' => 'User email address', - 'user.username' => 'Username', - 'user.password' => 'Auto-generated password', - 'user.organization.name' => 'Organization name (if applicable)', - ], ]; return $variables[$templateName] ?? []; @@ -3926,7 +3898,6 @@ public function getConsolidatedConfiguration(): array 'organization_registration' => $this->getEmailTemplate(templateName: 'organization_registration'), 'organization_activation' => $this->getEmailTemplate(templateName: 'organization_activation'), 'user_creation' => $this->getEmailTemplate(templateName: 'user_creation'), - 'user_password' => $this->getEmailTemplate(templateName: 'user_password'), ]; // Get Voorzieningen and AMEF configs (without object counts for performance). @@ -4888,11 +4859,6 @@ public function compactToJsonConfiguration(): array 'email_user_creation_enabled', 'true' ) === 'true', - 'user_password_enabled' => $this->config->getValueString( - $an, - 'email_user_password_enabled', - 'true' - ) === 'true', 'test_receiver_override' => $this->config->getValueString( $an, 'test_receiver_override', @@ -5015,7 +4981,6 @@ public function cleanupOldConfiguration(): array 'email_org_registration_enabled', 'email_org_activation_enabled', 'email_user_creation_enabled', - 'email_user_password_enabled', 'test_receiver_override', ]; @@ -5218,7 +5183,6 @@ public function getAllEmailTemplates(): array 'organization_registration', 'organization_activation', 'user_creation', - 'user_password', 'user_organisation', ]; $templates = []; diff --git a/lib/Service/SymfonyEmailService.php b/lib/Service/SymfonyEmailService.php index 223baafa..2227a200 100644 --- a/lib/Service/SymfonyEmailService.php +++ b/lib/Service/SymfonyEmailService.php @@ -151,35 +151,6 @@ class SymfonyEmailService '; - /** - * Email template for user password emails - * - * @var string User password email template - */ - private const USER_PASSWORD_TEMPLATE = ' - - - Inloggegevens - Software Catalogus - - - -

Uw inloggegevens voor de Software Catalogus

-

Beste {{ user.name }},

-

Hierbij ontvangt u uw inloggegevens voor de Software Catalogus.

-

Login gegevens:

- -

Belangrijk: We raden u aan om dit tijdelijke wachtwoord te wijzigen na uw eerste inlog.

-

U kunt inloggen op het platform en direct aan de slag met het beheren - van software voor {{ organization.name }}.

-

Heeft u vragen? Neem dan contact met ons op via info@conduction.nl

-

Met vriendelijke groet,
Het Software Catalogus Team

- - - '; - /** * Email template for contact welcome emails (backward compatibility) * @@ -928,123 +899,6 @@ public function sendUserUpdateEmail(array $user, array $organization=[]): bool }//end try }//end sendUserUpdateEmail() - /** - * Sends a user password email. - * - * @param array $user The user data. - * @param string $password The generated password. - * @param array $organization The organization data (optional). - * - * @return bool True if email was sent successfully, false otherwise. - * - * @throws \Exception If email sending fails. - * @spec openspec/changes/retrofit-2026-05-26-email-delivery/tasks.md#task-1 - */ - public function sendUserPasswordEmail(array $user, string $password, array $organization=[]): bool - { - // Check if email system is fully configured. - $configStatus = $this->isEmailSystemConfigured(); - if ($configStatus['configured'] === false) { - $this->logger->info( - 'UserPasswordEmail: Email system not configured, skipping', - [ - 'reason' => $configStatus['reason'], - 'hasCredentials' => $configStatus['hasCredentials'], - 'hasTemplates' => $configStatus['hasTemplates'], - 'userEmail' => $user['email'] ?? 'Unknown', - ] - ); - return false; - } - - $emailSettings = $this->settingsService->getEmailSettings(); - - // Check if user password emails are enabled. - if ($emailSettings['userPasswordEnabled'] === false) { - $this->logger->info( - 'UserPasswordEmail: User password emails disabled', - [ - 'userEmail' => $user['email'] ?? 'Unknown', - ] - ); - return false; - } - - $userEmail = $user['email'] ?? ''; - $userName = $user['naam'] ?? $user['name'] ?? ($user['voornaam'] ?? '').' '.($user['achternaam'] ?? ''); - $userName = trim($userName); - - if (empty($userEmail) === true) { - $this->logger->warning( - 'UserPasswordEmail: Cannot send without email address', - [ - 'user' => $user, - 'userName' => $userName, - ] - ); - return false; - } - - $this->logger->info( - 'UserPasswordEmail: Sending user password email', - [ - 'userName' => $userName, - 'userEmail' => $userEmail, - 'organizationName' => $organization['naam'] ?? $organization['name'] ?? 'Software Catalogus', - 'transportType' => $configStatus['transportType'], - ] - ); - - // Prepare template data. - $displayName = 'Gebruiker'; - if (empty($userName) === false) { - } - - $templateData = [ - 'user' => [ - 'name' => $displayName, - 'email' => $userEmail, - 'password' => $password, - 'functie' => ($user['functie'] ?? ''), - ], - 'organization' => [ - 'name' => ($organization['naam'] ?? $organization['name'] ?? 'Software Catalogus'), - ], - ]; - - try { - $success = $this->sendTemplatedEmail( - recipientEmail: $userEmail, - recipientName: $displayName, - subject: 'Software Catalogus - Inloggegevens', - templateName: 'user_password', - templateData: $templateData - ); - - if ($success === true) { - $this->logger->info( - 'UserPasswordEmail: Successfully sent user password email', - [ - 'userName' => $userName, - 'userEmail' => $userEmail, - ] - ); - } - - return $success; - } catch (\Exception $e) { - $this->logger->error( - 'UserPasswordEmail: Failed to send user password email', - [ - 'userName' => $userName, - 'userEmail' => $userEmail, - 'error' => $e->getMessage(), - ] - ); - return false; - }//end try - }//end sendUserPasswordEmail() - /** * Sends a templated email using the configured templates. * @@ -1112,7 +966,6 @@ private function getDefaultTemplate(string $templateName): string 'organization_registration' => self::ORGANIZATION_WELCOME_TEMPLATE, 'organization_activation' => self::ORGANIZATION_ACTIVATION_TEMPLATE, 'user_creation' => self::GEBRUIKER_WELCOME_TEMPLATE, - 'user_password' => self::USER_PASSWORD_TEMPLATE, 'user_organisation' => self::CONTACT_ADDED_TEMPLATE, default => self::ORGANIZATION_WELCOME_TEMPLATE, }; @@ -1529,18 +1382,6 @@ public function setUserCreationEnabled(bool $enabled): void $this->settingsService->updateEmailSettings(['userCreationEnabled' => $enabled]); }//end setUserCreationEnabled() - /** - * Sets whether user password emails are enabled. - * - * @param bool $enabled True to enable user password emails, false to disable. - * - * @return void - */ - public function setUserPasswordEnabled(bool $enabled): void - { - $this->settingsService->updateEmailSettings(['userPasswordEnabled' => $enabled]); - }//end setUserPasswordEnabled() - /** * Checks if the email system is fully configured with credentials and templates. * @@ -1631,7 +1472,7 @@ private function hasValidTransportCredentials(array $emailSettings): bool private function hasValidTemplates(array $emailSettings): bool { $templates = ($emailSettings['templates'] ?? []); - $requiredTemplates = ['organization_registration', 'organization_activation', 'user_creation', 'user_password']; + $requiredTemplates = ['organization_registration', 'organization_activation', 'user_creation']; foreach ($requiredTemplates as $templateName) { $template = ($templates[$templateName] ?? '');