From ea8c3b1abf1550f03432b9779e0d3ec002846a47 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 11:40:53 +0100 Subject: [PATCH 01/16] feat: Twig filter for adding UTM tags on links --- app/AppKernel.php | 1 + app/config/config.yml | 5 ++ composer.json | 5 +- .../Core/Twig/Extensions/UtmExtension.php | 48 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/Common/Core/Twig/Extensions/UtmExtension.php diff --git a/app/AppKernel.php b/app/AppKernel.php index 9d13a1040f..0ad939cedb 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -32,6 +32,7 @@ public function registerBundles(): array new \MailMotor\Bundle\MailChimpBundle\MailMotorMailChimpBundle(), new \MailMotor\Bundle\CampaignMonitorBundle\MailMotorCampaignMonitorBundle(), new \Liip\ImagineBundle\LiipImagineBundle(), + new \Twig\Extra\TwigExtraBundle\TwigExtraBundle(), ]; if ($this->getEnvironment() === 'prod') { diff --git a/app/config/config.yml b/app/config/config.yml index 71fc22a4b4..6f547d59e7 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -265,6 +265,11 @@ services: tags: - { name: twig.extension } + Common\Core\Twig\Extensions\UtmExtension: + public: false + tags: + - { name: twig.extension } + ForkCMS\Google\TagManager\DataLayer: public: true diff --git a/composer.json b/composer.json index 27a3e54b78..ffa4d4cf2e 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,10 @@ "sentry/sentry-symfony": "^5.8", "symfony/dom-crawler": "^5.4", "symfony/messenger": "^5.4", - "symfony/string": "^5.4" + "symfony/string": "^5.4", + "twig/extra-bundle": "^3.23", + "twig/cssinliner-extra": "^3.23", + "twig/string-extra": "^3.23" }, "require-dev": { "jdorn/sql-formatter": "1.2.17", diff --git a/src/Common/Core/Twig/Extensions/UtmExtension.php b/src/Common/Core/Twig/Extensions/UtmExtension.php new file mode 100644 index 0000000000..61e1a248b8 --- /dev/null +++ b/src/Common/Core/Twig/Extensions/UtmExtension.php @@ -0,0 +1,48 @@ + ['html']]), + ]; + } + + public function injectUtmTags( + string $html, + string $source, + string $medium, + string $campaign, + ): string { + if ($html === '') { + return $html; + } + + + return preg_replace_callback( + '/href="(https?:[^"]+)"/i', + function (array $matches) use ($campaign, $source, $medium): string { + $href = $matches[1]; + + $utmParams = http_build_query([ + 'utm_source' => $source, + 'utm_medium' => $medium, + 'utm_campaign' => $campaign, + ]); + + $separator = str_contains($href, '?') ? '&' : '?'; + + return 'href="' . $href . $separator . $utmParams . '"'; + }, + $html + ); + } +} From 397a6ccf22883fc70ba2b9a261926abf0a44342a Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 11:59:06 +0100 Subject: [PATCH 02/16] feat: install symfony/mailer --- app/config/config.yml | 2 ++ app/config/parameters.yml.dist | 2 ++ app/config/parameters.yml.test | 2 ++ composer.json | 1 + 4 files changed, 7 insertions(+) diff --git a/app/config/config.yml b/app/config/config.yml index 6f547d59e7..ad8cf142a1 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -26,6 +26,8 @@ framework: adapter: cache.app public: true default_lifetime: 3600 + mailer: + dsn: '%mailer.dsn%' messenger: transports: async: diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 513820f57d..7d017352f9 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -23,4 +23,6 @@ parameters: action.group_tag: '' action.rights_level: + mailer.dsn: 'smtp://127.0.0.1:1025' + sentry.dsn: '' diff --git a/app/config/parameters.yml.test b/app/config/parameters.yml.test index 79ceb24042..44576eedaf 100644 --- a/app/config/parameters.yml.test +++ b/app/config/parameters.yml.test @@ -22,3 +22,5 @@ parameters: action.group_tag: '\@actiongroup' action.rights_level: 7 + + mailer.dsn: 'null://null' diff --git a/composer.json b/composer.json index ffa4d4cf2e..f6564c43f6 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,7 @@ "symfony/dom-crawler": "^5.4", "symfony/messenger": "^5.4", "symfony/string": "^5.4", + "symfony/mailer": "^5.4", "twig/extra-bundle": "^3.23", "twig/cssinliner-extra": "^3.23", "twig/string-extra": "^3.23" From f52e91c285ec010b0ce5fd3e4e39282c3b037100 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 12:00:30 +0100 Subject: [PATCH 03/16] feat: introduce an factory to create a preconfigured TemplatedEmail instance --- app/config/config.yml | 28 +++++----------- src/Common/Mailer/Configurator.php | 52 ------------------------------ src/Common/Mailer/EmailFactory.php | 41 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 72 deletions(-) delete mode 100644 src/Common/Mailer/Configurator.php create mode 100644 src/Common/Mailer/EmailFactory.php diff --git a/app/config/config.yml b/app/config/config.yml index ad8cf142a1..1c0f06b1c5 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -65,17 +65,6 @@ monolog: path: "%site.path_www%/var/logs/%kernel.environment%/error.log" level: error max_files: 10 - # swift: - # type: swift_mailer - # from_email: %fork.debug_email% - # to_email: %fork.debug_email% - # subject: %site.default_title% %fork.debug_message% - # level: error - # formatter: monolog.formatter.html - # content_type: text/html - -swiftmailer: - transport: "sendmail" liip_imagine: resolvers: @@ -169,15 +158,6 @@ services: # and caused some queries to break. - [ execute, [ 'SET sql_mode = REPLACE(@@SESSION.sql_mode, "ONLY_FULL_GROUP_BY", "")'] ] - [ setDebug, [ "%kernel.debug%" ]] - mailer_configurator: - class: Common\Mailer\Configurator - tags: - - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest } - - { name: kernel.event_listener, event: console.command, method: onConsoleCommand } - arguments: - - "@fork.settings" - - "@service_container" - cache.filesystem.adapter: class: League\Flysystem\Adapter\Local arguments: @@ -303,3 +283,11 @@ services: alias: 'Symfony\Component\Messenger\MessageBusInterface' public: true + Symfony\Component\Mailer\MailerInterface: + alias: mailer.mailer + public: true + + Common\Mailer\EmailFactory: + public: true + arguments: + - "@fork.settings" diff --git a/src/Common/Mailer/Configurator.php b/src/Common/Mailer/Configurator.php deleted file mode 100644 index e9e02854bd..0000000000 --- a/src/Common/Mailer/Configurator.php +++ /dev/null @@ -1,52 +0,0 @@ -configureMail(); - } - - public function onConsoleCommand(ConsoleCommandEvent $event): void - { - $this->configureMail(); - } - - private function configureMail(): void - { - try { - $transport = TransportFactory::create( - (string) $this->modulesSettings->get('Core', 'mailer_type', 'sendmail'), - $this->modulesSettings->get('Core', 'smtp_server'), - (int) $this->modulesSettings->get('Core', 'smtp_port', 25), - $this->modulesSettings->get('Core', 'smtp_username'), - $this->modulesSettings->get('Core', 'smtp_password'), - $this->modulesSettings->get('Core', 'smtp_secure_layer') - ); - $mailer = $this->container->get('mailer'); - if ($mailer !== null) { - $this->container->get('mailer')->__construct($transport); - } - $this->container->set( - 'swiftmailer.transport', - $transport - ); - } catch (PDOException) { - // we'll just use the mail transport thats pre-configured - } - } -} diff --git a/src/Common/Mailer/EmailFactory.php b/src/Common/Mailer/EmailFactory.php new file mode 100644 index 0000000000..64ef7190e1 --- /dev/null +++ b/src/Common/Mailer/EmailFactory.php @@ -0,0 +1,41 @@ +createDefaultEmailInstance(); + } + + private function createDefaultEmailInstance(): TemplatedEmail + { + $email = new TemplatedEmail(); + + // set some default based on the settings + $defaultFrom = $this->modulesSettings->get('Core', 'mailer_from'); + if (!empty($defaultFrom)) { + $email->from(new Address($defaultFrom['email'], $defaultFrom['name'] ?? null)); + } + $defaultTo = $this->modulesSettings->get('Core', 'mailer_to'); + if (!empty($defaultTo)) { + $email->to(new Address($defaultTo['email'], $defaultTo['name'] ?? null)); + } + $defaultReplyTo = $this->modulesSettings->get('Core', 'mailer_reply_to'); + if (!empty($defaultReplyTo)) { + $email->replyTo(new Address($defaultReplyTo['email'], $defaultReplyTo['name'] ?? null)); + } + + return $email; + } +} From da4949c7e32e50722df542dca70cc22adfccc66c Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 12:53:37 +0100 Subject: [PATCH 04/16] feat: don't allow to configure mailer in the CMS --- .../Modules/Settings/Actions/Email.php | 71 ------- .../Settings/Ajax/TestEmailConnection.php | 85 -------- .../Settings/Installer/Data/locale.xml | 65 ------ .../Modules/Settings/Installer/Installer.php | 1 - src/Backend/Modules/Settings/Js/Settings.js | 46 ----- .../Settings/Layout/Templates/Email.html.twig | 193 ++++++------------ tests/data/test_db.sql | 1 - 7 files changed, 67 insertions(+), 395 deletions(-) delete mode 100644 src/Backend/Modules/Settings/Ajax/TestEmailConnection.php diff --git a/src/Backend/Modules/Settings/Actions/Email.php b/src/Backend/Modules/Settings/Actions/Email.php index 8d94285220..59a588d3ab 100644 --- a/src/Backend/Modules/Settings/Actions/Email.php +++ b/src/Backend/Modules/Settings/Actions/Email.php @@ -13,13 +13,6 @@ */ class Email extends BackendBaseActionIndex { - /** - * Is the user a god user? - * - * @var bool - */ - protected $isGod = false; - /** * The form instance * @@ -38,8 +31,6 @@ public function execute(): void private function loadForm(): void { - $this->isGod = BackendAuthentication::getUser()->isGod(); - $this->form = new BackendForm('settingsEmail'); // email settings @@ -61,28 +52,6 @@ private function loadForm(): void ->addText('mailer_reply_to_email', $mailerReplyTo['email'] ?? '') ->setAttribute('type', 'email') ; - - if ($this->isGod) { - $mailerType = $this->get('fork.settings')->get('Core', 'mailer_type', 'sendmail'); - $this->form->addDropdown('mailer_type', ['sendmail' => 'sendmail', 'smtp' => 'SMTP'], $mailerType); - - // smtp settings - $this->form->addText('smtp_server', $this->get('fork.settings')->get('Core', 'smtp_server', '')); - $this->form->addText('smtp_port', $this->get('fork.settings')->get('Core', 'smtp_port', 25)); - $this->form->addText('smtp_username', $this->get('fork.settings')->get('Core', 'smtp_username', '')); - $this->form->addPassword('smtp_password', $this->get('fork.settings')->get('Core', 'smtp_password', '')); - $this->form->addDropdown( - 'smtp_secure_layer', - [ - 'no' => s(BL::lbl('None'))->title()->toString(), - 'ssl' => 'SSL', - 'tls' => 'TLS' - ], - $this->get('fork.settings')->get('Core', 'smtp_secure_layer', 'no') - ); - } - - $this->template->assign('isGod', $this->isGod); } protected function parse(): void @@ -105,15 +74,6 @@ private function validateForm(): void $this->form->getField('mailer_reply_to_name')->isFilled(BL::err('FieldIsRequired')); $this->form->getField('mailer_reply_to_email')->isEmail(BL::err('EmailIsInvalid')); - if ($this->isGod) { - // SMTP type was chosen - if ($this->form->getField('mailer_type')->getValue() == 'smtp') { - // server & port are required - $this->form->getField('smtp_server')->isFilled(BL::err('FieldIsRequired')); - $this->form->getField('smtp_port')->isFilled(BL::err('FieldIsRequired')); - } - } - // no errors ? if ($this->form->isCorrect()) { // e-mail settings @@ -142,37 +102,6 @@ private function validateForm(): void ] ); - if ($this->isGod) { - $this->get('fork.settings')->set( - 'Core', - 'mailer_type', - $this->form->getField('mailer_type')->getValue() - ); - - // smtp settings - $this->get('fork.settings')->set( - 'Core', - 'smtp_server', - $this->form->getField('smtp_server')->getValue() - ); - $this->get('fork.settings')->set('Core', 'smtp_port', $this->form->getField('smtp_port')->getValue()); - $this->get('fork.settings')->set( - 'Core', - 'smtp_username', - $this->form->getField('smtp_username')->getValue() - ); - $this->get('fork.settings')->set( - 'Core', - 'smtp_password', - $this->form->getField('smtp_password')->getValue() - ); - $this->get('fork.settings')->set( - 'Core', - 'smtp_secure_layer', - $this->form->getField('smtp_secure_layer')->getValue() - ); - } - // assign report $this->template->assign('report', true); $this->template->assign('reportMessage', BL::msg('Saved')); diff --git a/src/Backend/Modules/Settings/Ajax/TestEmailConnection.php b/src/Backend/Modules/Settings/Ajax/TestEmailConnection.php deleted file mode 100644 index 49d2029d57..0000000000 --- a/src/Backend/Modules/Settings/Ajax/TestEmailConnection.php +++ /dev/null @@ -1,85 +0,0 @@ -getRequest()->request->get('mailer_from_email', ''); - $fromName = $this->getRequest()->request->get('mailer_from_name', ''); - $toEmail = $this->getRequest()->request->get('mailer_to_email', ''); - $toName = $this->getRequest()->request->get('mailer_to_name', ''); - $replyToEmail = $this->getRequest()->request->get('mailer_reply_to_email', ''); - $replyToName = $this->getRequest()->request->get('mailer_reply_to_name', ''); - - // init validation - $errors = []; - - // validate - if (!filter_var($fromEmail, FILTER_VALIDATE_EMAIL)) { - $errors['from'] = BL::err('EmailIsInvalid'); - } - if (!filter_var($toEmail, FILTER_VALIDATE_EMAIL)) { - $errors['to'] = BL::err('EmailIsInvalid'); - } - if (!filter_var($replyToEmail, FILTER_VALIDATE_EMAIL)) { - $errors['reply'] = BL::err('EmailIsInvalid'); - } - - // got errors? - if (!empty($errors)) { - $this->output( - Response::HTTP_BAD_REQUEST, - ['errors' => $errors], - 'invalid fields' - ); - - return; - } - - $message = new \Swift_Message('Test'); - $message - ->setFrom([$fromEmail => $fromName]) - ->setTo([$toEmail => $toName]) - ->setReplyTo([$replyToEmail => $replyToName]) - ->setBody(BL::msg('TestMessage'), 'text/plain') - ; - - $mailerType = $this->getRequest()->request->get('mailer_type'); - if (!in_array($mailerType, ['smtp', 'sendmail'])) { - $mailerType = 'sendmail'; - } - $transport = TransportFactory::create( - $mailerType, - $this->getRequest()->request->get('smtp_server', ''), - $this->getRequest()->request->getInt('smtp_port', 25), - $this->getRequest()->request->get('smtp_username', ''), - $this->getRequest()->request->get('smtp_password', ''), - $this->getRequest()->request->get('smtp_secure_layer', '') - ); - $mailer = new \Swift_Mailer($transport); - - try { - if ($mailer->send($message)) { - $this->output(Response::HTTP_OK, null, ''); - - return; - } - - $this->output(Response::HTTP_INTERNAL_SERVER_ERROR, null, 'unknown'); - } catch (\Exception $e) { - $this->output(Response::HTTP_INTERNAL_SERVER_ERROR, null, $e->getMessage()); - } - } -} diff --git a/src/Backend/Modules/Settings/Installer/Data/locale.xml b/src/Backend/Modules/Settings/Installer/Data/locale.xml index 5bac02339f..14fab63e37 100644 --- a/src/Backend/Modules/Settings/Installer/Data/locale.xml +++ b/src/Backend/Modules/Settings/Installer/Data/locale.xml @@ -512,19 +512,6 @@ - - - - - - - - - - - - - rel="nofollow" voor links in reacties]]> rel="nofollow" on links inside a comment]]> @@ -546,58 +533,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Backend/Modules/Settings/Installer/Installer.php b/src/Backend/Modules/Settings/Installer/Installer.php index f817d24fb8..39a6f9bc8a 100644 --- a/src/Backend/Modules/Settings/Installer/Installer.php +++ b/src/Backend/Modules/Settings/Installer/Installer.php @@ -45,6 +45,5 @@ private function configureBackendRights(): void $this->setActionRights(1, $this->getModule(), 'Email'); $this->setActionRights(1, $this->getModule(), 'Index'); $this->setActionRights(1, $this->getModule(), 'Seo'); - $this->setActionRights(1, $this->getModule(), 'TestEmailConnection'); } } diff --git a/src/Backend/Modules/Settings/Js/Settings.js b/src/Backend/Modules/Settings/Js/Settings.js index 7f830c8d91..558eeef931 100644 --- a/src/Backend/Modules/Settings/Js/Settings.js +++ b/src/Backend/Modules/Settings/Js/Settings.js @@ -12,7 +12,6 @@ jsBackend.settings = { canAddNew: true }) - $('#testEmailConnection').on('click', jsBackend.settings.testEmailConnection) $('[data-role="fork-clear-cache"]').on('click', jsBackend.settings.clearCache) $('#activeLanguages input:checkbox').on('change', jsBackend.settings.changeActiveLanguage).change() @@ -43,51 +42,6 @@ jsBackend.settings = { } }, - testEmailConnection: function (e) { - // prevent default - e.preventDefault() - - var $spinner = $('#testEmailConnectionSpinner') - var $error = $('#testEmailConnectionError') - var $success = $('#testEmailConnectionSuccess') - var $email = $('#settingsEmail') - - // show spinner - $spinner.show() - - // hide previous results - $error.hide() - $success.hide() - - // fetch email parameters - var settings = {} - $.each($email.serializeArray(), function () { settings[this.name] = this.value }) - - // make the call - $.ajax( - { - data: $.extend({fork: {action: 'TestEmailConnection'}}, settings), - success: function (data, textStatus) { - // hide spinner - $spinner.hide() - - // show success - if (data.code === 200) { - jsBackend.messages.add('success', jsBackend.locale.msg('TestWasSent'), '') - } else { - jsBackend.messages.add('danger', jsBackend.locale.err('ErrorWhileSendingEmail'), '') - } - }, - error: function (XMLHttpRequest, textStatus, errorThrown) { - // hide spinner - $spinner.hide() - - // show error - jsBackend.messages.add('danger', jsBackend.locale.err('ErrorWhileSendingEmail'), '') - } - }) - }, - clearCache: function (e) { // prevent default e.preventDefault() diff --git a/src/Backend/Modules/Settings/Layout/Templates/Email.html.twig b/src/Backend/Modules/Settings/Layout/Templates/Email.html.twig index b1020624d7..b72209b512 100644 --- a/src/Backend/Modules/Settings/Layout/Templates/Email.html.twig +++ b/src/Backend/Modules/Settings/Layout/Templates/Email.html.twig @@ -7,145 +7,86 @@ {% block content %} {% form settingsEmail %} -
-
-
-
-

- {{ 'lbl.Email'|trans|ucfirst }} -

-
-
- {% if isGod %} -
- - {{ 'lbl.SendingEmails'|trans|ucfirst }} -

{{ 'msg.HelpSendingEmails'|trans }}

-
-
- -
- {% form_field mailer_type %} {% form_field_error mailer_type %} - {{ 'msg.SendTestMail'|trans|ucfirst }} - -
- - -
-
-
- {% endif %} -
- - {{ 'lbl.From'|trans|ucfirst }} -

{{ 'msg.HelpEmailFrom'|trans }}

-
-
- - {% form_field mailer_from_name %} {% form_field_error mailer_from_name %} -
-
- - {% form_field mailer_from_email %} {% form_field_error mailer_from_email %} -
-
-
- - {{ 'lbl.To'|trans|ucfirst }} -

{{ 'msg.HelpEmailTo'|trans }}

-
-
- - {% form_field mailer_to_name %} {% form_field_error mailer_to_name %} -
-
- - {% form_field mailer_to_email %} {% form_field_error mailer_to_email %} -
-
-
- - {{ 'lbl.ReplyTo'|trans|ucfirst }} - -
- - {% form_field mailer_reply_to_name %} {% form_field_error mailer_reply_to_name %} -
-
- - {% form_field mailer_reply_to_email %} {% form_field_error mailer_reply_to_email %} -
-
-
-
-
-
- {% if isGod %}
-

- {{ 'lbl.SMTP'|trans|ucfirst }} -

+

+ {{ 'lbl.Email'|trans|ucfirst }} +

-
- -

{{ 'msg.HelpSMTPServer'|trans }}

-
- {% form_field smtp_server %} - : - {% form_field smtp_port %} - {% form_field_error smtp_port %} {% form_field_error smtp_server %} +
+ + {{ 'lbl.From'|trans|ucfirst }} +

{{ 'msg.HelpEmailFrom'|trans }}

+
+
+ + {% form_field mailer_from_name %} {% form_field_error mailer_from_name %} +
+
+ + {% form_field mailer_from_email %} {% form_field_error mailer_from_email %} +
+
+
+ + {{ 'lbl.To'|trans|ucfirst }} +

{{ 'msg.HelpEmailTo'|trans }}

+
+
+ + {% form_field mailer_to_name %} {% form_field_error mailer_to_name %}
-
-
- - {% form_field smtp_username %} {% form_field_error smtp_username %} -
-
- - {% form_field smtp_password %} {% form_field_error smtp_password %} -
-
- - {% form_field smtp_secure_layer %} -
+
+ + {% form_field mailer_to_email %} {% form_field_error mailer_to_email %} +
+ +
+ + {{ 'lbl.ReplyTo'|trans|ucfirst }} + +
+ + {% form_field mailer_reply_to_name %} {% form_field_error mailer_reply_to_name %} +
+
+ + {% form_field mailer_reply_to_email %} {% form_field_error mailer_reply_to_email %} +
+
- {% endif %} -
-
-
-
- {{ macro.buttonIcon('', 'floppy-o', 'lbl.Save'|trans|ucfirst, 'btn-primary', { "id":"save", "type":"submit", "name":"save" }) }} +
+
+
+
+ {{ macro.buttonIcon('', 'floppy-o', 'lbl.Save'|trans|ucfirst, 'btn-primary', { "id":"save", "type":"submit", "name":"save" }) }} +
-
{% endform %} {% endblock %} diff --git a/tests/data/test_db.sql b/tests/data/test_db.sql index 4e7b4fd172..62255b0873 100644 --- a/tests/data/test_db.sql +++ b/tests/data/test_db.sql @@ -375,7 +375,6 @@ VALUES (12,1,'Settings','Index',7), (13,1,'Settings','Email',7), (14,1,'Settings','Seo',7), - (15,1,'Settings','TestEmailConnection',7), (16,1,'Users','Add',7), (17,1,'Users','Delete',7), (18,1,'Users','Edit',7), From 4159cab34aa2eace2b1c9c09844f0fbe3011536b Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 14:29:05 +0100 Subject: [PATCH 05/16] feat: remove settings from profiles module --- src/Backend/Core/Installer/Data/locale.xml | 17 -- src/Backend/Modules/Profiles/Actions/Add.php | 100 ++---------- src/Backend/Modules/Profiles/Actions/Edit.php | 46 +----- .../Modules/Profiles/Actions/Settings.php | 150 ------------------ src/Backend/Modules/Profiles/Engine/Model.php | 120 -------------- .../Profiles/Installer/Data/locale.xml | 53 ------- .../Modules/Profiles/Installer/Installer.php | 7 - src/Backend/Modules/Profiles/Js/Profiles.js | 44 ----- .../Profiles/Layout/Templates/Add.html.twig | 4 - .../Profiles/Layout/Templates/Edit.html.twig | 3 - .../Layout/Templates/Settings.html.twig | 77 --------- .../Modules/Profiles/Actions/Register.php | 9 +- .../Modules/Profiles/Actions/Settings.php | 29 +--- .../Modules/Profiles/Engine/Model.php | 18 --- .../Layout/Templates/Settings.html.twig | 1 - .../Layout/Templates/Settings.html.twig | 1 - 16 files changed, 20 insertions(+), 659 deletions(-) delete mode 100644 src/Backend/Modules/Profiles/Actions/Settings.php delete mode 100644 src/Backend/Modules/Profiles/Layout/Templates/Settings.html.twig diff --git a/src/Backend/Core/Installer/Data/locale.xml b/src/Backend/Core/Installer/Data/locale.xml index 919eb6c827..c9567a134d 100644 --- a/src/Backend/Core/Installer/Data/locale.xml +++ b/src/Backend/Core/Installer/Data/locale.xml @@ -2822,23 +2822,6 @@ - - - - - - - - - - - - - - - - - diff --git a/src/Backend/Modules/Profiles/Actions/Add.php b/src/Backend/Modules/Profiles/Actions/Add.php index fa8a2129a9..e3ae31ac33 100644 --- a/src/Backend/Modules/Profiles/Actions/Add.php +++ b/src/Backend/Modules/Profiles/Actions/Add.php @@ -20,41 +20,15 @@ class Add extends BackendBaseActionAdd */ private $id; - /** - * @var bool - */ - private $notifyAdmin; - - /** - * @var bool - */ - private $notifyProfile; - public function execute(): void { parent::execute(); - $this->getData(); $this->loadForm(); $this->validateForm(); $this->parse(); $this->display(); } - public function getData(): void - { - $this->notifyAdmin = $this->get('fork.settings')->get( - $this->url->getModule(), - 'send_new_profile_admin_mail', - false - ); - - $this->notifyProfile = $this->get('fork.settings')->get( - $this->url->getModule(), - 'send_new_profile_mail', - false - ); - } - private function loadForm(): void { // gender dropdown values @@ -75,45 +49,30 @@ private function loadForm(): void $this->form ->addText('email') ->setAttribute('type', 'email') - ->makeRequired() - ; + ->makeRequired(); $this->form ->addPassword('password') - ->setAttribute('autocomplete', 'new-password') - ; - - if (!$this->notifyProfile) { - $this->form->getField('password')->makeRequired(); - } + ->setAttribute('autocomplete', 'new-password'); $this->form ->addText('display_name') - ->makeRequired() - ; + ->makeRequired(); $this->form - ->addText('first_name') - ; + ->addText('first_name'); $this->form - ->addText('last_name') - ; + ->addText('last_name'); $this->form - ->addText('city') - ; + ->addText('city'); $this->form - ->addDropdown('gender', $genderValues) - ; + ->addDropdown('gender', $genderValues); $this->form - ->addDropdown('day', array_combine($days, $days)) - ; + ->addDropdown('day', array_combine($days, $days)); $this->form - ->addDropdown('month', $months) - ; + ->addDropdown('month', $months); $this->form - ->addDropdown('year', array_combine($years, $years)) - ; + ->addDropdown('year', array_combine($years, $years)); $this->form - ->addDropdown('country', Countries::getNames(BL::getInterfaceLanguage())) - ; + ->addDropdown('country', Countries::getNames(BL::getInterfaceLanguage())); $this->form->addTextarea('about'); // set default elements dropdowns @@ -166,11 +125,6 @@ private function validateForm(): void } } - // profile must not be notified, password must not be empty - if (!$this->notifyProfile) { - $txtPassword->isFilled(BL::err('FieldIsRequired')); - } - // one of the birthday fields are filled in if ($ddmDay->isFilled() || $ddmMonth->isFilled() || $ddmYear->isFilled()) { // valid date? @@ -218,36 +172,10 @@ private function validateForm(): void BackendProfilesModel::setSetting($this->id, 'country', $ddmCountry->getValue()); BackendProfilesModel::setSetting($this->id, 'about', $txtAbout->getValue()); - // notify values - $notifyValues = array_merge( - $values, - [ - 'id' => $this->id, - 'first_name' => $txtFirstName->getValue(), - 'last_name' => $txtLastName->getValue(), - 'unencrypted_password' => $password, - ] - ); - $redirectUrl = BackendModel::createUrlForAction('Edit') . '&id=' . $this->id . - '&var=' . rawurlencode((string) $values['display_name']) . - '&report=' - ; - - // notify new profile user - if ($this->notifyProfile) { - BackendProfilesModel::notifyProfile($notifyValues); - - $redirectUrl .= 'saved-and-notified'; - } else { - $redirectUrl .= 'saved'; - } - - // notify admin - if ($this->notifyAdmin) { - BackendProfilesModel::notifyAdmin($notifyValues); - } + '&var=' . rawurlencode((string) $values['display_name']) . + '&report=saved'; // everything is saved, so redirect to the overview $this->redirect($redirectUrl); @@ -258,7 +186,5 @@ private function validateForm(): void protected function parse(): void { parent::parse(); - - $this->template->assign('notifyProfile', $this->notifyProfile); } } diff --git a/src/Backend/Modules/Profiles/Actions/Edit.php b/src/Backend/Modules/Profiles/Actions/Edit.php index 405e8996bc..63f7cf0f6f 100644 --- a/src/Backend/Modules/Profiles/Actions/Edit.php +++ b/src/Backend/Modules/Profiles/Actions/Edit.php @@ -26,11 +26,6 @@ class Edit extends BackendBaseActionEdit */ private $dgGroups; - /** - * @var bool - */ - private $notifyProfile; - /** * Info about the current profile. * @@ -61,12 +56,6 @@ private function getData(): void { // get general info $this->profile = BackendProfilesModel::get($this->id); - - $this->notifyProfile = $this->get('fork.settings')->get( - $this->url->getModule(), - 'send_new_profile_mail', - false - ); } private function loadForm(): void @@ -201,8 +190,6 @@ protected function parse(): void { parent::parse(); - $this->template->assign('notifyProfile', $this->notifyProfile); - // assign the active record and additional variables $this->template->assign('profile', $this->profile); @@ -272,9 +259,8 @@ private function validateForm(): void } } - // new_password is checked, so verify new password (only if profile should not be notified) - // because then if the password field is empty, it will generate a new password - if ($chkNewPassword->isChecked() && !$this->notifyProfile) { + // new_password is checked, so verify new password + if ($chkNewPassword->isChecked()) { $txtPassword->isFilled(BL::err('FieldIsRequired')); $txtPasswordRepeat->isFilled(BL::err('FieldIsRequired')); @@ -347,33 +333,7 @@ private function validateForm(): void '&var=' . rawurlencode((string) $values['email']) . '&highlight=row-' . $this->id . '&var=' . rawurlencode((string) $displayName) . - '&report=' - ; - - if ($this->notifyProfile && - ($chkNewEmail->isChecked() || $chkNewPassword->isChecked()) - ) { - // notify values - $notifyValues = array_merge( - $values, - [ - 'id' => $this->id, - 'first_name' => $txtFirstName->getValue(), - 'last_name' => $txtLastName->getValue(), - 'unencrypted_password' => $password, - ] - ); - - if (!isset($notifyValues['display_name'])) { - $notifyValues['display_name'] = $this->profile['display_name']; - } - - BackendProfilesModel::notifyProfile($notifyValues, true); - - $redirectUrl .= 'saved-and-notified'; - } else { - $redirectUrl .= 'saved'; - } + '&report=saved'; // everything is saved, so redirect to the overview $this->redirect($redirectUrl); diff --git a/src/Backend/Modules/Profiles/Actions/Settings.php b/src/Backend/Modules/Profiles/Actions/Settings.php deleted file mode 100644 index 816a83ad37..0000000000 --- a/src/Backend/Modules/Profiles/Actions/Settings.php +++ /dev/null @@ -1,150 +0,0 @@ -loadForm(); - $this->validateForm(); - - $this->parse(); - $this->display(); - } - - private function loadForm(): void - { - // init settings form - $this->form = new BackendForm('settings'); - - $this->form->addCheckbox( - 'limit_display_name_changes', - $this->get('fork.settings')->get( - $this->url->getModule(), - 'limit_display_name_changes', - false - ) - ); - - $this->form->addText( - 'max_display_name_changes', - $this->get('fork.settings')->get( - $this->url->getModule(), - 'max_display_name_changes', - Model::MAX_DISPLAY_NAME_CHANGES - ) - )->setAttribute('type', 'number'); - - // send email for new profile to admin - $this->form->addCheckbox( - 'send_new_profile_admin_mail', - $this->get('fork.settings')->get( - $this->url->getModule(), - 'send_new_profile_admin_mail', - false - ) - ); - - $this->form->addCheckbox( - 'overwrite_profile_notification_email', - (bool) ($this->get('fork.settings')->get( - $this->url->getModule(), - 'profile_notification_email', - null - ) !== null) - ); - - $this->form->addText( - 'profile_notification_email', - $this->get('fork.settings')->get( - $this->url->getModule(), - 'profile_notification_email', - null - ) - ); - - // send email for new profile to profile - $this->form->addCheckbox( - 'send_new_profile_mail', - $this->get('fork.settings')->get( - $this->url->getModule(), - 'send_new_profile_mail', - false - ) - ); - } - - private function validateForm(): void - { - if ($this->form->isSubmitted()) { - if ($this->form->getField('send_new_profile_admin_mail')->isChecked()) { - if ($this->form->getField('overwrite_profile_notification_email')->isChecked()) { - $this->form->getField('profile_notification_email')->isEmail(BL::msg('EmailIsRequired')); - } - } - - if ($this->form->getField('limit_display_name_changes')->isChecked()) { - $maxDisplayNameChanges = intval($this->form->getField('max_display_name_changes')->getValue()); - - if ($maxDisplayNameChanges <= 0) { - $this->form->getField('max_display_name_changes')->addError( - BL::getError('InvalidNumberOfChanges') - ); - } - } - - if ($this->form->isCorrect()) { - // set our settings - $this->get('fork.settings')->set( - $this->url->getModule(), - 'send_new_profile_admin_mail', - (bool) $this->form->getField('send_new_profile_admin_mail')->getValue() - ); - - $profileNotificationEmail = null; - - if ($this->form->getField('overwrite_profile_notification_email')->isChecked()) { - $profileNotificationEmail = $this->form->getField('profile_notification_email')->getValue(); - } - - $this->get('fork.settings')->set( - $this->url->getModule(), - 'profile_notification_email', - $profileNotificationEmail - ); - $this->get('fork.settings')->set( - $this->url->getModule(), - 'send_new_profile_mail', - (bool) $this->form->getField('send_new_profile_mail')->getValue() - ); - - $this->get('fork.settings')->set( - $this->url->getModule(), - 'limit_display_name_changes', - $this->form->getField('limit_display_name_changes')->isChecked() - ); - - $this->get('fork.settings')->set( - $this->url->getModule(), - 'max_display_name_changes', - intval($this->form->getField('max_display_name_changes')->getValue()) - ); - - // redirect to the settings page - $this->redirect(BackendModel::createUrlForAction('Settings') . '&report=saved-settings'); - } - } - } -} diff --git a/src/Backend/Modules/Profiles/Engine/Model.php b/src/Backend/Modules/Profiles/Engine/Model.php index 4ec1aff8f3..5e9fdc06c6 100644 --- a/src/Backend/Modules/Profiles/Engine/Model.php +++ b/src/Backend/Modules/Profiles/Engine/Model.php @@ -2,7 +2,6 @@ namespace Backend\Modules\Profiles\Engine; -use Common\Mailer\Message; use Common\Uri as CommonUri; use Backend\Core\Engine\Authentication as BackendAuthentication; use Backend\Core\Language\Language as BL; @@ -629,125 +628,6 @@ public static function insertProfileGroup(array $membership): int return (int) BackendModel::getContainer()->get('database')->insert('profiles_groups_rights', $membership); } - /** - * Notify admin - after adding profile to profiles module - * - * @param array $values - * @param string $templatePath - */ - public static function notifyAdmin(array $values, ?string $templatePath = null): void - { - // to email - $toEmail = BackendModel::get('fork.settings')->get('Profiles', 'profile_notification_email', null); - - if ($toEmail === null) { - $to = BackendModel::get('fork.settings')->get('Core', 'mailer_to'); - $toEmail = $to['email']; - } - - // define backend url - $backendUrl = BackendModel::createUrlForAction('Edit', 'Profiles') . '&id=' . $values['id']; - - // set variables - $variables = [ - 'message' => vsprintf( - BL::msg('NotificationNewProfileToAdmin', 'Profiles'), - [ - $values['display_name'], - $values['email'], - $backendUrl, - ] - ), - ]; - - // define subject - $subject = vsprintf( - BL::lbl('NotificationNewProfileToAdmin', 'Profiles'), - [ - $values['email'], - ] - ); - - self::sendMail( - $subject, - $templatePath, - $variables, - $toEmail - ); - } - - /** - * Notify profile - after adding profile to profiles module - * - * @param array $values - * @param bool $forUpdate - * @param string $templatePath - */ - public static function notifyProfile( - array $values, - bool $forUpdate = false, - ?string $templatePath = null - ): void { - // set variables - $variables = [ - 'message' => vsprintf( - BL::msg('NotificationNewProfileLoginCredentials', 'Profiles'), - [ - $values['email'], - $values['unencrypted_password'], - SITE_URL, - ] - ), - ]; - - // define subject - $notificationSubject = $forUpdate ? 'NotificationUpdatedProfileToProfile' : 'NotificationNewProfileToProfile'; - $subject = BL::lbl($notificationSubject, 'Profiles'); - - self::sendMail( - $subject, - $templatePath, - $variables, - $values['email'], - $values['display_name'] - ); - } - - /** - * Send mail - * - * @param string $subject - * @param string|null $templatePath - * @param array $variables - * @param string $toEmail - * @param string $toDisplayName - */ - protected static function sendMail( - $subject, - ?string $templatePath, - array $variables, - string $toEmail, - ?string $toDisplayName = null - ): void { - if (empty($templatePath)) { - $templatePath = FRONTEND_CORE_PATH . '/Layout/Templates/Mails/Notification.html.twig'; - } - - // define variables - $from = BackendModel::get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = BackendModel::get('fork.settings')->get('Core', 'mailer_reply_to'); - - // create a message object and set all the needed properties - $message = Message::newInstance($subject) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$toEmail => $toDisplayName]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml($templatePath, $variables, true); - - // send it through the mailer service - BackendModel::get('mailer')->send($message); - } - /** * Insert or update a single profile setting. * diff --git a/src/Backend/Modules/Profiles/Installer/Data/locale.xml b/src/Backend/Modules/Profiles/Installer/Data/locale.xml index 8e94cc6261..b3d37b8ddc 100644 --- a/src/Backend/Modules/Profiles/Installer/Data/locale.xml +++ b/src/Backend/Modules/Profiles/Installer/Data/locale.xml @@ -366,50 +366,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -424,20 +385,6 @@ - - - - - - - - - - - - - - diff --git a/src/Backend/Modules/Profiles/Installer/Installer.php b/src/Backend/Modules/Profiles/Installer/Installer.php index 03e18f8d2d..5eedab5d23 100644 --- a/src/Backend/Modules/Profiles/Installer/Installer.php +++ b/src/Backend/Modules/Profiles/Installer/Installer.php @@ -48,7 +48,6 @@ private function configureBackendActionRightsForProfile(): void $this->setActionRights(1, $this->getModule(), 'Import'); $this->setActionRights(1, $this->getModule(), 'Index'); $this->setActionRights(1, $this->getModule(), 'MassAction'); - $this->setActionRights(1, $this->getModule(), 'Settings'); } private function configureBackendActionRightsForProfileGroup(): void @@ -358,12 +357,6 @@ private function configureFrontendPages(): void private function configureSettings(): void { $this->setSetting($this->getModule(), 'allow_gravatar', true); - $this->setSetting($this->getModule(), 'overwrite_profile_notification_email', false); - $this->setSetting($this->getModule(), 'profile_notification_email', null); - $this->setSetting($this->getModule(), 'send_mail_for_new_profile_to_admin', false); - $this->setSetting($this->getModule(), 'send_mail_for_new_profile_to_profile', false); - $this->setSetting($this->getModule(), 'limit_display_name_changes', true); - $this->setSetting($this->getModule(), 'max_display_name_changes', Model::MAX_DISPLAY_NAME_CHANGES); } private function getExtraId(string $key): int diff --git a/src/Backend/Modules/Profiles/Js/Profiles.js b/src/Backend/Modules/Profiles/Js/Profiles.js index 444b345df3..15947b378a 100644 --- a/src/Backend/Modules/Profiles/Js/Profiles.js +++ b/src/Backend/Modules/Profiles/Js/Profiles.js @@ -4,7 +4,6 @@ jsBackend.Profiles = { init: function () { jsBackend.Profiles.massAddToGroup.init() - jsBackend.Profiles.settings.init() jsBackend.Profiles.editEmail.init() jsBackend.Profiles.editPassword.init() }, @@ -65,49 +64,6 @@ jsBackend.Profiles = { $('#newPasswordBox').toggle(checked) } }, - - settings: { - init: function () { - if ($('#sendNewProfileAdminMail').length === 0) return false - - $('#sendNewProfileAdminMail').on('change', function () { - jsBackend.Profiles.settings.toggleAdminMail() - }) - - $('#limitDisplayNameChanges').on('change', function () { - jsBackend.Profiles.settings.toggleDisplayNameChanges() - }) - - $('#overwriteProfileNotificationEmail').on('change', function () { - jsBackend.Profiles.settings.toggleProfileNotificationEmail() - }) - - jsBackend.Profiles.settings.toggleAdminMail() - jsBackend.Profiles.settings.toggleDisplayNameChanges() - jsBackend.Profiles.settings.toggleProfileNotificationEmail() - }, - - toggleAdminMail: function () { - var $item = $('#sendNewProfileAdminMail') - var checked = ($item.attr('checked') === 'checked') - - $('#overwriteProfileNotificationEmailBox').toggle(checked) - }, - - toggleDisplayNameChanges: function () { - var $item = $('#limitDisplayNameChanges') - var checked = ($item.attr('checked') === 'checked') - - $('#maxDisplayNameChangesBox').toggle(checked) - }, - - toggleProfileNotificationEmail: function () { - var $item = $('#overwriteProfileNotificationEmail') - var checked = ($item.attr('checked') === 'checked') - - $('#profileNotificationEmailBox').toggle(checked) - } - } } $(jsBackend.Profiles.init) diff --git a/src/Backend/Modules/Profiles/Layout/Templates/Add.html.twig b/src/Backend/Modules/Profiles/Layout/Templates/Add.html.twig index ffddfc5186..269a2ee355 100644 --- a/src/Backend/Modules/Profiles/Layout/Templates/Add.html.twig +++ b/src/Backend/Modules/Profiles/Layout/Templates/Add.html.twig @@ -7,10 +7,6 @@ {% block content %} {% form add %} - {% if notifyProfile %} -

{{ macro.icon('warning') }} {{ 'lbl.NewProfileWillBeNotified'|trans|ucfirst }} -

- {% endif %}
diff --git a/src/Backend/Modules/Profiles/Layout/Templates/Edit.html.twig b/src/Backend/Modules/Profiles/Layout/Templates/Edit.html.twig index 7b7719dd01..903f171f0c 100644 --- a/src/Backend/Modules/Profiles/Layout/Templates/Edit.html.twig +++ b/src/Backend/Modules/Profiles/Layout/Templates/Edit.html.twig @@ -7,9 +7,6 @@ {% block content %} {% form edit %} - {% if notifyProfile %} -

{{ macro.icon('warning') }} {{ 'lbl.UpdatedProfileWillBeNotified'|trans|ucfirst }}

- {% endif %}
diff --git a/src/Backend/Modules/Profiles/Layout/Templates/Settings.html.twig b/src/Backend/Modules/Profiles/Layout/Templates/Settings.html.twig deleted file mode 100644 index 3050c9969c..0000000000 --- a/src/Backend/Modules/Profiles/Layout/Templates/Settings.html.twig +++ /dev/null @@ -1,77 +0,0 @@ -{% extends 'Layout/Templates/base.html.twig' %} -{% import "Layout/Templates/macros.html.twig" as macro %} - -{% block actionbar %} - -{% endblock %} - -{% block content %} - - {% form settings %} -
-
-
-
-

- {{ 'lbl.DisplayNameChanges'|trans|ucfirst }} -

-
-
-
-
    -
  • - - - {{ macro.required }} {% form_field max_display_name_changes %} - {% form_field_error max_display_name_changes %} - -
  • -
-
-
-
-
-
-

- {{ 'lbl.Notifications'|trans|ucfirst }} -

-
-
-
-
    -
  • - -
  • -
  • -
    - - {{ macro.required }} {% form_field profile_notification_email %} - {% form_field_error profile_notification_email %} - -
  • -
-
-
-
    -
  • - -
  • -
-
-
-
-
-
-
-
-
-
- {{ macro.buttonIcon('', 'floppy-o', 'lbl.Save'|trans|ucfirst, 'btn-primary', { "type":"submit", "id":"save", "name":"save"}) }} -
-
-
-
- {% endform %} -{% endblock %} - - diff --git a/src/Frontend/Modules/Profiles/Actions/Register.php b/src/Frontend/Modules/Profiles/Actions/Register.php index 6b37e3c867..830182ac57 100644 --- a/src/Frontend/Modules/Profiles/Actions/Register.php +++ b/src/Frontend/Modules/Profiles/Actions/Register.php @@ -46,20 +46,17 @@ private function buildForm(): void $this->form ->addText('display_name') ->setAttribute('autocomplete', 'username') - ->makeRequired() - ; + ->makeRequired(); $this->form ->addText('email') ->setAttribute('type', 'email') ->setAttribute('autocomplete', 'email') - ->makeRequired() - ; + ->makeRequired(); $this->form ->addPassword('password') ->setAttribute('data-role', 'fork-new-password') ->setAttribute('autocomplete', 'new-password') - ->makeRequired() - ; + ->makeRequired(); $this->form->addCheckbox('show_password')->setAttributes( [ 'data-role' => 'fork-toggle-visible-password', diff --git a/src/Frontend/Modules/Profiles/Actions/Settings.php b/src/Frontend/Modules/Profiles/Actions/Settings.php index d0a6056e60..6a03e30eb2 100644 --- a/src/Frontend/Modules/Profiles/Actions/Settings.php +++ b/src/Frontend/Modules/Profiles/Actions/Settings.php @@ -77,9 +77,6 @@ private function buildForm(): void ->setAttribute('autocomplete', 'username') ->makeRequired() ; - if (!$this->displayNameCanStillBeChanged()) { - $this->form->getField('display_name')->setAttribute('disabled', 'disabled'); - } $this->form ->addText('first_name', $this->profile->getSetting('first_name')) ->setAttribute('autocomplete', 'given-name') @@ -142,23 +139,6 @@ private function parse(): void $this->template->assign('avatar', (string) $this->profile->getSetting('avatar', '')); $this->form->parse($this->template); - - // display name changes - $this->template->assign('maxDisplayNameChanges', FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES); - $this->template->assign( - 'displayNameChangesLeft', - FrontendProfilesModel::MAX_DISPLAY_NAME_CHANGES - $this->profile->getSetting('display_name_changes') - ); - } - - private function getAmountOfDisplayNameChanges(): int - { - return (int) FrontendProfilesModel::getSetting($this->profile->getId(), 'display_name_changes'); - } - - private function displayNameCanStillBeChanged(): bool - { - return FrontendProfilesModel::displayNameCanStillBeChanged($this->profile); } private function validateForm(): bool @@ -168,8 +148,7 @@ private function validateForm(): bool $ddmMonth = $this->form->getField('month'); $ddmYear = $this->form->getField('year'); - if ($this->displayNameCanStillBeChanged() - && $this->profile->getDisplayName() !== $txtDisplayName->getValue() + if ($this->profile->getDisplayName() !== $txtDisplayName->getValue() && $txtDisplayName->isFilled(FL::getError('FieldIsRequired')) && FrontendProfilesModel::existsDisplayName($txtDisplayName->getValue(), $this->profile->getId())) { $txtDisplayName->addError(FL::getError('DisplayNameExists')); @@ -225,14 +204,8 @@ private function handleForm(): void return; } - $displayNameChanges = $this->getAmountOfDisplayNameChanges(); - if ($this->displayNameWasChanged()) { - ++$displayNameChanges; - } - $this->profile->setSettings( [ - 'display_name_changes' => $displayNameChanges, 'first_name' => $this->form->getField('first_name')->getValue(), 'last_name' => $this->form->getField('last_name')->getValue(), 'city' => $this->form->getField('city')->getValue(), diff --git a/src/Frontend/Modules/Profiles/Engine/Model.php b/src/Frontend/Modules/Profiles/Engine/Model.php index 7f884c897c..dff303ef50 100644 --- a/src/Frontend/Modules/Profiles/Engine/Model.php +++ b/src/Frontend/Modules/Profiles/Engine/Model.php @@ -6,7 +6,6 @@ use Frontend\Core\Engine\Model as FrontendModel; use Frontend\Core\Engine\Navigation as FrontendNavigation; use Frontend\Modules\Profiles\Engine\Authentication as FrontendProfilesAuthentication; -use Frontend\Modules\Profiles\Engine\Model as FrontendProfilesModel; use Frontend\Modules\Profiles\Engine\Profile as FrontendProfilesProfile; /** @@ -14,8 +13,6 @@ */ class Model { - const MAX_DISPLAY_NAME_CHANGES = 2; - /** * Avatars cache * @@ -23,21 +20,6 @@ class Model */ private static $avatars = []; - public static function maxDisplayNameChanges(): int - { - return FrontendModel::get('fork.settings')->get('Profiles', 'max_display_name_changes', self::MAX_DISPLAY_NAME_CHANGES); - } - - public static function displayNameCanStillBeChanged(Profile $profile): bool - { - if (!FrontendModel::get('fork.settings')->get('Profiles', 'limit_display_name_changes', false)) { - return true; - } - - return (int) FrontendProfilesModel::getSetting($profile->getId(), 'display_name_changes') < - self::maxDisplayNameChanges(); - } - public static function deleteSetting(int $profileId, string $name): int { return (int) FrontendModel::getContainer()->get('database')->delete( diff --git a/src/Frontend/Modules/Profiles/Layout/Templates/Settings.html.twig b/src/Frontend/Modules/Profiles/Layout/Templates/Settings.html.twig index eecd8787ff..92508c7e28 100644 --- a/src/Frontend/Modules/Profiles/Layout/Templates/Settings.html.twig +++ b/src/Frontend/Modules/Profiles/Layout/Templates/Settings.html.twig @@ -26,7 +26,6 @@
{% form_field_error display_name %}{% form_field display_name %} - {{ 'msg.HelpDisplayNameChanges'|trans|format(maxDisplayNameChanges, displayNameChangesLeft ) }}
diff --git a/src/Frontend/Themes/Bootstrap/Modules/Profiles/Layout/Templates/Settings.html.twig b/src/Frontend/Themes/Bootstrap/Modules/Profiles/Layout/Templates/Settings.html.twig index b0faf1e754..d22dcef4ab 100644 --- a/src/Frontend/Themes/Bootstrap/Modules/Profiles/Layout/Templates/Settings.html.twig +++ b/src/Frontend/Themes/Bootstrap/Modules/Profiles/Layout/Templates/Settings.html.twig @@ -18,7 +18,6 @@ {% form_field display_name %} - {{ 'msg.HelpDisplayNameChanges'|trans|format(maxDisplayNameChanges, displayNameChangesLeft ) }} {% form_field_error display_name %}
From df8a0b4b3b969f4ef684430c6008eb4553e2c7ee Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 14:46:41 +0100 Subject: [PATCH 06/16] feat: Use new mailer for Forgot password --- app/config/config.yml | 2 + .../Layout/Templates/Mails/Default.html.twig | 1589 +++++++++++++++++ .../Modules/Authentication/Actions/Index.php | 26 +- .../Templates/Mails/ResetPassword.html.twig | 106 +- 4 files changed, 1618 insertions(+), 105 deletions(-) create mode 100644 src/Backend/Core/Layout/Templates/Mails/Default.html.twig diff --git a/app/config/config.yml b/app/config/config.yml index 1c0f06b1c5..f6a5d29d9c 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -57,6 +57,8 @@ twig: - "%fork.form.theme%" paths: '%site.path_www%/src/Frontend/Modules/': ForkFrontendModules + '%site.path_www%/src/Backend/Modules/': ForkBackendModules + '%site.path_www%/src/Backend/Core/': ForkBackendCore monolog: handlers: diff --git a/src/Backend/Core/Layout/Templates/Mails/Default.html.twig b/src/Backend/Core/Layout/Templates/Mails/Default.html.twig new file mode 100644 index 0000000000..1044c1b19a --- /dev/null +++ b/src/Backend/Core/Layout/Templates/Mails/Default.html.twig @@ -0,0 +1,1589 @@ +{% apply inline_css %} + + + + + + {% block title %} + Fork CMS - {{ email.subject }} + {% endblock %} + + + + + + + + + +
+
+ + + + + + +
 
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+

+
Fork CMS
+

+
+
+
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+ {% block main %} + + {% endblock %} +
+
+
+ + + + + + + +
 
+ +
+
+ +
                                                           
+ + + + +{% endapply %} diff --git a/src/Backend/Modules/Authentication/Actions/Index.php b/src/Backend/Modules/Authentication/Actions/Index.php index 263dd5899b..38a3b3a280 100644 --- a/src/Backend/Modules/Authentication/Actions/Index.php +++ b/src/Backend/Modules/Authentication/Actions/Index.php @@ -9,9 +9,11 @@ use Backend\Core\Engine\Model as BackendModel; use Backend\Core\Engine\User; use Backend\Modules\Users\Engine\Model as BackendUsersModel; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; use function Symfony\Component\String\s; /** @@ -209,21 +211,23 @@ private function validateForm(): void $user->setSetting('reset_password_key', $key); $user->setSetting('reset_password_timestamp', time()); + + /** @var EmailFactory $emailFactory */ + $emailFactory = $this->get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = $this->get(MailerInterface::class); + // send e-mail to user - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(s(BL::msg('ResetYourPasswordMailSubject'))->title()->toString()) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$email]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Authentication/Layout/Templates/Mails/ResetPassword.html.twig', - [ + $message = $emailFactory->create() + ->subject(s(BL::msg('ResetYourPasswordMailSubject'))->title()->toString()) + ->to(new Address($email)) + ->htmlTemplate('@ForkBackendModules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig') + ->context([ 'resetLink' => SITE_URL . BackendModel::createUrlForAction('ResetPassword') . '&email=' . $email . '&key=' . $key, ] ); - $this->get('mailer')->send($message); + $mailer->send($message); // clear post-values $_POST['backend_email_forgot'] = ''; diff --git a/src/Backend/Modules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig b/src/Backend/Modules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig index 818c010dff..2c8ec89540 100644 --- a/src/Backend/Modules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig +++ b/src/Backend/Modules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig @@ -1,97 +1,15 @@ - - - - {# do NOT remove the UTF-8 part #} - - Fork CMS - {{ 'msg.ResetYourPasswordMailSubject' }} - - - - - - - -
- - - - -
- -

{{ 'lbl.ResetYourPassword'|trans|ucfirst }}

- -
-

{{ 'lbl.Dear'|trans|ucfirst }},

-

{{ 'msg.ResetYourPasswordMailContent'|trans|ucfirst }}

-

{{ resetLink }}

-
- - - -
- -
- - + +{% endblock %} From 8d33283417bac4b63fff738aaf711c15b0e7f6ac Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:22:16 +0100 Subject: [PATCH 07/16] feat: use new way of sending mails --- src/Frontend/Modules/Blog/Engine/Model.php | 52 ++++++++----------- src/Frontend/Modules/Faq/Actions/Detail.php | 27 ++++------ .../Templates/Mails/OwnQuestion.html.twig | 2 +- .../Modules/Faq/Widgets/AskOwnQuestion.php | 29 +++++------ .../Profiles/Actions/ForgotPassword.php | 31 +++++------ .../Modules/Profiles/Actions/Register.php | 32 +++++++----- .../Profiles/Actions/ResendActivation.php | 31 ++++++----- .../Templates/Mails/OwnQuestion.html.twig | 2 +- 8 files changed, 98 insertions(+), 108 deletions(-) diff --git a/src/Frontend/Modules/Blog/Engine/Model.php b/src/Frontend/Modules/Blog/Engine/Model.php index 71026eb4fd..929791416c 100644 --- a/src/Frontend/Modules/Blog/Engine/Model.php +++ b/src/Frontend/Modules/Blog/Engine/Model.php @@ -4,7 +4,7 @@ use Common\Doctrine\Entity\Meta; use Common\Doctrine\Repository\MetaRepository; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use ForkCMS\Utility\Thumbnails; use Frontend\Core\Language\Language as FL; use Frontend\Core\Engine\Model as FrontendModel; @@ -13,6 +13,7 @@ use Frontend\Core\Language\Locale; use Frontend\Modules\Tags\Engine\Model as FrontendTagsModel; use Frontend\Modules\Tags\Engine\TagsInterface as FrontendTagsInterface; +use Symfony\Component\Mailer\MailerInterface; /** * In this file we store all generic functions that we will be using in the blog module @@ -850,7 +851,6 @@ public static function notifyAdmin(array $comment): void // notify on all comments if ($notifyByMailOnComment) { $variables = []; - // comment to moderate if ($comment['status'] == 'moderation') { $variables['message'] = vsprintf( @@ -865,21 +865,16 @@ public static function notifyAdmin(array $comment): void ); } - $to = FrontendModel::get('fork.settings')->get('Core', 'mailer_to'); - $from = FrontendModel::get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = FrontendModel::get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(FL::msg('NotificationSubject')) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Core/Layout/Templates/Mails/Notification.html.twig', - $variables, - true - ) - ; - FrontendModel::get('mailer')->send($message); - } elseif ($notifyByMailOnCommentToModerate && $comment['status'] == 'moderation') { + /** @var EmailFactory $emailFactory */ + $emailFactory = FrontendModel::get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = FrontendModel::get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(FL::msg('NotificationSubject')) + ->htmlTemplate('/Core/Layout/Templates/Mails/Notification.html.twig') + ->context($variables); + $mailer->send($message); + } elseif ($notifyByMailOnCommentToModerate && $comment['status'] === 'moderation') { // only notify on new comments to moderate and if the comment is one to moderate // set variables $variables = []; @@ -888,20 +883,15 @@ public static function notifyAdmin(array $comment): void [$comment['author'], $url, $comment['post_title'], $backendUrl] ); - $to = FrontendModel::get('fork.settings')->get('Core', 'mailer_to'); - $from = FrontendModel::get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = FrontendModel::get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(FL::msg('NotificationSubject')) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Core/Layout/Templates/Mails/Notification.html.twig', - $variables, - true - ) - ; - FrontendModel::get('mailer')->send($message); + /** @var EmailFactory $emailFactory */ + $emailFactory = FrontendModel::get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = FrontendModel::get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(FL::msg('NotificationSubject')) + ->htmlTemplate('/Core/Layout/Templates/Mails/Notification.html.twig') + ->context($variables); + $mailer->send($message); } } diff --git a/src/Frontend/Modules/Faq/Actions/Detail.php b/src/Frontend/Modules/Faq/Actions/Detail.php index 273ae5fab0..23be755fd7 100644 --- a/src/Frontend/Modules/Faq/Actions/Detail.php +++ b/src/Frontend/Modules/Faq/Actions/Detail.php @@ -2,7 +2,7 @@ namespace Frontend\Modules\Faq\Actions; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Core\Engine\Base\Block as FrontendBaseBlock; use Frontend\Core\Engine\Form as FrontendForm; use Frontend\Core\Language\Language as FL; @@ -11,6 +11,7 @@ use Frontend\Modules\Faq\Engine\Model as FrontendFaqModel; use Frontend\Modules\Tags\Engine\Model as FrontendTagsModel; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Mailer\MailerInterface; /** * This is the detail-action @@ -287,20 +288,14 @@ private function sendNotificationMail(array $feedback): void { $feedback['question'] = $this->question['question']; - $to = $this->get('fork.settings')->get('Core', 'mailer_to'); - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance( - sprintf(FL::getMessage('FaqFeedbackSubject'), $feedback['question']) - ) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Faq/Layout/Templates/Mails/Feedback.html.twig', - $feedback, - true - ); - $this->get('mailer')->send($message); + /** @var EmailFactory $emailFactory */ + $emailFactory = FrontendModel::get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = FrontendModel::get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(sprintf(FL::getMessage('FaqFeedbackSubject'), $feedback['question'])) + ->htmlTemplate('/Faq/Layout/Templates/Mails/Feedback.html.twig') + ->context($feedback); + $mailer->send($message); } } diff --git a/src/Frontend/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig b/src/Frontend/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig index b649feaf9b..98bbe45bfc 100644 --- a/src/Frontend/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig +++ b/src/Frontend/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig @@ -15,6 +15,6 @@

{{ 'lbl.Content'|trans|ucfirst }}

{{ 'lbl.Name'|trans|ucfirst }}:
{{ name }}

-

{{ 'lbl.Email'|trans|ucfirst }}:
{{ email }}

+

{{ 'lbl.Email'|trans|ucfirst }}:
{{ emailaddress }}

{{ 'lbl.Question'|trans|ucfirst }}:
{{ message }}

{% endblock %} diff --git a/src/Frontend/Modules/Faq/Widgets/AskOwnQuestion.php b/src/Frontend/Modules/Faq/Widgets/AskOwnQuestion.php index cb12f8af8d..a366a92874 100644 --- a/src/Frontend/Modules/Faq/Widgets/AskOwnQuestion.php +++ b/src/Frontend/Modules/Faq/Widgets/AskOwnQuestion.php @@ -2,12 +2,11 @@ namespace Frontend\Modules\Faq\Widgets; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Core\Engine\Base\Widget as FrontendBaseWidget; use Frontend\Core\Engine\Form as FrontendForm; use Frontend\Core\Language\Language as FL; -use Frontend\Core\Engine\Model as FrontendModel; -use Frontend\Core\Engine\Navigation as FrontendNavigation; +use Symfony\Component\Mailer\MailerInterface; /** * This is a widget with the form to ask a question @@ -82,7 +81,7 @@ private function getSubmittedQuestion(): array return [ 'sentOn' => time(), 'name' => $this->form->getField('name')->getValue(), - 'email' => $this->form->getField('email')->getValue(), + 'emailaddress' => $this->form->getField('email')->getValue(), 'message' => $this->form->getField('message')->getValue(), ]; } @@ -101,18 +100,14 @@ private function handleForm(): void private function sendNewQuestionNotification(array $question): void { - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $to = $this->get('fork.settings')->get('Core', 'mailer_to'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(sprintf(FL::getMessage('FaqOwnQuestionSubject'), $question['name'])) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Faq/Layout/Templates/Mails/OwnQuestion.html.twig', - $question, - true - ); - $this->get('mailer')->send($message); + /** @var EmailFactory $emailFactory */ + $emailFactory = $this->get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = $this->get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(sprintf(FL::getMessage('FaqOwnQuestionSubject'), $question['name'])) + ->htmlTemplate('/Faq/Layout/Templates/Mails/OwnQuestion.html.twig') + ->context($question); + $mailer->send($message); } } diff --git a/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php b/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php index c55c5a607f..c82e907e60 100644 --- a/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php +++ b/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php @@ -2,13 +2,15 @@ namespace Frontend\Modules\Profiles\Actions; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Core\Engine\Base\Block as FrontendBaseBlock; use Frontend\Core\Engine\Form as FrontendForm; use Frontend\Core\Language\Language as FL; use Frontend\Core\Engine\Navigation as FrontendNavigation; use Frontend\Modules\Profiles\Engine\Authentication as FrontendProfilesAuthentication; use Frontend\Modules\Profiles\Engine\Model as FrontendProfilesModel; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; /** * Request a reset password email. @@ -40,8 +42,7 @@ private function buildForm(): void ->addText('email') ->setAttribute('type', 'email') ->setAttribute('autocomplete', 'email') - ->makeRequired() - ; + ->makeRequired(); } private function parse(): void @@ -98,21 +99,21 @@ private function handleForm(): void private function sendForgotPasswordEmail(int $profileId, string $resetUrl): void { - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(FL::getMessage('ForgotPasswordSubject')) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$this->form->getField('email')->getValue() => '']) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Profiles/Layout/Templates/Mails/ForgotPassword.html.twig', - [ + /** @var EmailFactory $emailFactory */ + $emailFactory = $this->get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = $this->get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(FL::getMessage('ForgotPasswordSubject')) + ->to(new Address($this->form->getField('email')->getValue())) + ->htmlTemplate('/Profiles/Layout/Templates/Mails/ForgotPassword.html.twig') + ->context([ 'resetUrl' => $resetUrl, 'firstName' => FrontendProfilesModel::getSetting($profileId, 'first_name'), 'lastName' => FrontendProfilesModel::getSetting($profileId, 'last_name'), - ], - true + ] ); - $this->get('mailer')->send($message); + + $mailer->send($message); } } diff --git a/src/Frontend/Modules/Profiles/Actions/Register.php b/src/Frontend/Modules/Profiles/Actions/Register.php index 830182ac57..402ed16290 100644 --- a/src/Frontend/Modules/Profiles/Actions/Register.php +++ b/src/Frontend/Modules/Profiles/Actions/Register.php @@ -2,7 +2,7 @@ namespace Frontend\Modules\Profiles\Actions; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Core\Engine\Base\Block as FrontendBaseBlock; use Frontend\Core\Engine\Form as FrontendForm; use Frontend\Core\Language\Language as FL; @@ -10,6 +10,8 @@ use Frontend\Core\Engine\Navigation as FrontendNavigation; use Frontend\Modules\Profiles\Engine\Authentication as FrontendProfilesAuthentication; use Frontend\Modules\Profiles\Engine\Model as FrontendProfilesModel; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; class Register extends FrontendBaseBlock { @@ -130,18 +132,22 @@ private function handleForm(): void private function sendActivationEmail(array $profile, string $activationKey): void { - $activationUrl = SITE_URL . FrontendNavigation::getUrlForBlock($this->getModule(), 'Activate'); - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(FL::getMessage('RegisterSubject')) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$profile['email'] => $profile['display_name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - 'Profiles/Layout/Templates/Mails/Register.html.twig', - ['activationUrl' => $activationUrl . '/' . $activationKey], - true + /** @var EmailFactory $emailFactory */ + $emailFactory = $this->get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = $this->get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(FL::getMessage('RegisterSubject')) + ->to(new Address($profile['email'], $profile['display_name'])) + ->htmlTemplate('Profiles/Layout/Templates/Mails/Register.html.twig') + ->context([ + 'activationUrl' => SITE_URL . + FrontendNavigation::getUrlForBlock( + $this->getModule(), + 'Activate' + ) . '/' . $activationKey + ] ); - $this->get('mailer')->send($message); + $mailer->send($message); } } diff --git a/src/Frontend/Modules/Profiles/Actions/ResendActivation.php b/src/Frontend/Modules/Profiles/Actions/ResendActivation.php index 7dc8b998c2..752dbc09be 100644 --- a/src/Frontend/Modules/Profiles/Actions/ResendActivation.php +++ b/src/Frontend/Modules/Profiles/Actions/ResendActivation.php @@ -2,7 +2,7 @@ namespace Frontend\Modules\Profiles\Actions; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Core\Engine\Base\Block as FrontendBaseBlock; use Frontend\Core\Engine\Form as FrontendForm; use Frontend\Core\Language\Language as FL; @@ -11,6 +11,8 @@ use Frontend\Modules\Profiles\Engine\Model as FrontendProfilesModel; use Frontend\Modules\Profiles\Engine\Profile; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; /** * This is the resend activation-action. It will resend your activation email. @@ -102,19 +104,20 @@ private function handleForm(): void private function resendActivationEmail(): void { - $activationUrl = SITE_URL . FrontendNavigation::getUrlForBlock($this->getModule(), 'Activate') - . '/' . $this->profile->getSetting('activation_key'); - $from = $this->get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = $this->get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance(FL::getMessage('RegisterSubject')) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$this->profile->getEmail() => $this->profile->getDisplayName()]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - 'Profiles/Layout/Templates/Mails/Register.html.twig', - ['activationUrl' => $activationUrl], - true + /** @var EmailFactory $emailFactory */ + $emailFactory = $this->get(EmailFactory::class); + /** @var MailerInterface $mailer */ + $mailer = $this->get(MailerInterface::class); + $message = $emailFactory->create() + ->subject(FL::getMessage('RegisterSubject')) + ->to(new Address($this->profile->getEmail(), $this->profile->getDisplayName())) + ->htmlTemplate('Profiles/Layout/Templates/Mails/Register.html.twig') + ->context([ + 'activationUrl' => SITE_URL . FrontendNavigation::getUrlForBlock($this->getModule(), 'Activate') + . '/' . $this->profile->getSetting('activation_key') + ] ); - $this->get('mailer')->send($message); + + $mailer->send($message); } } diff --git a/src/Frontend/Themes/Bootstrap/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig b/src/Frontend/Themes/Bootstrap/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig index 3c4180c825..7d04cb2a53 100644 --- a/src/Frontend/Themes/Bootstrap/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig +++ b/src/Frontend/Themes/Bootstrap/Modules/Faq/Layout/Templates/Mails/OwnQuestion.html.twig @@ -6,6 +6,6 @@

{{ 'lbl.SentOn'|trans|ucfirst }}:
{{ sentOn|spoondate(dateFormatLong, LANGUAGE) }}

{{ 'lbl.Content'|trans|ucfirst }}

{{ 'lbl.Name'|trans|ucfirst }}:
{{ name }}

-

{{ 'lbl.Email'|trans|ucfirst }}:
{{ email }}

+

{{ 'lbl.Email'|trans|ucfirst }}:
{{ emailaddress }}

{{ 'lbl.Question'|trans|ucfirst }}:
{{ message }}

{% endblock %} From 4b50d7ab2db7de1ce199692658eaecf7635711c4 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:25:13 +0100 Subject: [PATCH 08/16] fix: make FormBuilderSubmittedMailSubscriber work again --- .../Modules/FormBuilder/Resources/config/services.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Backend/Modules/FormBuilder/Resources/config/services.yml b/src/Backend/Modules/FormBuilder/Resources/config/services.yml index 651148c703..ecf91c2e3c 100644 --- a/src/Backend/Modules/FormBuilder/Resources/config/services.yml +++ b/src/Backend/Modules/FormBuilder/Resources/config/services.yml @@ -8,4 +8,8 @@ services: - "@mailer" - "@fork.settings" tags: - - { name: kernel.event_listener, event: form.submitted, method: onFormSubmitted } + - { + name: kernel.event_listener, + event: Frontend\Modules\FormBuilder\Event\FormBuilderSubmittedEvent, + method: onFormSubmitted + } From 7df6911a16277527196b663a4b1d8b4ff848c7f0 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:26:06 +0100 Subject: [PATCH 09/16] feat: use new way of sending mails in FormBuilderSubmittedMailSubscriber --- .../FormBuilder/Resources/config/services.yml | 4 +- .../FormBuilderSubmittedMailSubscriber.php | 99 +++++++------------ 2 files changed, 37 insertions(+), 66 deletions(-) diff --git a/src/Backend/Modules/FormBuilder/Resources/config/services.yml b/src/Backend/Modules/FormBuilder/Resources/config/services.yml index ecf91c2e3c..33f123e724 100644 --- a/src/Backend/Modules/FormBuilder/Resources/config/services.yml +++ b/src/Backend/Modules/FormBuilder/Resources/config/services.yml @@ -5,8 +5,8 @@ services: formbuilder.submitted.mailer: class: Frontend\Modules\FormBuilder\EventListener\FormBuilderSubmittedMailSubscriber arguments: - - "@mailer" - - "@fork.settings" + - "@mailer.mailer" + - '@Common\Mailer\EmailFactory' tags: - { name: kernel.event_listener, diff --git a/src/Frontend/Modules/FormBuilder/EventListener/FormBuilderSubmittedMailSubscriber.php b/src/Frontend/Modules/FormBuilder/EventListener/FormBuilderSubmittedMailSubscriber.php index 3a0d52da82..388b973c0e 100644 --- a/src/Frontend/Modules/FormBuilder/EventListener/FormBuilderSubmittedMailSubscriber.php +++ b/src/Frontend/Modules/FormBuilder/EventListener/FormBuilderSubmittedMailSubscriber.php @@ -2,21 +2,22 @@ namespace Frontend\Modules\FormBuilder\EventListener; -use Common\Mailer\Message; -use Swift_Mailer; -use Common\ModulesSettings; +use Common\Mailer\EmailFactory; use Frontend\Core\Language\Language; -use Frontend\Core\Engine\Model as FrontendModel; use Frontend\Modules\FormBuilder\Event\FormBuilderSubmittedEvent; -use Swift_Mime_SimpleMessage; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; /** * A Formbuilder submitted event subscriber that will send an email if needed */ final class FormBuilderSubmittedMailSubscriber { - public function __construct(protected Swift_Mailer $mailer, protected ModulesSettings $modulesSettings) - { + public function __construct( + protected MailerInterface $mailer, + protected EmailFactory $emailFactory, + ) { } public function onFormSubmitted(FormBuilderSubmittedEvent $event): void @@ -34,82 +35,52 @@ public function onFormSubmitted(FormBuilderSubmittedEvent $event): void if (array_key_exists('send_confirmation_mail_to', $field['settings']) && $field['settings']['send_confirmation_mail_to'] === true ) { - $to = $fieldData[$field['id']]['value']; - $from = FrontendModel::get('fork.settings')->get('Core', 'mailer_from'); - $replyTo = FrontendModel::get('fork.settings')->get('Core', 'mailer_reply_to'); - $message = Message::newInstance($field['settings']['confirmation_mail_subject']) - ->setFrom([$from['email'] => $from['name']]) - ->setTo($to) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - '/Core/Layout/Templates/Mails/Notification.html.twig', - ['message' => $field['settings']['confirmation_mail_message']], - true - ) - ; + $message = $this->emailFactory->create() + ->subject($field['settings']['confirmation_mail_subject']) + ->to(new Address($fieldData[$field['id']]['value'])) + ->htmlTemplate('/Core/Layout/Templates/Mails/Notification.html.twig') + ->context([ + 'message' => $field['settings']['confirmation_mail_message'], + ]); $this->mailer->send($message); } } } - /** - * @param array $form - * @param array $fieldData - * @param string $subject - * @param string|array|null $to - * @param bool $isConfirmationMail - * - * @return Swift_Mime_SimpleMessage - */ private function getMessage( array $form, array $fieldData, - ?string $subject = null, - $to = null, - bool $isConfirmationMail = false - ) : Swift_Mime_SimpleMessage { + ?string $subject = null + ): TemplatedEmail { if ($subject === null) { $subject = Language::getMessage('FormBuilderSubject'); } - $from = $this->modulesSettings->get('Core', 'mailer_from'); + $message = $this->emailFactory->create() + ->subject(sprintf($subject, $form['name'])) + ->htmlTemplate('/FormBuilder/Layout/Templates/Mails/' . $form['email_template']) + ->context([ + 'subject' => $subject, + 'sentOn' => time(), + 'name' => $form['name'], + 'fields' => array_map( + function (array $field): array { + $field['value'] = html_entity_decode((string) $field['value']); - $message = Message::newInstance(sprintf($subject, $form['name'])) - ->parseHtml( - '/FormBuilder/Layout/Templates/Mails/' . $form['email_template'], - [ - 'subject' => $subject, - 'sentOn' => time(), - 'name' => $form['name'], - 'fields' => array_map( - function (array $field) : array { - $field['value'] = html_entity_decode((string) $field['value']); - - return $field; - }, - $fieldData - ), - 'is_confirmation_mail' => $isConfirmationMail, - ], - true - ) - ->setTo($to ?? $form['email']) - ->setFrom([$from['email'] => $from['name']]) - ; + return $field; + }, + $fieldData + ) + ]); // check if we have a replyTo email set foreach ($form['fields'] as $field) { if (array_key_exists('reply_to', $field['settings']) && $field['settings']['reply_to'] === true ) { - $email = $fieldData[$field['id']]['value']; - $message->setReplyTo([$email => $email]); + $message->replyTo(new Address($fieldData[$field['id']]['value'])); } } - if (empty($message->getReplyTo())) { - $replyTo = $this->modulesSettings->get('Core', 'mailer_reply_to'); - $message->setReplyTo([$replyTo['email'] => $replyTo['name']]); - } return $message; } @@ -124,13 +95,13 @@ function (array $field) : array { protected function getEmailFields(array $data): array { return array_map( - function ($item) : array { + function ($item): array { $value = unserialize($item['value'], ['allowed_classes' => false]); return [ 'label' => $item['label'], 'value' => ( - is_array($value) + is_array($value) ? implode(',', $value) : nl2br($value) ), From c3b52d7e961b88e68fdf110eeaf9c09b73aab9c1 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:47:35 +0100 Subject: [PATCH 10/16] feat: use new way of sending mails in Mailmotor listeners --- .../Resources/config/eventListeners.yml | 32 ++++++++++++----- ...wNotImplementedMailingListSubscription.php | 35 ++++++------------- ...otImplementedMailingListUnsubscription.php | 35 ++++++------------- 3 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/Backend/Modules/Mailmotor/Resources/config/eventListeners.yml b/src/Backend/Modules/Mailmotor/Resources/config/eventListeners.yml index 200236eff9..6fc35901af 100755 --- a/src/Backend/Modules/Mailmotor/Resources/config/eventListeners.yml +++ b/src/Backend/Modules/Mailmotor/Resources/config/eventListeners.yml @@ -4,25 +4,41 @@ services: arguments: - "%kernel.cache_dir%" tags: - - { name: kernel.event_listener, event: mailmotor.event.settings_saved, method: onSettingsSavedEvent } + - { + name: kernel.event_listener, + event: Backend\Modules\Mailmotor\Domain\Settings\Event\SettingsSavedEvent, + method: onSettingsSavedEvent + } mailmotor.listener.subscribed: class: Frontend\Modules\Mailmotor\EventListener\NewNotImplementedMailingListSubscription arguments: - - "@mailer" - - "@fork.settings" + - "@mailer.mailer" + - '@Common\Mailer\EmailFactory' tags: - - { name: kernel.event_listener, event: mailmotor.event.not_implemented.subscribed, method: onNotImplementedSubscribedEvent } + - { + name: kernel.event_listener, + event: Frontend\Modules\Mailmotor\Domain\Subscription\Event\NotImplementedSubscribedEvent, + method: onNotImplementedSubscribedEvent + } mailmotor.listener.unsubscribed: class: Frontend\Modules\Mailmotor\EventListener\NewNotImplementedMailingListUnsubscription arguments: - - "@mailer" - - "@fork.settings" + - "@mailer.mailer" + - '@Common\Mailer\EmailFactory' tags: - - { name: kernel.event_listener, event: mailmotor.event.not_implemented.unsubscribed, method: onNotImplementedUnsubscribedEvent } + - { + name: kernel.event_listener, + event: Frontend\Modules\Mailmotor\Domain\Subscription\Event\NotImplementedUnsubscribedEvent, + method: onNotImplementedUnsubscribedEvent + } Frontend\Modules\Mailmotor\EventListener\FormBuilderSubmittedMailmotorSubscriber: arguments: - "@fork.settings" - "@mailmotor.subscriber" tags: - - { name: kernel.event_listener, event: form.submitted, method: onFormSubmitted } + - { + name: kernel.event_listener, + event: Frontend\Modules\FormBuilder\Event\FormBuilderSubmittedEvent, + method: onFormSubmitted + } diff --git a/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListSubscription.php b/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListSubscription.php index ae13b14849..c905531363 100644 --- a/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListSubscription.php +++ b/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListSubscription.php @@ -3,10 +3,9 @@ namespace Frontend\Modules\Mailmotor\EventListener; use Common\Language; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Modules\Mailmotor\Domain\Subscription\Event\NotImplementedSubscribedEvent; -use Swift_Mailer; -use Common\ModulesSettings; +use Symfony\Component\Mailer\MailerInterface; /** * New mailing list subscription @@ -18,36 +17,24 @@ final readonly class NewNotImplementedMailingListSubscription { public function __construct( - private Swift_Mailer $mailer, - private ModulesSettings $modulesSettings, + protected MailerInterface $mailer, + protected EmailFactory $emailFactory, ) { } public function onNotImplementedSubscribedEvent(NotImplementedSubscribedEvent $event): void { - $title = sprintf( + $subject = sprintf( Language::lbl('MailTitleSubscribeSubscriber'), $event->getSubscription()->email, strtoupper((string) $event->getSubscription()->locale) ); - - $to = $this->modulesSettings->get('Core', 'mailer_to'); - $from = $this->modulesSettings->get('Core', 'mailer_from'); - $replyTo = $this->modulesSettings->get('Core', 'mailer_reply_to'); - - $message = Message::newInstance($title) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - FRONTEND_CORE_PATH . '/Layout/Templates/Mails/Notification.html.twig', - [ - 'message' => $title, - ], - true - ) - ; - + $message = $this->emailFactory->create() + ->subject($subject) + ->htmlTemplate('/Core/Layout/Templates/Mails/Notification.html.twig') + ->context([ + 'message' => $subject, + ]); $this->mailer->send($message); } } diff --git a/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListUnsubscription.php b/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListUnsubscription.php index 524813bd49..c5e0904fa8 100644 --- a/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListUnsubscription.php +++ b/src/Frontend/Modules/Mailmotor/EventListener/NewNotImplementedMailingListUnsubscription.php @@ -3,10 +3,9 @@ namespace Frontend\Modules\Mailmotor\EventListener; use Common\Language; -use Common\Mailer\Message; +use Common\Mailer\EmailFactory; use Frontend\Modules\Mailmotor\Domain\Subscription\Event\NotImplementedUnsubscribedEvent; -use Swift_Mailer; -use Common\ModulesSettings; +use Symfony\Component\Mailer\MailerInterface; /** * New mailing list unsubscription @@ -18,36 +17,24 @@ final readonly class NewNotImplementedMailingListUnsubscription { public function __construct( - private Swift_Mailer $mailer, - private ModulesSettings $modulesSettings, + protected MailerInterface $mailer, + protected EmailFactory $emailFactory, ) { } public function onNotImplementedUnsubscribedEvent(NotImplementedUnsubscribedEvent $event): void { - $title = sprintf( + $subject = sprintf( Language::lbl('MailTitleUnsubscribeSubscriber'), $event->getUnsubscription()->email, strtoupper((string) $event->getUnsubscription()->locale) ); - - $to = $this->modulesSettings->get('Core', 'mailer_to'); - $from = $this->modulesSettings->get('Core', 'mailer_from'); - $replyTo = $this->modulesSettings->get('Core', 'mailer_reply_to'); - - $message = Message::newInstance($title) - ->setFrom([$from['email'] => $from['name']]) - ->setTo([$to['email'] => $to['name']]) - ->setReplyTo([$replyTo['email'] => $replyTo['name']]) - ->parseHtml( - FRONTEND_CORE_PATH . '/Layout/Templates/Mails/Notification.html.twig', - [ - 'message' => $title, - ], - true - ) - ; - + $message = $this->emailFactory->create() + ->subject($subject) + ->htmlTemplate('/Core/Layout/Templates/Mails/Notification.html.twig') + ->context([ + 'message' => $subject, + ]); $this->mailer->send($message); } } From 434493b129b82403619df0af0be8c49b94136529 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:48:54 +0100 Subject: [PATCH 11/16] feat: inline styles --- src/Common/Mailer/Message.php | 196 - .../Layout/Templates/Mails/Default.html.twig | 3180 +++++++++-------- .../Layout/Templates/Mails/Default.html.twig | 3102 ++++++++-------- 3 files changed, 3185 insertions(+), 3293 deletions(-) delete mode 100644 src/Common/Mailer/Message.php diff --git a/src/Common/Mailer/Message.php b/src/Common/Mailer/Message.php deleted file mode 100644 index 9d089acc57..0000000000 --- a/src/Common/Mailer/Message.php +++ /dev/null @@ -1,196 +0,0 @@ -getTemplateContent($template, $variables); - $html = $this->relativeToAbsolute($html); - $html = $this->cssToInlineStyles($html); - - if ($addUTM === true) { - $html = $this->addUTM($html, $this->getSubject()); - } - - $this->setBody($html, 'text/html'); - - return $this; - } - - /** - * Attach multiple attachments to this message - * - * @param array $attachments - * - * @return Message - */ - public function addAttachments(array $attachments): Message - { - if (!empty($attachments)) { - // add attachments one by one - foreach ($attachments as $attachment) { - // only add existing files - if (is_file($attachment)) { - $this->attach(\Swift_Attachment::fromPath($attachment)); - } - } - } - - return $this; - } - - /** - * Add plaintext content as fallback for the html - * - * @param string $content - * - * @return Message - */ - public function setPlainText(string $content): Message - { - if (!empty($content)) { - $this->addPart($content, 'text/plain'); - } - - return $this; - } - - /** - * @param string $html The html to convert links in. - * @param string $subject The subject of the mail - * - * @return string - */ - private function addUTM(string $html, string $subject): string - { - // match links - $matches = []; - preg_match_all('/href="(http:\/\/(.*))"/iU', $html, $matches); - - // any links? - $utm = [ - 'utm_source' => 'mail', - 'utm_medium' => 'email', - 'utm_campaign' => Uri::getUrl($subject), - ]; - if (isset($matches[0]) && !empty($matches[0])) { - $searchLinks = []; - $replaceLinks = []; - - // loop old links - foreach ($matches[1] as $i => $link) { - $searchLinks[] = $matches[0][$i]; - $replaceLinks[] = 'href="' . Model::addUrlParameters($link, $utm) . '"'; - } - - $html = str_replace($searchLinks, $replaceLinks, $html); - } - - return $html; - } - - /** - * Returns the content from a given template - * - * @param string $template The template to use. - * @param array $variables The variables to assign. - * - * @return string - */ - private function getTemplateContent(string $template, ?array $variables = null): string - { - // with the strpos we check if it is a frontend template, in that case we use the frontend template to prevent - // errors that the template could not be found. This way we don't have a backwards compatibility break. - if (APPLICATION !== 'Backend' || str_contains($template, FRONTEND_CORE_PATH)) { - return Model::get('templating')->render( - $template, - $variables - ); - } - - $tpl = new BackendTemplate(false); - - // variables were set - if (!empty($variables)) { - $tpl->assignArray($variables); - } - - // grab the content - return $tpl->getContent($template); - } - - /** - * Converts all css to inline styles - * - * @param string $html - * - * @return string - */ - private function cssToInlineStyles(string $html): string - { - $cssToInlineStyles = new CssToInlineStyles(); - - return (string) $cssToInlineStyles->convert( - $html - ); - } - - /** - * Replace internal links and images to absolute links - * - * @param string $html The html to convert links in. - * - * @return string - */ - private function relativeToAbsolute(string $html): string - { - // replace internal links/images - $search = ['href="/', 'src="/']; - $replace = ['href="' . SITE_URL . '/', 'src="' . SITE_URL . '/']; - - return str_replace($search, $replace, $html); - } -} diff --git a/src/Frontend/Core/Layout/Templates/Mails/Default.html.twig b/src/Frontend/Core/Layout/Templates/Mails/Default.html.twig index e33b2922e5..b121c5e268 100644 --- a/src/Frontend/Core/Layout/Templates/Mails/Default.html.twig +++ b/src/Frontend/Core/Layout/Templates/Mails/Default.html.twig @@ -1,1589 +1,1591 @@ - - - - - - - {% block title %} - {{ SITE_TITLE }} - {% endblock %} - - - - - - - - - -
-
- - - - - - -
 
- - - - - - - -
- - - - - - -
 
- - - - - - - -
- - - - - -
-

-
{{ SITE_TITLE }}
-

-
-
-
- - - - - - - -
- - - - - - -
 
- - - - - - - -
- - - - - -
- {% block main %} - - {% endblock %} -
-
-
- - - - - - - -
 
- -
-
- -
                                                           
- - - - - +{% apply inline_css %} + {% apply utm('mail', 'email', (email.subject ?? 'unknown')|slug)|inline_css %} + + + + + + {% block title %} + {{ SITE_TITLE }} - {{ email.subject }} + {% endblock %} + + + + + + + + + +
+
+ + + + + + +
 
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+

+
{{ SITE_TITLE }}
+

+
+
+
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+ {% block main %} + + {% endblock %} +
+
+
+ + + + + + + +
 
+ +
+
+ +
                                                           
+ + + + + {% endapply %} +{% endapply %} diff --git a/src/Frontend/Themes/Bootstrap/src/Layout/Templates/Mails/Default.html.twig b/src/Frontend/Themes/Bootstrap/src/Layout/Templates/Mails/Default.html.twig index bfa4afa2c8..1f309bc99e 100644 --- a/src/Frontend/Themes/Bootstrap/src/Layout/Templates/Mails/Default.html.twig +++ b/src/Frontend/Themes/Bootstrap/src/Layout/Templates/Mails/Default.html.twig @@ -1,1508 +1,1594 @@ - - - - - - - {% block title %} - {{ SITE_TITLE }} - {% endblock %} - - - - - - - - - -
-
- - - - - - -
 
- - - - - - - -
- - - - - - -
 
- - - - - - - -
- - - - - -
-
- {# make sure you logo will also be visible on dark backgrounds for mail clients that invert colors in dark mode #} - logo {{ SITE_TITLE }} -
-
-
-
- - - - - - - -
- - - - - - -
 
- - - - - - - -
- - - - - -
- {% block main %} - - {% endblock %} -
-
-
- - - - - - - -
 
- -
-
- -
                                                           
- - - - - +{% apply inline_css %} + {% apply utm('mail', 'email', (email.subject ?? 'unknown')|slug)|inline_css %} + + + + + + + {% block title %} + {{ SITE_TITLE }} + {% endblock %} + + + + + + + + + +
+
+ + + + + + +
 
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+
+ {# make sure you logo will also be visible on dark backgrounds for mail clients that invert colors in dark mode #} + logo {{ SITE_TITLE }} +
+
+
+
+ + + + + + + +
+ + + + + + +
 
+ + + + + + + +
+ + + + + +
+ {% block main %} + + {% endblock %} +
+
+
+ + + + + + + +
 
+ +
+
+ +
                                                           
+ + + + + + {% endapply %} +{% endapply %} From d03015198660934ab684015af67228a3830a03b3 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Fri, 27 Feb 2026 16:49:24 +0100 Subject: [PATCH 12/16] chore: cleanup unused code --- composer.json | 1 - src/Common/Mailer/TransportFactory.php | 64 ----------- src/Common/Tests/Mailer/ConfiguratorTest.php | 102 ------------------ .../Tests/Mailer/TransportFactoryTest.php | 43 -------- 4 files changed, 210 deletions(-) delete mode 100644 src/Common/Mailer/TransportFactory.php delete mode 100644 src/Common/Tests/Mailer/ConfiguratorTest.php delete mode 100644 src/Common/Tests/Mailer/TransportFactoryTest.php diff --git a/composer.json b/composer.json index f6564c43f6..66a2c64023 100644 --- a/composer.json +++ b/composer.json @@ -52,7 +52,6 @@ "symfony/expression-language": "^5.4", "symfony/translation": "^5.4", "symfony/intl": "^5.4", - "tijsverkoyen/css-to-inline-styles": "^2.0", "phpoffice/phpspreadsheet": "^5.4", "guzzlehttp/guzzle": "^7.10", "doctrine/annotations": "^1.14", diff --git a/src/Common/Mailer/TransportFactory.php b/src/Common/Mailer/TransportFactory.php deleted file mode 100644 index d433542ce7..0000000000 --- a/src/Common/Mailer/TransportFactory.php +++ /dev/null @@ -1,64 +0,0 @@ -setUsername($user) - ->setPassword($pass); - - if (in_array($encryption, ['ssl', 'tls'], true)) { - $transport->setEncryption($encryption); - } - - return $transport; - } - - private static function getMailTransport(): Swift_SendmailTransport - { - return new Swift_SendmailTransport(); - } -} diff --git a/src/Common/Tests/Mailer/ConfiguratorTest.php b/src/Common/Tests/Mailer/ConfiguratorTest.php deleted file mode 100644 index 975ab9eda6..0000000000 --- a/src/Common/Tests/Mailer/ConfiguratorTest.php +++ /dev/null @@ -1,102 +0,0 @@ -getModulesSettingsMock(); - $containerMock = - $this->getContainerMock(); - - $configurator = new Configurator( - $modulesSettingsMock, - $containerMock - ); - - // always return null: we have no modules settings set - $modulesSettingsMock - ->expects($this->exactly(6)) - ->method('get') - ->will($this->returnValue(null)) - ; - - // we want our set method to be called with a Mail transport - $containerMock - ->expects($this->once()) - ->method('set') - ->with( - $this->equalTo('swiftmailer.transport'), - $this->isInstanceOf('\Swift_SendmailTransport') - ) - ; - - $configurator->onKernelRequest($this->getRequestEventMock()); - } - - public function testConfiguratorSetsSmtpTransport(): void - { - $modulesSettingsMock = $this->getModulesSettingsMock(); - $containerMock = - $this->getContainerMock(); - - $configurator = new Configurator( - $modulesSettingsMock, - $containerMock - ); - - // always return null: we have modules settings set for smtp - $modulesSettingsMock - ->expects($this->exactly(6)) - ->method('get') - ->will($this->onConsecutiveCalls( - 'smtp', - 'test.server.com', - 25, - 'test@server.com', - 'testpass' - )) - ; - - // we want our set method to be called with a Smtp transport - $containerMock - ->expects($this->once()) - ->method('set') - ->with( - $this->equalTo('swiftmailer.transport'), - $this->isInstanceOf('\Swift_SmtpTransport') - ) - ; - - $configurator->onKernelRequest($this->getRequestEventMock()); - } - - private function getModulesSettingsMock(): MockObject - { - return $this->createMock(\Common\ModulesSettings::class); - } - - private function getContainerMock(): MockObject - { - return $this->getMockBuilder(\Symfony\Component\DependencyInjection\ContainerInterface::class) - ->disableOriginalConstructor() - ->getMock() - ; - } - - private function getRequestEventMock(): MockObject - { - return $this->getMockBuilder(\Symfony\Component\HttpKernel\Event\RequestEvent::class) - ->disableOriginalConstructor() - ->getMock() - ; - } -} diff --git a/src/Common/Tests/Mailer/TransportFactoryTest.php b/src/Common/Tests/Mailer/TransportFactoryTest.php deleted file mode 100644 index f0008dedea..0000000000 --- a/src/Common/Tests/Mailer/TransportFactoryTest.php +++ /dev/null @@ -1,43 +0,0 @@ -getEncryption() - ); - - $transport = TransportFactory::create('smtp', null, 21, null, null, 'tls'); - self::assertEquals( - 'tls', - $transport->getEncryption() - ); - } -} From 33245eb37c4f6319310805872ebc7bbb580cde15 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Tue, 3 Mar 2026 07:59:11 +0100 Subject: [PATCH 13/16] =?UTF-8?q?chore:=20update=20fslightbox=20(3.7.4=20?= =?UTF-8?q?=E2=86=92=203.7.5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index d8448dfda1..2e963538be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9119,9 +9119,9 @@ } }, "node_modules/fslightbox": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.7.4.tgz", - "integrity": "sha512-zQqMHxiYkR0W/xrWQlchoO626C5KCM6rabpMWiJsy+MZCMHo7zlywsGAOGeOahRUqBZzXT9OeMddiVSfW77gaA==" + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.7.5.tgz", + "integrity": "sha512-swEUrwMOyiBhdkPf3GXj4nxARX5d8/9yfVCdxgPLl9+ZMiacUTub9O2wxLI0Y2G2jI85Qxfqpv2I24vlbx0zfg==" }, "node_modules/function-bind": { "version": "1.1.2", @@ -27307,9 +27307,9 @@ "optional": true }, "fslightbox": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.7.4.tgz", - "integrity": "sha512-zQqMHxiYkR0W/xrWQlchoO626C5KCM6rabpMWiJsy+MZCMHo7zlywsGAOGeOahRUqBZzXT9OeMddiVSfW77gaA==" + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.7.5.tgz", + "integrity": "sha512-swEUrwMOyiBhdkPf3GXj4nxARX5d8/9yfVCdxgPLl9+ZMiacUTub9O2wxLI0Y2G2jI85Qxfqpv2I24vlbx0zfg==" }, "function-bind": { "version": "1.1.2", From 8363aa848aca18e22479dfe00704e8d6425e2956 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Tue, 3 Mar 2026 08:01:53 +0100 Subject: [PATCH 14/16] chore: remove swiftmailer/swiftmailer as it is replaced by symfony/mailer --- app/AppKernel.php | 1 - composer.json | 2 -- 2 files changed, 3 deletions(-) diff --git a/app/AppKernel.php b/app/AppKernel.php index 0ad939cedb..597ac8b3c2 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -19,7 +19,6 @@ public function registerBundles(): array new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(), new \Symfony\Bundle\TwigBundle\TwigBundle(), new \Symfony\Bundle\MonologBundle\MonologBundle(), - new \Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new \ForkCMS\Bundle\InstallerBundle\ForkCMSInstallerBundle(), new \ForkCMS\Bundle\CoreBundle\ForkCMSCoreBundle(), new \Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), diff --git a/composer.json b/composer.json index 66a2c64023..a02843b8a4 100644 --- a/composer.json +++ b/composer.json @@ -37,9 +37,7 @@ "simple-bus/doctrine-orm-bridge": "6.2.*", "simple-bus/symfony-bridge": "~6.2", "spoon/library": "^4.0", - "swiftmailer/swiftmailer": "^6.0", "symfony/monolog-bundle": "^3.1", - "symfony/swiftmailer-bundle": "^3.0", "symfony/console": "^5.4", "symfony/dotenv": "^5.4", "symfony/framework-bundle": "^5.4", From 2af6caaf6822850aa9d791179894b6a9ae0228a8 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Tue, 3 Mar 2026 08:05:55 +0100 Subject: [PATCH 15/16] chore: fix PHPCS issues --- src/Backend/Modules/Authentication/Actions/Index.php | 8 ++++++-- src/Frontend/Modules/Profiles/Actions/ForgotPassword.php | 3 ++- src/Frontend/Modules/Profiles/Actions/Register.php | 3 ++- .../Modules/Profiles/Actions/ResendActivation.php | 8 ++++---- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Backend/Modules/Authentication/Actions/Index.php b/src/Backend/Modules/Authentication/Actions/Index.php index 38a3b3a280..9f11f97cbe 100644 --- a/src/Backend/Modules/Authentication/Actions/Index.php +++ b/src/Backend/Modules/Authentication/Actions/Index.php @@ -108,7 +108,10 @@ private function validateForm(): void $userId = BackendUsersModel::getIdByEmail($txtEmail->getValue()); // all fields are ok? - if ($txtEmail->isFilled() && $txtPassword->isFilled() && $this->form->getToken() == $this->form->getField('form_token')->getValue()) { + if ($txtEmail->isFilled() + && $txtPassword->isFilled() + && $this->form->getToken() == $this->form->getField('form_token')->getValue() + ) { // try to login the user if (!BackendAuthentication::loginUser($txtEmail->getValue(), $txtPassword->getValue())) { $this->getContainer()->get('logger.public')->info( @@ -222,7 +225,8 @@ private function validateForm(): void ->subject(s(BL::msg('ResetYourPasswordMailSubject'))->title()->toString()) ->to(new Address($email)) ->htmlTemplate('@ForkBackendModules/Authentication/Layout/Templates/Mails/ResetPassword.html.twig') - ->context([ + ->context( + [ 'resetLink' => SITE_URL . BackendModel::createUrlForAction('ResetPassword') . '&email=' . $email . '&key=' . $key, ] diff --git a/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php b/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php index c82e907e60..f6c58c3302 100644 --- a/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php +++ b/src/Frontend/Modules/Profiles/Actions/ForgotPassword.php @@ -107,7 +107,8 @@ private function sendForgotPasswordEmail(int $profileId, string $resetUrl): void ->subject(FL::getMessage('ForgotPasswordSubject')) ->to(new Address($this->form->getField('email')->getValue())) ->htmlTemplate('/Profiles/Layout/Templates/Mails/ForgotPassword.html.twig') - ->context([ + ->context( + [ 'resetUrl' => $resetUrl, 'firstName' => FrontendProfilesModel::getSetting($profileId, 'first_name'), 'lastName' => FrontendProfilesModel::getSetting($profileId, 'last_name'), diff --git a/src/Frontend/Modules/Profiles/Actions/Register.php b/src/Frontend/Modules/Profiles/Actions/Register.php index 402ed16290..13656feb9c 100644 --- a/src/Frontend/Modules/Profiles/Actions/Register.php +++ b/src/Frontend/Modules/Profiles/Actions/Register.php @@ -140,7 +140,8 @@ private function sendActivationEmail(array $profile, string $activationKey): voi ->subject(FL::getMessage('RegisterSubject')) ->to(new Address($profile['email'], $profile['display_name'])) ->htmlTemplate('Profiles/Layout/Templates/Mails/Register.html.twig') - ->context([ + ->context( + [ 'activationUrl' => SITE_URL . FrontendNavigation::getUrlForBlock( $this->getModule(), diff --git a/src/Frontend/Modules/Profiles/Actions/ResendActivation.php b/src/Frontend/Modules/Profiles/Actions/ResendActivation.php index 752dbc09be..4ed9b2e14f 100644 --- a/src/Frontend/Modules/Profiles/Actions/ResendActivation.php +++ b/src/Frontend/Modules/Profiles/Actions/ResendActivation.php @@ -47,8 +47,7 @@ private function buildForm(): void ->addText('email') ->setAttribute('type', 'email') ->setAttribute('autocomplete', 'email') - ->makeRequired() - ; + ->makeRequired(); } private function parse(): void @@ -112,9 +111,10 @@ private function resendActivationEmail(): void ->subject(FL::getMessage('RegisterSubject')) ->to(new Address($this->profile->getEmail(), $this->profile->getDisplayName())) ->htmlTemplate('Profiles/Layout/Templates/Mails/Register.html.twig') - ->context([ + ->context( + [ 'activationUrl' => SITE_URL . FrontendNavigation::getUrlForBlock($this->getModule(), 'Activate') - . '/' . $this->profile->getSetting('activation_key') + . '/' . $this->profile->getSetting('activation_key') ] ); From ca16ce09fb80a42d5cd515f0f7b173c846a00623 Mon Sep 17 00:00:00 2001 From: Tijs Verkoyen Date: Tue, 3 Mar 2026 08:07:58 +0100 Subject: [PATCH 16/16] chore: fix PHPStan issue --- .../Modules/Profiles/Actions/Settings.php | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/Frontend/Modules/Profiles/Actions/Settings.php b/src/Frontend/Modules/Profiles/Actions/Settings.php index 6a03e30eb2..d3d82d4ec1 100644 --- a/src/Frontend/Modules/Profiles/Actions/Settings.php +++ b/src/Frontend/Modules/Profiles/Actions/Settings.php @@ -168,30 +168,6 @@ private function validateForm(): bool return $this->form->isCorrect(); } - private function displayNameWasChanged(): bool - { - $txtDisplayName = $this->form->getField('display_name'); - - if (!$this->displayNameCanStillBeChanged() - || $this->profile->getDisplayName() === $txtDisplayName->getValue()) { - // no change or not allowed to change the display name - return false; - } - - $this->profile->setDisplayName($txtDisplayName->getValue()); - $this->profile->setUrl(FrontendProfilesModel::getUrl($txtDisplayName->getValue(), $this->profile->getId())); - - FrontendProfilesModel::update( - $this->profile->getId(), - [ - 'display_name' => $this->profile->getDisplayName(), - 'url' => $this->profile->getUrl(), - ] - ); - - return true; - } - private function handleForm(): void { if (!$this->form->isSubmitted()) {