[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
master
andryyy 2021-05-21 12:48:19 +02:00
parent 99ab945ae2
commit e21e0b9dbf
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
16 changed files with 293 additions and 114 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-ms-touch-action:none;touch-action:none;-ms-user-select:none;-moz-user-select:none;user-select:none;-moz-box-sizing:border-box;box-sizing:border-box}.noUi-target{position:relative}.noUi-base,.noUi-connects{width:100%;height:100%;position:relative;z-index:1}.noUi-connects{overflow:hidden;z-index:0}.noUi-connect,.noUi-origin{will-change:transform;position:absolute;z-index:1;top:0;right:0;-ms-transform-origin:0 0;-webkit-transform-origin:0 0;-webkit-transform-style:preserve-3d;transform-origin:0 0;transform-style:flat}.noUi-connect{height:100%;width:100%}.noUi-origin{height:10%;width:10%}.noUi-txt-dir-rtl.noUi-horizontal .noUi-origin{left:0;right:auto}.noUi-vertical .noUi-origin{width:0}.noUi-horizontal .noUi-origin{height:0}.noUi-handle{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute}.noUi-touch-area{height:100%;width:100%}.noUi-state-tap .noUi-connect,.noUi-state-tap .noUi-origin{-webkit-transition:transform .3s;transition:transform .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-horizontal{height:18px}.noUi-horizontal .noUi-handle{width:34px;height:28px;right:-17px;top:-6px}.noUi-vertical{width:18px}.noUi-vertical .noUi-handle{width:28px;height:34px;right:-6px;top:-17px}.noUi-txt-dir-rtl.noUi-horizontal .noUi-handle{left:-17px;right:auto}.noUi-target{background:#FAFAFA;border-radius:4px;border:1px solid #D3D3D3;box-shadow:inset 0 1px 1px #F0F0F0,0 3px 6px -5px #BBB}.noUi-connects{border-radius:3px}.noUi-connect{background:#3FB8AF}.noUi-draggable{cursor:ew-resize}.noUi-vertical .noUi-draggable{cursor:ns-resize}.noUi-handle{border:1px solid #D9D9D9;border-radius:3px;background:#FFF;cursor:default;box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #EBEBEB,0 3px 6px -3px #BBB}.noUi-active{box-shadow:inset 0 0 1px #FFF,inset 0 1px 7px #DDD,0 3px 6px -3px #BBB}.noUi-handle:after,.noUi-handle:before{content:"";display:block;position:absolute;height:14px;width:1px;background:#E8E7E6;left:14px;top:6px}.noUi-handle:after{left:17px}.noUi-vertical .noUi-handle:after,.noUi-vertical .noUi-handle:before{width:14px;height:1px;left:6px;top:14px}.noUi-vertical .noUi-handle:after{top:17px}[disabled] .noUi-connect{background:#B8B8B8}[disabled] .noUi-handle,[disabled].noUi-handle,[disabled].noUi-target{cursor:not-allowed}.noUi-pips,.noUi-pips *{-moz-box-sizing:border-box;box-sizing:border-box}.noUi-pips{position:absolute;color:#999}.noUi-value{position:absolute;white-space:nowrap;text-align:center}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{position:absolute;background:#CCC}.noUi-marker-sub{background:#AAA}.noUi-marker-large{background:#AAA}.noUi-pips-horizontal{padding:10px 0;height:80px;top:100%;left:0;width:100%}.noUi-value-horizontal{-webkit-transform:translate(-50%,50%);transform:translate(-50%,50%)}.noUi-rtl .noUi-value-horizontal{-webkit-transform:translate(50%,50%);transform:translate(50%,50%)}.noUi-marker-horizontal.noUi-marker{margin-left:-1px;width:2px;height:5px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{padding:0 10px;height:100%;top:0;left:100%}.noUi-value-vertical{-webkit-transform:translate(0,-50%);transform:translate(0,-50%);padding-left:25px}.noUi-rtl .noUi-value-vertical{-webkit-transform:translate(0,50%);transform:translate(0,50%)}.noUi-marker-vertical.noUi-marker{width:5px;height:2px;margin-top:-1px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{display:block;position:absolute;border:1px solid #D9D9D9;border-radius:3px;background:#fff;color:#000;padding:5px;text-align:center;white-space:nowrap}.noUi-horizontal .noUi-tooltip{-webkit-transform:translate(-50%,0);transform:translate(-50%,0);left:50%;bottom:120%}.noUi-vertical .noUi-tooltip{-webkit-transform:translate(0,-50%);transform:translate(0,-50%);top:50%;right:120%}.noUi-horizontal .noUi-origin>.noUi-tooltip{-webkit-transform:translate(50%,0);transform:translate(50%,0);left:auto;bottom:10px}.noUi-vertical .noUi-origin>.noUi-tooltip{-webkit-transform:translate(0,-18px);transform:translate(0,-18px);top:auto;right:28px}

View File

@ -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;
}

View File

@ -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">

View File

@ -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));

View File

@ -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");

View File

@ -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;
}
}

View File

@ -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(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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);
}

View File

@ -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,

View File

@ -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",

View File

@ -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",

View File

@ -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">

View File

@ -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