2
0
Эх сурвалжийг харах

[Web] Time limited aliases: show create date; create aliases with 1yr retention by default; create temp alias in alias domain; better random names; accept any validity time
[Web] Replace spam score slider by nouislider and rework table a bit

andryyy 4 жил өмнө
parent
commit
e21e0b9dbf

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 40
data/web/css/build/004-bootstrap-slider.min.css


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
data/web/css/build/004-slider.min.css


+ 55 - 0
data/web/css/site/user.css

@@ -66,4 +66,59 @@ table tbody tr td input[type="checkbox"] {
 .key-action {
   font-weight:bold;
   color:white !important;
+}
+svg {
+  display: inline-block;
+  vertical-align: middle;
+}
+.c-1-color,
+.label-ham {
+  background: #28b62c;
+}
+.c-2-color,
+.label-spam {
+  background: #fff233; color: #333;
+}
+.c-3-color,
+.label-reject {
+  background: #ff4136;
+}
+#spam_score {
+  margin-bottom: 10px;
+}
+.noUi-handle {
+  border: 1px solid #e2e2e2;
+  border-radius: 0px;
+  background: #eee;
+  cursor: default;
+  box-shadow: none;
+  border-top-width: 0px;
+  border-right-width: 1px;
+  border-bottom-width: 4px;
+  border-left-width: 1px;
+}
+.noUi-handle:hover {
+  background-color: #eee;
+  border-color: #e2e2e2;
+  margin-top: 1px;
+border-bottom-width: 3px;
+}
+.noUi-handle::after, .noUi-handle::before {
+  background: #555;
+}
+.noUi-target {
+  background: transparent;
+  border-radius: 0px;
+  border: 1px solid #D3D3D3;
+  box-shadow: none;
+}
+.noUi-connects {
+  border-radius: 0px;
+}
+.label-ham,
+.label-spam,
+.label-reject {
+  padding: .1em .5em .1em;
+  font-size: inherit;
+  font-weight: 400;
 }

+ 1 - 0
data/web/edit.php

@@ -262,6 +262,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
             <li class="active"><a data-toggle="tab" href="#dedit"><?=$lang['edit']['domain'];?></a></li>
             <li><a data-toggle="tab" href="#dratelimit"><?=$lang['edit']['ratelimit'];?></a></li>
             <li><a data-toggle="tab" href="#dspamfilter"><?=$lang['edit']['spam_filter'];?></a></li>
+            <li><a data-toggle="tab" href="#dqwbcc"><?=$lang['edit']['quota_warning_bcc'];?></a></li>
           </ul>
           <hr>
           <div class="tab-content">

+ 12 - 1
data/web/inc/functions.inc.php

@@ -13,6 +13,17 @@ function isset_has_content($var) {
     return false;
   }
 }
+function readable_random_string($length = 8) {
+  $string = '';
+  $vowels = array('a', 'e', 'i', 'o', 'u');
+  $consonants = array('b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z');
+  $max = $length / 2;
+  for ($i = 1; $i <= $max; $i++) {
+    $string .= $consonants[rand(0,19)];
+    $string .= $vowels[rand(0,4)];
+  }
+  return $string;
+}
 // Validates ips and cidrs
 function valid_network($network) {
   if (filter_var($network, FILTER_VALIDATE_IP)) {
@@ -951,7 +962,6 @@ function user_get_alias_details($username) {
   $run = $stmt->fetchAll(PDO::FETCH_ASSOC);
   while ($row = array_shift($run)) {
     $data['shared_aliases'][$row['shared_aliases']]['public_comment'] = htmlspecialchars($row['public_comment']);
-
     //$data['shared_aliases'][] = $row['shared_aliases'];
   }
 
@@ -978,6 +988,7 @@ function user_get_alias_details($username) {
       continue;
     }
     $data['direct_aliases'][$row['ad_alias']]['public_comment'] = '↪ ' . $row['alias_domain'];
+    $data['alias_domains'][] = $row['alias_domain'];
   }
   $stmt = $pdo->prepare("SELECT IFNULL(GROUP_CONCAT(`send_as` SEPARATOR ', '), '&#10008;') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `send_as` NOT LIKE '@%';");
   $stmt->execute(array(':username' => $username));

+ 17 - 8
data/web/inc/functions.mailbox.inc.php

@@ -35,7 +35,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
           else {
             $username = $_SESSION['mailcow_cc_username'];
           }
-          if (!is_numeric($_data["validity"]) || $_data["validity"] > 672) {
+          if (isset($_data["validity"]) && !filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
             $_SESSION['return'][] = array(
               'type' => 'danger',
               'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
@@ -43,8 +43,17 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             );
             return false;
           }
-          $domain = mailbox('get', 'mailbox_details', $username)['domain'];
-          if (!is_valid_domain_name($domain)) {
+          else {
+            // Default to 1 yr
+            $_data["validity"] = 8760;
+          }
+          $domain = $_data['domain'];
+          $valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
+          $valid_alias_domains = user_get_alias_details($username)['alias_domains'];
+          if (!empty($valid_alias_domains)) {
+            $valid_domains = array_merge($valid_domains, $valid_alias_domains);
+          }
+          if (!in_array($domain, $valid_domains)) {
             $_SESSION['return'][] = array(
               'type' => 'danger',
               'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
@@ -52,13 +61,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             );
             return false;
           }
-          $validity = strtotime("+".$_data["validity"]." hour");
-          $letters = 'abcefghijklmnopqrstuvwxyz1234567890';
-          $random_name = substr(str_shuffle($letters), 0, 24);
+          $validity = strtotime("+" . $_data["validity"] . " hour");
           $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `goto`, `validity`) VALUES
             (:address, :goto, :validity)");
           $stmt->execute(array(
-            ':address' => $random_name . '@' . $domain,
+            ':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
             ':goto' => $username,
             ':validity' => $validity
           ));
@@ -3147,7 +3154,9 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
           }
           $stmt = $pdo->prepare("SELECT `address`,
             `goto`,
-            `validity`
+            `validity`,
+            `created`,
+            `modified`
               FROM `spamalias`
                 WHERE `goto` = :username
                   AND `validity` >= :unixnow");

+ 73 - 0
data/web/inc/functions.quota_notification.inc.php

@@ -65,3 +65,76 @@ function quota_notification($_action, $_data = null) {
     break;
   }
 }
+function quota_notification_bcc($_action, $_data = null) {
+	global $redis;
+	$_data_log = $_data;
+  if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
+    $_SESSION['return'][] = array(
+      'type' => 'danger',
+      'log' => array(__FUNCTION__, $_action, $_data_log),
+      'msg' => 'access_denied'
+    );
+    return false;
+  }
+  switch ($_action) {
+    case 'edit':
+      $domain = $_data['domain'];
+      if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => 'access_denied'
+        );
+        return false;
+      }
+      $active = intval($_data['active']);
+      $bcc_rcpt = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $_data['bcc_rcpt']);
+      if (filter_var($bcc_rcpt, FILTER_VALIDATE_EMAIL) === false) {
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => 'access_denied'
+        );
+        return false;
+      }
+      try {
+        $redis->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpt' => $bcc_rcpt, 'active' => $active)));
+      }
+      catch (RedisException $e) {
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => array('redis_error', $e)
+        );
+        return false;
+      }
+      $_SESSION['return'][] = array(
+        'type' => 'success',
+        'log' => array(__FUNCTION__, $_action, $_data_log),
+        'msg' => 'saved_settings'
+      );
+    break;
+    case 'get':
+      $domain = $_data['domain'];
+      if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => 'access_denied'
+        );
+        return false;
+      }
+      try {
+        return json_decode($redis->hGet('QW_BCC', $domain), true);
+      }
+      catch (RedisException $e) {
+        $_SESSION['return'][] = array(
+          'type' => 'danger',
+          'log' => array(__FUNCTION__, $_action, $_data_log),
+          'msg' => array('redis_error', $e)
+        );
+        return false;
+      }
+    break;
+  }
+}

+ 4 - 2
data/web/inc/init_db.inc.php

@@ -3,7 +3,7 @@ function init_db_schema() {
   try {
     global $pdo;
 
-    $db_version = "09032021_1000";
+    $db_version = "21052021_0900";
 
     $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
     $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -445,7 +445,9 @@ function init_db_schema() {
         "cols" => array(
           "address" => "VARCHAR(255) NOT NULL",
           "goto" => "TEXT NOT NULL",
-          "validity" => "INT(11) NOT NULL"
+          "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+          "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
+          "validity" => "INT(11)"
         ),
         "keys" => array(
           "primary" => array(

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 3
data/web/js/build/003-bootstrap-slider.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
data/web/js/build/003-slider.min.js


+ 1 - 1
data/web/js/build/014-mailcow.js

@@ -195,7 +195,7 @@ $(document).ready(function() {
     } else if ($(this).hasClass('btn')) {
       $(this).attr("disabled", true);
     } else if ($(this).attr('data-provide') == 'slider') {
-      $(this).slider("disable");
+      $(this).attr('disabled', true);
     } else if ($(this).is(':checkbox')) {
       $(this).attr("disabled", true);
     }

+ 29 - 1
data/web/js/site/user.js

@@ -1,4 +1,31 @@
 $(document).ready(function() {
+  // Spam score slider
+  var spam_slider = $('#spam_score')[0];
+  noUiSlider.create(spam_slider, {
+    start: user_spam_score,
+    connect: [true, true, true],
+    range: {
+      'min': [0], //stepsize is 50.000
+      '50%': [10],
+      '70%': [20, 5],
+      '80%': [50, 10],
+      '90%': [100, 100],
+      '95%': [1000, 1000],
+      'max': [5000]
+    },
+  });
+  var connect = spam_slider.querySelectorAll('.noUi-connect');
+  var classes = ['c-1-color', 'c-2-color', 'c-3-color'];
+  for (var i = 0; i < connect.length; i++) {
+    connect[i].classList.add(classes[i]);
+  }
+  spam_slider.noUiSlider.on('update', function (values, handle) {
+    $('.spam-ham-score').text('< ' + Math.round(values[0] * 10) / 10);
+    $('.spam-spam-score').text(Math.round(values[0] * 10) / 10 + ' - ' + Math.round(values[1] * 10) / 10);
+    $('.spam-reject-score').text('> ' + Math.round(values[1] * 10) / 10);
+    $('#spam_score_value').val((Math.round(values[0] * 10) / 10) + ',' + (Math.round(values[1] * 10) / 10));
+  });
+  // syncjobLogModal
   $('#syncjobLogModal').on('show.bs.modal', function(e) {
     var syncjob_id = $(e.relatedTarget).data('syncjob-id');
     $.ajax({
@@ -50,8 +77,9 @@ jQuery(function($){
     ft_tla_table = FooTable.init('#tla_table', {
       "columns": [
         {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
-        {"sorted": true,"name":"address","title":lang.alias},
+        {"name":"address","title":lang.alias},
         {"name":"validity","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.alias_valid_until,"style":{"width":"170px"}},
+        {"sorted": true,"sortValue": function(value){res = new Date(value);return res.getTime();},"direction":"DESC","name":"created","formatter":function date_format(datetime) { var date = new Date(datetime); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.created_on,"style":{"width":"170px"}},
         {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
       ],
       "empty": lang.empty,

+ 9 - 4
data/web/lang/lang.de.json

@@ -740,9 +740,9 @@
         "owner": "Besitzer",
         "private_comment": "Privater Kommentar",
         "public_comment": "Öffentlicher Kommentar",
-        "q_add_header": "Junk-Ordner",
-        "q_all": "Alle Kategorien",
-        "q_reject": "Abgelehnt",
+        "q_add_header": "bei Mail in Junk-Ordner",
+        "q_all": "bei Reject und Mail in Junk-Ordner",
+        "q_reject": "bei Reject",
         "quarantine_notification": "Quarantäne-Benachrichtigung",
         "quarantine_category": "Quarantäne-Benachrichtigungskategorie",
         "quick_actions": "Aktionen",
@@ -1009,6 +1009,7 @@
         "client_configuration": "Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen",
         "create_app_passwd": "Erstelle App-Passwort",
         "create_syncjob": "Neuen Sync-Job erstellen",
+        "created_on": "Erstellt am",
         "daily": "Täglich",
         "day": "Tag",
         "delete_ays": "Soll der Löschvorgang wirklich ausgeführt werden?",
@@ -1036,6 +1037,8 @@
         "loading": "Lade...",
         "mailbox_details": "Mailbox-Details",
         "messages": "Nachrichten",
+        "month": "Monat",
+        "months": "Monate",
         "never": "Niemals",
         "new_password": "Neues Passwort",
         "new_password_repeat": "Neues Passwort (Wiederholung)",
@@ -1111,7 +1114,9 @@
         "waiting": "Warte auf Ausführung",
         "week": "Woche",
         "weekly": "Wöchentlich",
-        "weeks": "Wochen"
+        "weeks": "Wochen",
+        "year": "Jahr",
+        "years": "Jahren"
     },
     "warning": {
         "cannot_delete_self": "Kann derzeit eingeloggten Benutzer nicht entfernen",

+ 9 - 4
data/web/lang/lang.en.json

@@ -738,9 +738,9 @@
         "owner": "Owner",
         "private_comment": "Private comment",
         "public_comment": "Public comment",
-        "q_add_header": "Junk folder",
-        "q_all": "All categories",
-        "q_reject": "Rejected",
+        "q_add_header": "when moved to Junk folder",
+        "q_all": " when moved to Junk folder and on reject",
+        "q_reject": "on reject",
         "quarantine_notification": "Quarantine notifications",
         "quarantine_category": "Quarantine notification category",
         "quick_actions": "Actions",
@@ -1007,6 +1007,7 @@
         "client_configuration": "Show configuration guides for email clients and smartphones",
         "create_app_passwd": "Create app password",
         "create_syncjob": "Create new sync job",
+        "created_on": "Created on",
         "daily": "Daily",
         "day": "day",
         "delete_ays": "Please confirm the deletion process.",
@@ -1034,6 +1035,8 @@
         "loading": "Loading...",
         "mailbox_details": "Mailbox details",
         "messages": "messages",
+        "month": "month",
+        "months": "months",
         "never": "Never",
         "new_password": "New password",
         "new_password_repeat": "Confirmation password (repeat)",
@@ -1109,7 +1112,9 @@
         "waiting": "Waiting",
         "week": "week",
         "weekly": "Weekly",
-        "weeks": "weeks"
+        "weeks": "weeks",
+        "year": "year",
+        "years": "years"
     },
     "warning": {
         "cannot_delete_self": "Cannot delete logged in user",

+ 36 - 0
data/web/modals/user.php

@@ -283,6 +283,42 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
     </div>
   </div>
 </div><!-- pw change modal -->
+<!-- pw change modal -->
+<div class="modal fade" id="tempAliasModal" tabindex="-1" role="dialog" aria-labelledby="tempAliasModalLabel">
+  <div class="modal-dialog" role="document">
+    <div class="modal-content">
+      <div class="modal-body">
+        <form class="form-horizontal" data-cached-form="false" data-id="pwchange" role="form" method="post" autocomplete="off">
+          <div class="form-group">
+            <label class="control-label col-sm-3" for="user_new_pass"><?=$lang['user']['new_password'];?> (<a href="#" class="generate_password"><?=$lang['user']['generate'];?></a>)</label>
+            <div class="col-sm-5">
+            <input type="password" data-pwgen-field="true" data-hibp="true" class="form-control" name="user_new_pass" autocomplete="new-password" required>
+            </div>
+          </div>
+          <div class="form-group">
+            <label class="control-label col-sm-3" for="user_new_pass2"><?=$lang['user']['new_password_repeat'];?></label>
+            <div class="col-sm-5">
+            <input type="password" data-pwgen-field="true" class="form-control" name="user_new_pass2" autocomplete="new-password" required>
+            <p class="help-block"><?=$lang['user']['new_password_description'];?></p>
+            </div>
+          </div>
+          <hr>
+          <div class="form-group">
+            <label class="control-label col-sm-3" for="user_old_pass"><?=$lang['user']['password_now'];?></label>
+            <div class="col-sm-5">
+            <input type="password" class="form-control" name="user_old_pass" autocomplete="off" required>
+            </div>
+          </div>
+          <div class="form-group">
+            <div class="col-sm-offset-3 col-sm-9">
+              <button class="btn btn-default" data-action="edit_selected" data-id="pwchange" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#"><?=$lang['user']['change_password'];?></button>
+            </div>
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+</div><!-- pw change modal -->
 <!-- sieve filter modal -->
 <div class="modal fade" id="userFilterModal" tabindex="-1" role="dialog">
   <div class="modal-dialog" role="document">

+ 45 - 47
data/web/user.php

@@ -222,6 +222,11 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
         <hr>
         <?php // Get user information about aliases
         $user_get_alias_details = user_get_alias_details($username);
+        $user_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
+        $user_alias_domains = $user_get_alias_details['alias_domains'];
+        if (!empty($user_alias_domains)) {
+          $user_domains = array_merge($user_domains, $user_alias_domains);
+        }
         ?>
         <div class="row">
           <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>:
@@ -448,22 +453,29 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
           <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
           <ul class="dropdown-menu">
             <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1"}' href="#"><?=$lang['user']['expire_in'];?> 1 <?=$lang['user']['hour'];?></a></li>
-            <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"6"}' href="#"><?=$lang['user']['expire_in'];?> 6 <?=$lang['user']['hours'];?></a></li>
             <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24"}' href="#"><?=$lang['user']['expire_in'];?> 1 <?=$lang['user']['day'];?></a></li>
             <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168"}' href="#"><?=$lang['user']['expire_in'];?> 1 <?=$lang['user']['week'];?></a></li>
-            <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"672"}' href="#"><?=$lang['user']['expire_in'];?> 4 <?=$lang['user']['weeks'];?></a></li>
+            <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744"}' href="#"><?=$lang['user']['expire_in'];?> 1 <?=$lang['user']['month'];?></a></li>
+            <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760"}' href="#"><?=$lang['user']['expire_in'];?> 1 <?=$lang['user']['year'];?></a></li>
+            <li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600"}' href="#"><?=$lang['user']['expire_in'];?> 10 <?=$lang['user']['years'];?></a></li>
             <li role="separator" class="divider"></li>
             <li><a data-action="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#"><?=$lang['mailbox']['remove'];?></a></li>
           </ul>
         </div>
         <div class="btn-group">
-          <a class="btn btn-sm btn-success dropdown-toggle" data-toggle="dropdown" href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['alias_create_random'];?> <span class="caret"></span></a>
+          <a class="btn btn-sm btn-success dropdown-toggle" data-toggle="dropdown" href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['alias_create_random'];?>, 1 <?=$lang['user']['year'];?> <span class="caret"></span></a>
           <ul class="dropdown-menu">
-            <li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">1 <?=$lang['user']['hour'];?></a></li>
-            <li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"6"}' href="#">6 <?=$lang['user']['hours'];?></a></li>
-            <li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">1 <?=$lang['user']['day'];?></a></li>
-            <li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">1 <?=$lang['user']['week'];?></a></li>
-            <li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"672"}' href="#">4 <?=$lang['user']['weeks'];?></a></li>
+          <?php
+          foreach($user_domains as $domain) {
+          ?>
+            <li>
+              <a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"domain":"<?=$domain;?>"}' href="#">
+                @ <?=$domain;?>
+              </a>
+            </li>
+          <?php
+          }
+          ?>
           </ul>
         </div>
       </div>
@@ -474,43 +486,28 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
 		<h4><?=$lang['user']['spamfilter_behavior'];?></h4>
 		<form class="form-horizontal" role="form" data-id="spam_score" method="post">
 			<div class="form-group">
-				<div class="col-lg-6 col-sm-12">
-					<input data-acl="<?=$_SESSION['acl']['spam_score'];?>" name="spam_score" id="spam_score" type="text" style="width: 100%;"
-						data-provide="slider"
-						data-slider-min="1"
-						data-slider-max="2000"
-            data-slider-scale='logarithmic'
-						data-slider-step="0.5"
-						data-slider-range="true"
-						data-slider-tooltip='always'
-						data-slider-id="slider1"
-						data-slider-value="[<?=mailbox('get', 'spam_score', $username);?>]"
-						data-slider-step="1" />
-					<br /><br />
-					<ul>
-						<li><?=$lang['user']['spamfilter_green'];?></li>
-						<li><?=$lang['user']['spamfilter_yellow'];?></li>
-						<li><?=$lang['user']['spamfilter_red'];?></li>
+				<div class="col-lg-8 col-sm-12">
+          <div id="spam_score" data-provide="slider" data-acl="<?=$_SESSION['acl']['spam_score'];?>"></div>
+					<input id="spam_score_value" name="spam_score" type="hidden" value="<?=mailbox('get', 'spam_score', $username);?>">
+					<ul class="list-group list-group-flush">
+						<li class="list-group-item"><span class="label label-ham spam-ham-score"></span> <?=$lang['user']['spamfilter_green'];?></li>
+						<li class="list-group-item"><span class="label label-spam spam-spam-score"></span> <?=$lang['user']['spamfilter_yellow'];?></li>
+						<li class="list-group-item"><span class="label label-reject spam-reject-score"></span> <?=$lang['user']['spamfilter_red'];?></li>
 					</ul>
-					<p><?=$lang['user']['spamfilter_hint'];?></p>
 				</div>
 			</div>
-      <div class="form-group">
-				<div class="col-sm-10">
-				</div>
-        <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
-          <a type="button" class="btn btn-sm btn-success" data-action="edit_selected"
-            data-item="<?= htmlentities($username); ?>"
-            data-id="spam_score"
-            data-api-url='edit/spam-score'
-            data-api-attr='{}'><?=$lang['user']['save_changes'];?></a>
-          <a type="button" class="btn btn-sm btn-default" data-action="edit_selected"
-            data-item="<?= htmlentities($username); ?>"
-            data-id="spam_score_reset"
-            data-api-url='edit/spam-score'
-            data-api-attr='{"spam_score":"default"}'><?=$lang['user']['spam_score_reset'];?></a>
-        </div>
-			</div>
+      <div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
+        <a type="button" class="btn btn-sm btn-success" data-action="edit_selected"
+          data-item="<?= htmlentities($username); ?>"
+          data-id="spam_score"
+          data-api-url='edit/spam-score'
+          data-api-attr='{}'><?=$lang['user']['save_changes'];?></a>
+        <a type="button" class="btn btn-sm btn-default" data-action="edit_selected"
+          data-item="<?= htmlentities($username); ?>"
+          data-id="spam_score_reset"
+          data-api-url='edit/spam-score'
+          data-api-attr='{"spam_score":"default"}'><?=$lang['user']['spam_score_reset'];?></a>
+      </div>
 		</form>
 		<hr>
 		<div class="row">
@@ -690,11 +687,12 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/user.php';
 <script type='text/javascript'>
 <?php
 $lang_user = json_encode($lang['user']);
-echo "var lang = ". $lang_user . ";\n";
-echo "var acl = '". json_encode($_SESSION['acl']) . "';\n";
-echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
-echo "var mailcow_cc_username = '". $_SESSION['mailcow_cc_username'] . "';\n";
-echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
+echo "var lang = " . $lang_user . ";\n";
+echo "var user_spam_score = [" . mailbox('get', 'spam_score', $username) . "];\n";
+echo "var acl = '" . json_encode($_SESSION['acl']) . "';\n";
+echo "var csrf_token = '" . $_SESSION['CSRF']['TOKEN'] . "';\n";
+echo "var mailcow_cc_username = '" . $_SESSION['mailcow_cc_username'] . "';\n";
+echo "var pagination_size = '" . $PAGINATION_SIZE . "';\n";
 ?>
 </script>
 <?php

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно