From 4ce739667d36405d810f99f06b083d5ef340a83d Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Sat, 28 Sep 2024 14:49:32 +0200 Subject: [PATCH] add rewrite-subject flag to email-edit form; hide spam-related settings if 'bypass_spam' is activated; add possibility to disable rejection of spam-mails, refs #1282 Signed-off-by: Michael Kaufmann --- install/froxlor.sql.php | 3 +- install/updates/froxlor/update_2.2.inc.php | 9 +++++ lib/Froxlor/Api/Commands/Emails.php | 24 +++++++++--- lib/Froxlor/Cron/Mail/Rspamd.php | 6 ++- lib/Froxlor/Froxlor.php | 2 +- .../customer/email/formfield.emails_edit.php | 37 ++++++++++++------- lng/de.lng.php | 5 +++ lng/en.lng.php | 5 +++ templates/Froxlor/assets/js/jquery/emails.js | 33 +++++++++++++++++ templates/Froxlor/form/formfields.html.twig | 6 ++- 10 files changed, 105 insertions(+), 25 deletions(-) create mode 100644 templates/Froxlor/assets/js/jquery/emails.js diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index f3d4b114..bfcd1dca 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -95,6 +95,7 @@ CREATE TABLE `mail_virtual` ( `iscatchall` tinyint(1) unsigned NOT NULL default '0', `description` varchar(255) NOT NULL DEFAULT '', `spam_tag_level` float(4,1) NOT NULL DEFAULT 7.0, + `rewrite_subject` tinyint(1) NOT NULL default '1', `spam_kill_level` float(4,1) NOT NULL DEFAULT 14.0, `bypass_spam` tinyint(1) NOT NULL default '0', `policy_greylist` tinyint(1) NOT NULL default '1', @@ -730,7 +731,7 @@ opcache.validate_timestamps'), ('panel', 'settings_mode', '0'), ('panel', 'menu_collapsed', '1'), ('panel', 'version', '2.2.1'), - ('panel', 'db_version', '202408140'); + ('panel', 'db_version', '202409280'); DROP TABLE IF EXISTS `panel_tasks`; diff --git a/install/updates/froxlor/update_2.2.inc.php b/install/updates/froxlor/update_2.2.inc.php index ccabd891..b9d9b900 100644 --- a/install/updates/froxlor/update_2.2.inc.php +++ b/install/updates/froxlor/update_2.2.inc.php @@ -169,3 +169,12 @@ if (Froxlor::isFroxlorVersion('2.2.0')) { Update::showUpdateStep("Updating from 2.2.0 to 2.2.1", false); Froxlor::updateToVersion('2.2.1'); } + +if (Froxlor::isDatabaseVersion('202408140')) { + + Update::showUpdateStep("Adding new rewrite-subject field to email table"); + Database::query("ALTER TABLE `" . TABLE_MAIL_VIRTUAL . "` ADD `rewrite_subject` tinyint(1) NOT NULL default '1' AFTER `spam_tag_level`;"); + Update::lastStepStatus(0); + + Froxlor::updateToDbVersion('202409280'); +} diff --git a/lib/Froxlor/Api/Commands/Emails.php b/lib/Froxlor/Api/Commands/Emails.php index ee7a2128..5294e639 100644 --- a/lib/Froxlor/Api/Commands/Emails.php +++ b/lib/Froxlor/Api/Commands/Emails.php @@ -53,6 +53,8 @@ class Emails extends ApiCommand implements ResourceEntity * domain-name for the email-address * @param float $spam_tag_level * optional, score which is required to tag emails as spam, default: 7.0 + * @param bool $rewrite_subject + * optional, whether to add ***SPAM*** to the email's subject if applicable, default true * @param float $spam_kill_level * optional, score which is required to discard emails, default: 14.0 * @param boolean $bypass_spam @@ -85,7 +87,8 @@ class Emails extends ApiCommand implements ResourceEntity // parameters $spam_tag_level = $this->getParam('spam_tag_level', true, '7.0'); - $spam_kill_level = $this->getParam('spam_kill_level', true, '14.0'); + $rewrite_subject = $this->getBoolParam('rewrite_subject', true, 1); + $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, '14.0'); $bypass_spam = $this->getBoolParam('bypass_spam', true, 0); $policy_greylist = $this->getBoolParam('policy_greylist', true, 1); $iscatchall = $this->getBoolParam('iscatchall', true, 0); @@ -155,8 +158,10 @@ class Emails extends ApiCommand implements ResourceEntity } } - $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true); - $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true); + $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1})?$/', '', [7.0], true); + if ($spam_kill_level > -1) { + $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1})?$/', '', [14.0], true); + } $description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true); $stmt = Database::prepare(" @@ -165,6 +170,7 @@ class Emails extends ApiCommand implements ResourceEntity `email` = :email, `email_full` = :email_full, `spam_tag_level` = :spam_tag_level, + `rewrite_subject` = :rewrite_subject, `spam_kill_level` = :spam_kill_level, `bypass_spam` = :bypass_spam, `policy_greylist` = :policy_greylist, @@ -177,6 +183,7 @@ class Emails extends ApiCommand implements ResourceEntity "email" => $email, "email_full" => $email_full, "spam_tag_level" => $spam_tag_level, + "rewrite_subject" => $rewrite_subject, "spam_kill_level" => $spam_kill_level, "bypass_spam" => $bypass_spam, "policy_greylist" => $policy_greylist, @@ -250,6 +257,8 @@ class Emails extends ApiCommand implements ResourceEntity * optional, required when called as admin (if $customerid is not specified) * @param float $spam_tag_level * optional, score which is required to tag emails as spam, default: 7.0 + * @param bool $rewrite_subject + * optional, whether to add ***SPAM*** to the email's subject if applicable, default true * @param float $spam_kill_level * optional, score which is required to discard emails, default: 14.0 * @param boolean $bypass_spam @@ -283,7 +292,8 @@ class Emails extends ApiCommand implements ResourceEntity // parameters $spam_tag_level = $this->getParam('spam_tag_level', true, $result['spam_tag_level']); - $spam_kill_level = $this->getParam('spam_kill_level', true, $result['spam_kill_level']); + $rewrite_subject = $this->getBoolParam('rewrite_subject', true, $result['rewrite_subject']); + $spam_kill_level = $this->getUlParam('spam_kill_level', 'spam_kill_level_ul', true, $result['spam_kill_level']); $bypass_spam = $this->getBoolParam('bypass_spam', true, $result['bypass_spam']); $policy_greylist = $this->getBoolParam('policy_greylist', true, $result['policy_greylist']); $iscatchall = $this->getBoolParam('iscatchall', true, $result['iscatchall']); @@ -327,13 +337,16 @@ class Emails extends ApiCommand implements ResourceEntity } $spam_tag_level = Validate::validate($spam_tag_level, 'spam_tag_level', '/^\d{1,}(\.\d{1,2})?$/', '', [7.0], true); - $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true); + if ($spam_kill_level > -1) { + $spam_kill_level = Validate::validate($spam_kill_level, 'spam_kill_level', '/^\d{1,}(\.\d{1,2})?$/', '', [14.0], true); + } $description = Validate::validate(trim($description), 'description', Validate::REGEX_DESC_TEXT, '', [], true); $stmt = Database::prepare(" UPDATE `" . TABLE_MAIL_VIRTUAL . "` SET `email` = :email , `spam_tag_level` = :spam_tag_level, + `rewrite_subject` = :rewrite_subject, `spam_kill_level` = :spam_kill_level, `bypass_spam` = :bypass_spam, `policy_greylist` = :policy_greylist, @@ -344,6 +357,7 @@ class Emails extends ApiCommand implements ResourceEntity $params = [ "email" => $email, "spam_tag_level" => $spam_tag_level, + "rewrite_subject" => $rewrite_subject, "spam_kill_level" => $spam_kill_level, "bypass_spam" => $bypass_spam, "policy_greylist" => $policy_greylist, diff --git a/lib/Froxlor/Cron/Mail/Rspamd.php b/lib/Froxlor/Cron/Mail/Rspamd.php index 624e91dd..625552f6 100644 --- a/lib/Froxlor/Cron/Mail/Rspamd.php +++ b/lib/Froxlor/Cron/Mail/Rspamd.php @@ -165,7 +165,7 @@ class Rspamd $this->logger->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Generating antispam config for ' . $email['email']); $email['spam_tag_level'] = floatval($email['spam_tag_level']); - $email['spam_kill_level'] = floatval($email['spam_kill_level']); + $email['spam_kill_level'] = $email['spam_kill_level'] == -1 ? "null" : floatval($email['spam_kill_level']); $email_id = md5($email['email']); $this->frx_settings_file .= '# Email: ' . $email['email'] . "\n"; @@ -185,7 +185,9 @@ class Rspamd $this->frx_settings_file .= ' apply {' . "\n"; $this->frx_settings_file .= ' actions {' . "\n"; $this->frx_settings_file .= ' "add header" = ' . $email['spam_tag_level'] . ';' . "\n"; - $this->frx_settings_file .= ' rewrite_subject = ' . ($email['spam_tag_level'] + 0.01) . ';' . "\n"; + if ((int)$email['rewrite_subject'] == 1) { + $this->frx_settings_file .= ' rewrite_subject = ' . ($email['spam_tag_level'] + 0.01) . ';' . "\n"; + } $this->frx_settings_file .= ' reject = ' . $email['spam_kill_level'] . ';' . "\n"; if ($type == 'rcpt' && (int)$email['policy_greylist'] == 0) { $this->frx_settings_file .= ' greylist = null;' . "\n"; diff --git a/lib/Froxlor/Froxlor.php b/lib/Froxlor/Froxlor.php index 92eb1b70..046e3855 100644 --- a/lib/Froxlor/Froxlor.php +++ b/lib/Froxlor/Froxlor.php @@ -34,7 +34,7 @@ final class Froxlor const VERSION = '2.2.1'; // Database version (YYYYMMDDC where C is a daily counter) - const DBVERSION = '202408140'; + const DBVERSION = '202409280'; // Distribution branding-tag (used for Debian etc.) const BRANDING = ''; diff --git a/lib/formfields/customer/email/formfield.emails_edit.php b/lib/formfields/customer/email/formfield.emails_edit.php index a56f14a1..2642c091 100644 --- a/lib/formfields/customer/email/formfield.emails_edit.php +++ b/lib/formfields/customer/email/formfield.emails_edit.php @@ -96,20 +96,6 @@ return [ 'value' => '1', 'checked' => (int)$result['iscatchall'], ], - 'spam_tag_level' => [ - 'visible' => Settings::Get('antispam.activated') == '1', - 'label' => lng('antispam.spam_tag_level'), - 'type' => 'text', - 'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/', - 'value' => $result['spam_tag_level'] - ], - 'spam_kill_level' => [ - 'visible' => Settings::Get('antispam.activated') == '1', - 'label' => lng('antispam.spam_kill_level'), - 'type' => 'text', - 'string_regexp' => '/^\d{1,}(\.\d{1,2})?$/', - 'value' => $result['spam_kill_level'] - ], 'bypass_spam' => [ 'visible' => Settings::Get('antispam.activated') == '1', 'label' => lng('antispam.bypass_spam'), @@ -117,6 +103,29 @@ return [ 'value' => '1', 'checked' => (int)$result['bypass_spam'], ], + 'spam_tag_level' => [ + 'visible' => Settings::Get('antispam.activated') == '1', + 'label' => lng('antispam.spam_tag_level'), + 'type' => 'number', + 'min' => 0, + 'step' => 0.1, + 'value' => $result['spam_tag_level'], + ], + 'spam_rewrite_subject' => [ + 'visible' => Settings::Get('antispam.activated') == '1', + 'label' => lng('antispam.rewrite_subject'), + 'type' => 'checkbox', + 'value' => '1', + 'checked' => (int)$result['rewrite_subject'], + ], + 'spam_kill_level' => [ + 'visible' => Settings::Get('antispam.activated') == '1', + 'label' => lng('antispam.spam_kill_level'), + 'desc' => lng('panel.use_checkbox_to_disable'), + 'type' => 'textul', + 'step' => 0.1, + 'value' => $result['spam_kill_level'] + ], 'policy_greylist' => [ 'visible' => Settings::Get('antispam.activated') == '1', 'label' => lng('antispam.policy_greylist'), diff --git a/lng/de.lng.php b/lng/de.lng.php index 627bef2a..7199ee87 100644 --- a/lng/de.lng.php +++ b/lng/de.lng.php @@ -621,6 +621,10 @@ return [ 'title' => 'Spam Level', 'description' => 'Erforderliche Punktzahl zum Markieren einer E-Mail als Spam
Standard: 7.0' ], + 'rewrite_subject' => [ + 'title' => 'Betreff ändern', + 'description' => 'Dem E-Mail Betreff ***SPAM*** hinzufügen, sofern zutreffend', + ], 'spam_kill_level' => [ 'title' => 'Ablehnungs Level', 'description' => 'Erforderliche Punktzahl für das Ablehnen einer E-Mail
Standard: 14.0' @@ -1262,6 +1266,7 @@ Vielen Dank, Ihr Administrator', 'upload_import' => 'Hochladen und importieren', 'profile' => 'Mein Profil', 'use_checkbox_for_unlimited' => 'Der Wert "0" deaktiviert die Resource. Die Checkbox rechts erlaubt "unlimitierte" Nutzung.', + 'use_checkbox_to_disable' => 'Zum Deaktivieren, klicke die Checkbox auf der rechten Seite des Eingabefeldes', ], 'phpfpm' => [ 'vhost_httpuser' => 'Lokaler Benutzer für PHP-FPM (Froxlor-Vhost)', diff --git a/lng/en.lng.php b/lng/en.lng.php index 48fb799c..6c0af9c1 100644 --- a/lng/en.lng.php +++ b/lng/en.lng.php @@ -670,6 +670,10 @@ return [ 'title' => 'Spam tag level', 'description' => 'Score that is required to mark an email as spam
Default: 7.0' ], + 'rewrite_subject' => [ + 'title' => 'Rewrite subject', + 'description' => 'Whether to add ***SPAM*** to the email subject if applicable', + ], 'spam_kill_level' => [ 'title' => 'Spam kill level', 'description' => 'Score that is required to discard an email entirely
Default: 14.0' @@ -1377,6 +1381,7 @@ Yours sincerely, your administrator', 'upload_import' => 'Upload and import', 'profile' => 'My profile', 'use_checkbox_for_unlimited' => 'The value "0" deactivates this resource. The checkbox on the right allows "unlimited" usage.', + 'use_checkbox_to_disable' => 'To disable, activate the checkbox on the right of the input field', ], 'phpfpm' => [ 'vhost_httpuser' => 'Local user to use for PHP-FPM (Froxlor vHost)', diff --git a/templates/Froxlor/assets/js/jquery/emails.js b/templates/Froxlor/assets/js/jquery/emails.js new file mode 100644 index 00000000..93ffbcbd --- /dev/null +++ b/templates/Froxlor/assets/js/jquery/emails.js @@ -0,0 +1,33 @@ +export default function () { + $(function () { + + /** + * bypass spam - hide unnecessary/unused sections + */ + if ($('#id') && $('#bypass_spam').is(':checked')) { + $('#spam_tag_level').closest('.row').addClass('d-none'); + $('#spam_rewrite_subject').closest('.row').addClass('d-none'); + $('#spam_kill_level').closest('.row').addClass('d-none'); + $('#policy_greylist').closest('.row').addClass('d-none'); + } + + /** + * toggle show/hide of sections in case of bypass spam flag + */ + $('#bypass_spam').on('click', function () { + if ($(this).is(':checked')) { + // hide unnecessary sections + $('#spam_tag_level').closest('.row').addClass('d-none'); + $('#spam_rewrite_subject').closest('.row').addClass('d-none'); + $('#spam_kill_level').closest('.row').addClass('d-none'); + $('#policy_greylist').closest('.row').addClass('d-none'); + } else { + // show sections + $('#spam_tag_level').closest('.row').removeClass('d-none'); + $('#spam_rewrite_subject').closest('.row').removeClass('d-none'); + $('#spam_kill_level').closest('.row').removeClass('d-none'); + $('#policy_greylist').closest('.row').removeClass('d-none'); + } + }) + }); +} diff --git a/templates/Froxlor/form/formfields.html.twig b/templates/Froxlor/form/formfields.html.twig index f93b2038..ae8f146d 100644 --- a/templates/Froxlor/form/formfields.html.twig +++ b/templates/Froxlor/form/formfields.html.twig @@ -19,6 +19,8 @@ {% endif %} {% if field.label.description is defined and field.label.description is not empty %}
{{ field.label.description|raw }} {% endif %} + {% if field.desc is defined and field.desc is not empty %}
{{ field.desc|raw }} + {% endif %} {% if field.requires_reconf is defined and field.requires_reconf is not empty %}