Add Domain and Mailbox tagging (#4569)
* [Web] define tag tables * [Web] add mailbox tag functions * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * Include new tags lang in language.en.json * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging * [Web] add domain/mailbox tagging Co-authored-by: Niklas Meyer <62480600+DerLinkman@users.noreply.github.com>
This commit is contained in:
parent
456b528785
commit
549ff7d100
@ -65,7 +65,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/api/v1/(.*)$ {
|
location ~ ^/api/v1/(.*)$ {
|
||||||
try_files $uri $uri/ /json_api.php?query=$1;
|
try_files $uri $uri/ /json_api.php?query=$1&$args;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /.well-known/acme-challenge/ {
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
@ -497,6 +497,7 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
rl_frame: s
|
rl_frame: s
|
||||||
rl_value: "10"
|
rl_value: "10"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- domain_added
|
- domain_added
|
||||||
@ -544,6 +545,7 @@ paths:
|
|||||||
rl_frame: s
|
rl_frame: s
|
||||||
rl_value: "10"
|
rl_value: "10"
|
||||||
restart_sogo: "10"
|
restart_sogo: "10"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
properties:
|
properties:
|
||||||
active:
|
active:
|
||||||
description: is domain active or not
|
description: is domain active or not
|
||||||
@ -1010,6 +1012,7 @@ paths:
|
|||||||
force_pw_update: "1"
|
force_pw_update: "1"
|
||||||
tls_enforce_in: "1"
|
tls_enforce_in: "1"
|
||||||
tls_enforce_out: "1"
|
tls_enforce_out: "1"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- mailbox_added
|
- mailbox_added
|
||||||
@ -1054,6 +1057,7 @@ paths:
|
|||||||
force_pw_update: "1"
|
force_pw_update: "1"
|
||||||
tls_enforce_in: "1"
|
tls_enforce_in: "1"
|
||||||
tls_enforce_out: "1"
|
tls_enforce_out: "1"
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
properties:
|
properties:
|
||||||
active:
|
active:
|
||||||
description: is mailbox active or not
|
description: is mailbox active or not
|
||||||
@ -2716,6 +2720,140 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
summary: Delete Transport Maps
|
summary: Delete Transport Maps
|
||||||
|
"/api/v1/delete/mailbox/tag/{mailbox}":
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: name of mailbox
|
||||||
|
in: path
|
||||||
|
name: mailbox
|
||||||
|
example: info@domain.tld
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
- log:
|
||||||
|
- mailbox
|
||||||
|
- delete
|
||||||
|
- tags_mailbox
|
||||||
|
- tags:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
mailbox: info@domain.tld
|
||||||
|
- null
|
||||||
|
msg:
|
||||||
|
- mailbox_modified
|
||||||
|
- info@domain.tld
|
||||||
|
type: success
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
log:
|
||||||
|
description: contains request object
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
msg:
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- success
|
||||||
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Mailboxes
|
||||||
|
description: You can delete one or more mailbox tags.
|
||||||
|
operationId: Delete mailbox tags
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
example:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
description: contains list of mailboxes you want to delete
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
summary: Delete mailbox tags
|
||||||
|
"/api/v1/delete/domain/tag/{domain}":
|
||||||
|
post:
|
||||||
|
parameters:
|
||||||
|
- description: name of domain
|
||||||
|
in: path
|
||||||
|
name: domain
|
||||||
|
example: domain.tld
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"200":
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
examples:
|
||||||
|
response:
|
||||||
|
value:
|
||||||
|
- log:
|
||||||
|
- mailbox
|
||||||
|
- delete
|
||||||
|
- tags_domain
|
||||||
|
- tags:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
domain: domain.tld
|
||||||
|
- null
|
||||||
|
msg:
|
||||||
|
- domain_modified
|
||||||
|
- domain.tld
|
||||||
|
type: success
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
log:
|
||||||
|
description: contains request object
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
msg:
|
||||||
|
items: {}
|
||||||
|
type: array
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- success
|
||||||
|
- danger
|
||||||
|
- error
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
description: OK
|
||||||
|
headers: {}
|
||||||
|
tags:
|
||||||
|
- Domains
|
||||||
|
description: You can delete one or more domain tags.
|
||||||
|
operationId: Delete domain tags
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
example:
|
||||||
|
- tag1
|
||||||
|
- tag2
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
description: contains list of domains you want to delete
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
summary: Delete domain tags
|
||||||
/api/v1/edit/alias:
|
/api/v1/edit/alias:
|
||||||
post:
|
post:
|
||||||
responses:
|
responses:
|
||||||
@ -2865,6 +3003,7 @@ paths:
|
|||||||
quota: "10240"
|
quota: "10240"
|
||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "2"
|
relayhost: "2"
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
items: domain.tld
|
items: domain.tld
|
||||||
properties:
|
properties:
|
||||||
attr:
|
attr:
|
||||||
@ -3019,6 +3158,7 @@ paths:
|
|||||||
sogo_access: "1"
|
sogo_access: "1"
|
||||||
username:
|
username:
|
||||||
- info@domain.tld
|
- info@domain.tld
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
- null
|
- null
|
||||||
msg:
|
msg:
|
||||||
- mailbox_modified
|
- mailbox_modified
|
||||||
@ -3066,6 +3206,7 @@ paths:
|
|||||||
- domain3.tld
|
- domain3.tld
|
||||||
- "*"
|
- "*"
|
||||||
sogo_access: "1"
|
sogo_access: "1"
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
items:
|
items:
|
||||||
- info@domain.tld
|
- info@domain.tld
|
||||||
properties:
|
properties:
|
||||||
@ -3793,6 +3934,11 @@ paths:
|
|||||||
- all
|
- all
|
||||||
- mailcow.tld
|
- mailcow.tld
|
||||||
type: string
|
type: string
|
||||||
|
- description: comma seperated list of tags to filter by
|
||||||
|
example: "tag1,tag2"
|
||||||
|
in: query
|
||||||
|
name: tags
|
||||||
|
required: false
|
||||||
- description: e.g. api-key-string
|
- description: e.g. api-key-string
|
||||||
example: api-key-string
|
example: api-key-string
|
||||||
in: header
|
in: header
|
||||||
@ -3831,6 +3977,7 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "0"
|
relayhost: "0"
|
||||||
rl: false
|
rl: false
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
- active: "1"
|
- active: "1"
|
||||||
aliases_in_domain: 0
|
aliases_in_domain: 0
|
||||||
aliases_left: 400
|
aliases_left: 400
|
||||||
@ -3853,6 +4000,7 @@ paths:
|
|||||||
relay_all_recipients: "0"
|
relay_all_recipients: "0"
|
||||||
relayhost: "0"
|
relayhost: "0"
|
||||||
rl: false
|
rl: false
|
||||||
|
tags: ["tag3", "tag4"]
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
@ -4345,6 +4493,11 @@ paths:
|
|||||||
- all
|
- all
|
||||||
- user@domain.tld
|
- user@domain.tld
|
||||||
type: string
|
type: string
|
||||||
|
- description: comma seperated list of tags to filter by
|
||||||
|
example: "tag1,tag2"
|
||||||
|
in: query
|
||||||
|
name: tags
|
||||||
|
required: false
|
||||||
- description: e.g. api-key-string
|
- description: e.g. api-key-string
|
||||||
example: api-key-string
|
example: api-key-string
|
||||||
in: header
|
in: header
|
||||||
@ -4382,6 +4535,7 @@ paths:
|
|||||||
rl: false
|
rl: false
|
||||||
spam_aliases: 0
|
spam_aliases: 0
|
||||||
username: info@doman3.tld
|
username: info@doman3.tld
|
||||||
|
tags: ["tag1", "tag2"]
|
||||||
description: OK
|
description: OK
|
||||||
headers: {}
|
headers: {}
|
||||||
tags:
|
tags:
|
||||||
|
@ -256,3 +256,40 @@ code {
|
|||||||
.flag-icon {
|
.flag-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag-box {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.tag-badge {
|
||||||
|
transition: 200ms linear;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
.tag-badge.btn-badge {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.tag-badge .bi {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.tag-badge.btn-badge:hover {
|
||||||
|
filter: brightness(0.9);
|
||||||
|
}
|
||||||
|
.tag-input {
|
||||||
|
margin-left: 10px;
|
||||||
|
border: 0;
|
||||||
|
flex: 1;
|
||||||
|
height: 24px;
|
||||||
|
min-width: 150px;
|
||||||
|
}
|
||||||
|
.tag-input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.tag-add {
|
||||||
|
padding: 0 5px 0 5px;
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
@ -54,6 +54,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||||||
'rl' => $rl,
|
'rl' => $rl,
|
||||||
'rlyhosts' => $rlyhosts,
|
'rlyhosts' => $rlyhosts,
|
||||||
'dkim' => dkim('details', $domain),
|
'dkim' => dkim('details', $domain),
|
||||||
|
'domain_details' => $result,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['oauth2client']) &&
|
elseif (isset($_GET['oauth2client']) &&
|
||||||
@ -99,6 +100,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||||||
'rlyhosts' => $rlyhosts,
|
'rlyhosts' => $rlyhosts,
|
||||||
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox),
|
||||||
'user_acls' => acl('get', 'user', $mailbox),
|
'user_acls' => acl('get', 'user', $mailbox),
|
||||||
|
'mailbox_details' => $result
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
|
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
|
||||||
|
@ -443,16 +443,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
'msg' => 'access_denied'
|
'msg' => 'access_denied'
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
|
||||||
$description = $_data['description'];
|
$description = $_data['description'];
|
||||||
if (empty($description)) {
|
if (empty($description)) $description = $domain;
|
||||||
$description = $domain;
|
$tags = (array)$_data['tags'];
|
||||||
}
|
|
||||||
$aliases = (int)$_data['aliases'];
|
$aliases = (int)$_data['aliases'];
|
||||||
$mailboxes = (int)$_data['mailboxes'];
|
$mailboxes = (int)$_data['mailboxes'];
|
||||||
$defquota = (int)$_data['defquota'];
|
$defquota = (int)$_data['defquota'];
|
||||||
@ -545,10 +544,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
|
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':domain' => '%@' . $domain
|
':domain' => '%@' . $domain
|
||||||
));
|
));
|
||||||
|
// save domain
|
||||||
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
|
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
|
||||||
VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
|
VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
@ -565,6 +566,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':relay_unknown_only' => $relay_unknown_only,
|
':relay_unknown_only' => $relay_unknown_only,
|
||||||
':relay_all_recipients' => $relay_all_recipients
|
':relay_all_recipients' => $relay_all_recipients
|
||||||
));
|
));
|
||||||
|
// save tags
|
||||||
|
foreach($tags as $index => $tag){
|
||||||
|
if ($index > $GLOBALS['TAGGING_LIMIT']) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'warning',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':domain' => $domain,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DOMAIN_MAP', $domain, 1);
|
$redis->hSet('DOMAIN_MAP', $domain, 1);
|
||||||
}
|
}
|
||||||
@ -942,6 +960,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$password = $_data['password'];
|
$password = $_data['password'];
|
||||||
$password2 = $_data['password2'];
|
$password2 = $_data['password2'];
|
||||||
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
$name = ltrim(rtrim($_data['name'], '>'), '<');
|
||||||
|
$tags = $_data['tags'];
|
||||||
$quota_m = intval($_data['quota']);
|
$quota_m = intval($_data['quota']);
|
||||||
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@ -1103,6 +1122,22 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $username
|
':username' => $username
|
||||||
));
|
));
|
||||||
|
// save tags
|
||||||
|
foreach($tags as $index => $tag){
|
||||||
|
if ($index > $GLOBALS['TAGGING_LIMIT']) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'warning',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
|
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
|
||||||
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
|
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
@ -2146,6 +2181,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
|
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
|
||||||
$description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
|
$description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
|
||||||
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
|
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
|
||||||
|
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@ -2155,6 +2191,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare("UPDATE `domain` SET
|
$stmt = $pdo->prepare("UPDATE `domain` SET
|
||||||
`description` = :description,
|
`description` = :description,
|
||||||
`gal` = :gal
|
`gal` = :gal
|
||||||
@ -2164,6 +2201,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':gal' => $gal,
|
':gal' => $gal,
|
||||||
':domain' => $domain
|
':domain' => $domain
|
||||||
));
|
));
|
||||||
|
// save tags, tag_name is unique
|
||||||
|
foreach($tags as $index => $tag){
|
||||||
|
if ($index > $GLOBALS['TAGGING_LIMIT']) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'warning',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':domain' => $domain,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@ -2185,6 +2239,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
|
$maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
|
||||||
$quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
|
$quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
|
||||||
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
|
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
|
||||||
|
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
|
||||||
if ($relay_all_recipients == '1') {
|
if ($relay_all_recipients == '1') {
|
||||||
$backupmx = '1';
|
$backupmx = '1';
|
||||||
}
|
}
|
||||||
@ -2283,6 +2338,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $pdo->prepare("UPDATE `domain` SET
|
$stmt = $pdo->prepare("UPDATE `domain` SET
|
||||||
`relay_all_recipients` = :relay_all_recipients,
|
`relay_all_recipients` = :relay_all_recipients,
|
||||||
`relay_unknown_only` = :relay_unknown_only,
|
`relay_unknown_only` = :relay_unknown_only,
|
||||||
@ -2312,6 +2368,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':description' => $description,
|
':description' => $description,
|
||||||
':domain' => $domain
|
':domain' => $domain
|
||||||
));
|
));
|
||||||
|
// save tags, tag_name is unique
|
||||||
|
foreach($tags as $index => $tag){
|
||||||
|
if ($index > $GLOBALS['TAGGING_LIMIT']) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'warning',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':domain' => $domain,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@ -2360,6 +2433,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$quota_b = $quota_m * 1048576;
|
$quota_b = $quota_m * 1048576;
|
||||||
$password = (!empty($_data['password'])) ? $_data['password'] : null;
|
$password = (!empty($_data['password'])) ? $_data['password'] : null;
|
||||||
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
|
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
|
||||||
|
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@ -2636,6 +2710,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':relayhost' => $relayhost,
|
':relayhost' => $relayhost,
|
||||||
':username' => $username
|
':username' => $username
|
||||||
));
|
));
|
||||||
|
// save tags
|
||||||
|
foreach($tags as $index => $tag){
|
||||||
|
if ($index > $GLOBALS['TAGGING_LIMIT']) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'warning',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@ -2851,10 +2942,34 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
break;
|
break;
|
||||||
case 'mailboxes':
|
case 'mailboxes':
|
||||||
$mailboxes = array();
|
$mailboxes = array();
|
||||||
if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
if (isset($_extra) && is_array($_extra) && isset($_data)) {
|
||||||
return false;
|
// get by domain and tags
|
||||||
|
$tags = is_array($_extra) ? $_extra : array();
|
||||||
|
|
||||||
|
$sql = "";
|
||||||
|
foreach ($tags as $key => $tag) {
|
||||||
|
$sql = $sql."SELECT DISTINCT `username` FROM `tags_mailbox` WHERE `username` LIKE ? AND `tag_name` LIKE ?"; // distinct, avoid duplicates
|
||||||
|
if ($key === array_key_last($tags)) break;
|
||||||
|
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepend domain to array
|
||||||
|
$params = array();
|
||||||
|
foreach ($tags as $key => $val){
|
||||||
|
array_push($params, '%'.$_data.'%');
|
||||||
|
array_push($params, '%'.$val.'%');
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], explode('@', $row['username'])[1]))
|
||||||
|
$mailboxes[] = $row['username'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||||
|
// get by domain
|
||||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
|
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':domain' => $_data,
|
':domain' => $_data,
|
||||||
@ -3348,20 +3463,46 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
|
||||||
WHERE (`domain` IN (
|
if (isset($_extra) && is_array($_extra)){
|
||||||
SELECT `domain` from `domain_admins`
|
// get by tags
|
||||||
WHERE (`active`='1' AND `username` = :username))
|
$tags = is_array($_extra) ? $_extra : array();
|
||||||
)
|
// add % as prefix and suffix to every element for relative searching
|
||||||
OR 'admin'= :role");
|
$tags = array_map(function($x){ return '%'.$x.'%'; }, $tags);
|
||||||
$stmt->execute(array(
|
$sql = "";
|
||||||
':username' => $_SESSION['mailcow_cc_username'],
|
foreach ($tags as $key => $tag) {
|
||||||
':role' => $_SESSION['mailcow_cc_role'],
|
$sql = $sql."SELECT DISTINCT `domain` FROM `tags_domain` WHERE `tag_name` LIKE ?"; // distinct, avoid duplicates
|
||||||
));
|
if ($key === array_key_last($tags)) break;
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
|
||||||
while($row = array_shift($rows)) {
|
}
|
||||||
$domains[] = $row['domain'];
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($tags);
|
||||||
|
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
if ($_SESSION['mailcow_cc_role'] == "admin")
|
||||||
|
$domains[] = $row['domain'];
|
||||||
|
elseif (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain']))
|
||||||
|
$domains[] = $row['domain'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get all
|
||||||
|
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
|
||||||
|
WHERE (`domain` IN (
|
||||||
|
SELECT `domain` from `domain_admins`
|
||||||
|
WHERE (`active`='1' AND `username` = :username))
|
||||||
|
)
|
||||||
|
OR 'admin'= :role");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $_SESSION['mailcow_cc_username'],
|
||||||
|
':role' => $_SESSION['mailcow_cc_role'],
|
||||||
|
));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
$domains[] = $row['domain'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $domains;
|
return $domains;
|
||||||
break;
|
break;
|
||||||
case 'domain_details':
|
case 'domain_details':
|
||||||
@ -3478,6 +3619,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
|
$domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
(isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
|
(isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
|
||||||
}
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT `tag_name`
|
||||||
|
FROM `tags_domain` WHERE `domain`= :domain");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':domain' => $_data
|
||||||
|
));
|
||||||
|
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while ($tag = array_shift($tags)) {
|
||||||
|
$domaindata['tags'][] = $tag['tag_name'];
|
||||||
|
}
|
||||||
|
|
||||||
return $domaindata;
|
return $domaindata;
|
||||||
break;
|
break;
|
||||||
case 'mailbox_details':
|
case 'mailbox_details':
|
||||||
@ -3613,6 +3764,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
$mailboxdata['is_relayed'] = $row['backupmx'];
|
$mailboxdata['is_relayed'] = $row['backupmx'];
|
||||||
}
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT `tag_name`
|
||||||
|
FROM `tags_mailbox` WHERE `username`= :username");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $_data
|
||||||
|
));
|
||||||
|
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while ($tag = array_shift($tags)) {
|
||||||
|
$mailboxdata['tags'][] = $tag['tag_name'];
|
||||||
|
}
|
||||||
|
|
||||||
return $mailboxdata;
|
return $mailboxdata;
|
||||||
break;
|
break;
|
||||||
@ -4342,6 +4502,108 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'tags_domain':
|
||||||
|
if (!is_array($_data['domain'])) {
|
||||||
|
$domains = array();
|
||||||
|
$domains[] = $_data['domain'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$domains = $_data['domain'];
|
||||||
|
}
|
||||||
|
$tags = $_data['tags'];
|
||||||
|
if (!is_array($tags)) $tags = array();
|
||||||
|
|
||||||
|
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wasModified = false;
|
||||||
|
foreach ($domains as $domain) {
|
||||||
|
if (!is_valid_domain_name($domain)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'domain_invalid'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($tags as $tag){
|
||||||
|
// delete tag
|
||||||
|
$wasModified = true;
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `tags_domain` WHERE `domain` = :domain AND `tag_name` = :tag_name");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':domain' => $domain,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$wasModified) return false;
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('domain_modified', $domain)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'tags_mailbox':
|
||||||
|
if (!is_array($_data['username'])) {
|
||||||
|
$usernames = array();
|
||||||
|
$usernames[] = $_data['username'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$usernames = $_data['username'];
|
||||||
|
}
|
||||||
|
$tags = $_data['tags'];
|
||||||
|
if (!is_array($tags)) $tags = array();
|
||||||
|
|
||||||
|
$wasModified = false;
|
||||||
|
foreach ($usernames as $username) {
|
||||||
|
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'email invalid'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_now = mailbox('get', 'mailbox_details', $username);
|
||||||
|
$domain = $is_now['domain'];
|
||||||
|
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete tags
|
||||||
|
foreach($tags as $tag){
|
||||||
|
$wasModified = true;
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM `tags_mailbox` WHERE `username` = :username AND `tag_name` = :tag_name");
|
||||||
|
$stmt->execute(array(
|
||||||
|
':username' => $username,
|
||||||
|
':tag_name' => $tag,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$wasModified) return false;
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => array('mailbox_modified', $username)
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
|||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "22032022_1330";
|
$db_version = "02052022_1500";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
@ -23,35 +23,35 @@ function init_db_schema() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$views = array(
|
$views = array(
|
||||||
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
|
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
|
||||||
SELECT goto, IFNULL(GROUP_CONCAT(address ORDER BY address SEPARATOR ' '), '') AS address FROM alias
|
SELECT goto, IFNULL(GROUP_CONCAT(address ORDER BY address SEPARATOR ' '), '') AS address FROM alias
|
||||||
WHERE address!=goto
|
WHERE address!=goto
|
||||||
AND active = '1'
|
AND active = '1'
|
||||||
AND sogo_visible = '1'
|
AND sogo_visible = '1'
|
||||||
AND address NOT LIKE '@%'
|
AND address NOT LIKE '@%'
|
||||||
GROUP BY goto;",
|
GROUP BY goto;",
|
||||||
// START
|
// START
|
||||||
// Unused at the moment - we cannot allow to show a foreign mailbox as sender address in SOGo, as SOGo does not like this
|
// Unused at the moment - we cannot allow to show a foreign mailbox as sender address in SOGo, as SOGo does not like this
|
||||||
// We need to create delegation in SOGo AND set a sender_acl in mailcow to allow to send as user X
|
// We need to create delegation in SOGo AND set a sender_acl in mailcow to allow to send as user X
|
||||||
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
|
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
|
||||||
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
|
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
|
||||||
WHERE send_as NOT LIKE '@%'
|
WHERE send_as NOT LIKE '@%'
|
||||||
GROUP BY logged_in_as;",
|
GROUP BY logged_in_as;",
|
||||||
// END
|
// END
|
||||||
"grouped_sender_acl_external" => "CREATE VIEW grouped_sender_acl_external (username, send_as_acl) AS
|
"grouped_sender_acl_external" => "CREATE VIEW grouped_sender_acl_external (username, send_as_acl) AS
|
||||||
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
|
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
|
||||||
WHERE send_as NOT LIKE '@%' AND external = '1'
|
WHERE send_as NOT LIKE '@%' AND external = '1'
|
||||||
GROUP BY logged_in_as;",
|
GROUP BY logged_in_as;",
|
||||||
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
|
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
|
||||||
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
|
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
|
||||||
LEFT OUTER JOIN alias_domain ON target_domain=domain
|
LEFT OUTER JOIN alias_domain ON target_domain=domain
|
||||||
GROUP BY username;",
|
GROUP BY username;",
|
||||||
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
|
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
|
||||||
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
||||||
WHERE filter_type = 'prefilter';",
|
WHERE filter_type = 'prefilter';",
|
||||||
"sieve_after" => "CREATE VIEW sieve_after (id, username, script_name, script_data) AS
|
"sieve_after" => "CREATE VIEW sieve_after (id, username, script_name, script_data) AS
|
||||||
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
|
||||||
WHERE filter_type = 'postfilter';"
|
WHERE filter_type = 'postfilter';"
|
||||||
);
|
);
|
||||||
|
|
||||||
$tables = array(
|
$tables = array(
|
||||||
@ -251,6 +251,26 @@ function init_db_schema() {
|
|||||||
),
|
),
|
||||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
),
|
),
|
||||||
|
"tags_domain" => array(
|
||||||
|
"cols" => array(
|
||||||
|
"tag_name" => "VARCHAR(255) NOT NULL",
|
||||||
|
"domain" => "VARCHAR(255) NOT NULL"
|
||||||
|
),
|
||||||
|
"keys" => array(
|
||||||
|
"fkey" => array(
|
||||||
|
"fk_tags_domain" => array(
|
||||||
|
"col" => "domain",
|
||||||
|
"ref" => "domain.domain",
|
||||||
|
"delete" => "CASCADE",
|
||||||
|
"update" => "NO ACTION"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"unique" => array(
|
||||||
|
"tag_name" => array("tag_name", "domain")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
|
),
|
||||||
"tls_policy_override" => array(
|
"tls_policy_override" => array(
|
||||||
"cols" => array(
|
"cols" => array(
|
||||||
"id" => "INT NOT NULL AUTO_INCREMENT",
|
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||||
@ -325,6 +345,26 @@ function init_db_schema() {
|
|||||||
),
|
),
|
||||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
),
|
),
|
||||||
|
"tags_mailbox" => array(
|
||||||
|
"cols" => array(
|
||||||
|
"tag_name" => "VARCHAR(255) NOT NULL",
|
||||||
|
"username" => "VARCHAR(255) NOT NULL"
|
||||||
|
),
|
||||||
|
"keys" => array(
|
||||||
|
"fkey" => array(
|
||||||
|
"fk_tags_mailbox" => array(
|
||||||
|
"col" => "username",
|
||||||
|
"ref" => "mailbox.username",
|
||||||
|
"delete" => "CASCADE",
|
||||||
|
"update" => "NO ACTION"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"unique" => array(
|
||||||
|
"tag_name" => array("tag_name", "username")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||||
|
),
|
||||||
"sieve_filters" => array(
|
"sieve_filters" => array(
|
||||||
"cols" => array(
|
"cols" => array(
|
||||||
"id" => "INT NOT NULL AUTO_INCREMENT",
|
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||||
|
@ -148,6 +148,9 @@ $ACCESS_TOKEN_LIFETIME = 86400;
|
|||||||
// Logout from mailcow after first OAuth2 session profile request
|
// Logout from mailcow after first OAuth2 session profile request
|
||||||
$OAUTH2_FORGET_SESSION_AFTER_LOGIN = false;
|
$OAUTH2_FORGET_SESSION_AFTER_LOGIN = false;
|
||||||
|
|
||||||
|
// Set a limit for mailbox and domain tagging
|
||||||
|
$TAGGING_LIMIT = 25;
|
||||||
|
|
||||||
// MAILBOX_DEFAULT_ATTRIBUTES define default attributes for new mailboxes
|
// MAILBOX_DEFAULT_ATTRIBUTES define default attributes for new mailboxes
|
||||||
// These settings will not change existing mailboxes
|
// These settings will not change existing mailboxes
|
||||||
|
|
||||||
|
@ -156,6 +156,12 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
if (!invalid) {
|
if (!invalid) {
|
||||||
var attr_to_merge = $(this).closest("form").serializeObject();
|
var attr_to_merge = $(this).closest("form").serializeObject();
|
||||||
|
// parse possible JSON Strings
|
||||||
|
for (var [key, value] of Object.entries(attr_to_merge)) {
|
||||||
|
try {
|
||||||
|
attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
var api_attr = $.extend(api_attr, attr_to_merge)
|
var api_attr = $.extend(api_attr, attr_to_merge)
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -263,6 +269,12 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
if (!invalid) {
|
if (!invalid) {
|
||||||
var attr_to_merge = $(this).closest("form").serializeObject();
|
var attr_to_merge = $(this).closest("form").serializeObject();
|
||||||
|
// parse possible JSON Strings
|
||||||
|
for (var [key, value] of Object.entries(attr_to_merge)) {
|
||||||
|
try {
|
||||||
|
attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
var api_attr = $.extend(api_attr, attr_to_merge)
|
var api_attr = $.extend(api_attr, attr_to_merge)
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -329,6 +341,7 @@ $(document).ready(function() {
|
|||||||
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
|
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
|
||||||
multi_data[id].push($(this).data('item'));
|
multi_data[id].push($(this).data('item'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof $(this).data('text') !== 'undefined') {
|
if (typeof $(this).data('text') !== 'undefined') {
|
||||||
$("#DeleteText").empty();
|
$("#DeleteText").empty();
|
||||||
$("#DeleteText").text($(this).data('text'));
|
$("#DeleteText").text($(this).data('text'));
|
||||||
@ -340,9 +353,9 @@ $(document).ready(function() {
|
|||||||
$("#ItemsToDelete").empty();
|
$("#ItemsToDelete").empty();
|
||||||
for (var i in data_array) {
|
for (var i in data_array) {
|
||||||
data_array[i] = decodeURIComponent(data_array[i]);
|
data_array[i] = decodeURIComponent(data_array[i]);
|
||||||
$("#ItemsToDelete").append("<li>" + data_array[i] + "</li>");
|
$("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
$('#ConfirmDeleteModal').modal({
|
$('#ConfirmDeleteModal').modal({
|
||||||
backdrop: 'static',
|
backdrop: 'static',
|
||||||
keyboard: false
|
keyboard: false
|
||||||
|
@ -48,7 +48,7 @@ $(document).ready(function() {
|
|||||||
$(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
|
$(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
|
||||||
}
|
}
|
||||||
$(div).animate({ left: 0},interval);
|
$(div).animate({ left: 0},interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// form cache
|
// form cache
|
||||||
$('[data-cached-form="true"]').formcache({key: $(this).data('id')});
|
$('[data-cached-form="true"]').formcache({key: $(this).data('id')});
|
||||||
@ -273,4 +273,50 @@ $(document).ready(function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// tag boxes
|
||||||
|
$('.tag-box .tag-add').click(function(){
|
||||||
|
addTag(this);
|
||||||
|
});
|
||||||
|
$(".tag-box .tag-input").keydown(function (e) {
|
||||||
|
if (e.which == 13){
|
||||||
|
e.preventDefault();
|
||||||
|
addTag(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function addTag(tagAddElem){
|
||||||
|
var tagboxElem = $(tagAddElem).parent();
|
||||||
|
var tagInputElem = $(tagboxElem).find(".tag-input")[0];
|
||||||
|
var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
|
||||||
|
|
||||||
|
var tag = escapeHtml($(tagInputElem).val());
|
||||||
|
var value_tags = [];
|
||||||
|
try {
|
||||||
|
value_tags = JSON.parse($(tagValuesElem).val());
|
||||||
|
} catch {}
|
||||||
|
if (!Array.isArray(value_tags)) value_tags = [];
|
||||||
|
if (value_tags.includes(tag)) return;
|
||||||
|
|
||||||
|
$('<span class="badge badge-primary tag-badge btn-badge"><i class="bi bi-tag-fill"></i> ' + tag + '</span>').insertBefore('.tag-input').click(function(){
|
||||||
|
var del_tag = unescapeHtml($(this).text());
|
||||||
|
var del_tags = [];
|
||||||
|
try {
|
||||||
|
del_tags = JSON.parse($(tagValuesElem).val());
|
||||||
|
} catch {}
|
||||||
|
if (Array.isArray(del_tags)){
|
||||||
|
del_tags.splice(del_tags.indexOf(del_tag), 1);
|
||||||
|
$(tagValuesElem).val(JSON.stringify(del_tags));
|
||||||
|
}
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
value_tags.push($(tagInputElem).val());
|
||||||
|
$(tagValuesElem).val(JSON.stringify(value_tags));
|
||||||
|
$(tagInputElem).val('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
||||||
|
function escapeHtml(n){var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
|
||||||
|
function unescapeHtml(t){var n={"&":"&","<":"<",">":">",""":'"',"'":"'","/":"/","`":"`","=":"="};return String(t).replace(/&|<|>|"|'|/|`|=/g,function(t){return n[t]})}
|
||||||
|
@ -236,9 +236,6 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
jQuery(function($){
|
jQuery(function($){
|
||||||
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
|
||||||
var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
|
|
||||||
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
|
|
||||||
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
|
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
|
||||||
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
|
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
|
||||||
function unix_time_format(i){return""==i?'<i class="bi bi-x-lg"></i>':new Date(i?1e3*i:0).toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}
|
function unix_time_format(i){return""==i?'<i class="bi bi-x-lg"></i>':new Date(i?1e3*i:0).toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}
|
||||||
@ -293,6 +290,7 @@ jQuery(function($){
|
|||||||
{"name":"rl","title":"RL","breakpoints":"xs sm md lg","style":{"min-width":"100px","width":"100px"}},
|
{"name":"rl","title":"RL","breakpoints":"xs sm md lg","style":{"min-width":"100px","width":"100px"}},
|
||||||
{"name":"backupmx","filterable": false,"style":{"min-width":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md lg","formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
{"name":"backupmx","filterable": false,"style":{"min-width":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md lg","formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||||
{"name":"domain_admins","title":lang.domain_admins,"style":{"word-break":"break-all","min-width":"200px"},"breakpoints":"xs sm md lg","filterable":(role == "admin"),"visible":(role == "admin")},
|
{"name":"domain_admins","title":lang.domain_admins,"style":{"word-break":"break-all","min-width":"200px"},"breakpoints":"xs sm md lg","filterable":(role == "admin"),"visible":(role == "admin")},
|
||||||
|
{"name":"tags","title":"Tags","style":{},"breakpoints":"xs sm md lg"},
|
||||||
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
|
||||||
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||||
],
|
],
|
||||||
@ -330,6 +328,13 @@ jQuery(function($){
|
|||||||
'<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
|
'<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(item.tags)){
|
||||||
|
var tags = '';
|
||||||
|
for (var i = 0; i < item.tags.length; i++)
|
||||||
|
tags += '<span class="badge badge-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
|
||||||
|
item.tags = tags;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.backupmx == 1) {
|
if (item.backupmx == 1) {
|
||||||
if (item.relay_unknown_only == 1) {
|
if (item.relay_unknown_only == 1) {
|
||||||
item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
|
item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
|
||||||
@ -418,6 +423,7 @@ jQuery(function($){
|
|||||||
},
|
},
|
||||||
{"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
|
{"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
|
||||||
/* {"name":"rl","title":"RL","breakpoints":"all","style":{"width":"125px"}}, */
|
/* {"name":"rl","title":"RL","breakpoints":"all","style":{"width":"125px"}}, */
|
||||||
|
{"name":"tags","title":"Tags","style":{},"breakpoints":"xs sm md lg"},
|
||||||
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':(0==value?'<i class="bi bi-x-lg"></i>':2==value&&'—');}},
|
{"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':(0==value?'<i class="bi bi-x-lg"></i>':2==value&&'—');}},
|
||||||
{"name":"action","filterable": false,"sortable": false,"style":{"min-width":"290px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
{"name":"action","filterable": false,"sortable": false,"style":{"min-width":"290px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
|
||||||
],
|
],
|
||||||
@ -497,6 +503,13 @@ jQuery(function($){
|
|||||||
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
|
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
|
||||||
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
|
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
|
||||||
item.username = escapeHtml(item.username);
|
item.username = escapeHtml(item.username);
|
||||||
|
|
||||||
|
if (Array.isArray(item.tags)){
|
||||||
|
var tags = '';
|
||||||
|
for (var i = 0; i < item.tags.length; i++)
|
||||||
|
tags += '<span class="badge badge-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
|
||||||
|
item.tags = tags;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -14,17 +14,20 @@ function api_log($_data) {
|
|||||||
if ($data == 'csrf_token') {
|
if ($data == 'csrf_token') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($value = json_decode($value, true)) {
|
|
||||||
unset($value["csrf_token"]);
|
$value = json_decode($value, true);
|
||||||
|
if ($value) {
|
||||||
|
if (is_array($value)) unset($value["csrf_token"]);
|
||||||
foreach ($value as $key => &$val) {
|
foreach ($value as $key => &$val) {
|
||||||
if(preg_match("/pass/i", $key)) {
|
if(preg_match("/pass/i", $key)) {
|
||||||
$val = '*';
|
$val = '*';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$value = json_encode($value);
|
$value = json_encode($value);
|
||||||
}
|
}
|
||||||
$data_var[] = $data . "='" . $value . "'";
|
$data_var[] = $data . "='" . $value . "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$log_line = array(
|
$log_line = array(
|
||||||
'time' => time(),
|
'time' => time(),
|
||||||
@ -41,7 +44,7 @@ function api_log($_data) {
|
|||||||
'msg' => 'Redis: '.$e
|
'msg' => 'Redis: '.$e
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['query'])) {
|
if (isset($_GET['query'])) {
|
||||||
@ -82,10 +85,10 @@ if (isset($_GET['query'])) {
|
|||||||
if ($action == 'delete') {
|
if ($action == 'delete') {
|
||||||
$_POST['items'] = $request;
|
$_POST['items'] = $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
api_log($_POST);
|
api_log($_POST);
|
||||||
|
|
||||||
|
|
||||||
$request_incomplete = json_encode(array(
|
$request_incomplete = json_encode(array(
|
||||||
'type' => 'error',
|
'type' => 'error',
|
||||||
'msg' => 'Cannot find attributes in post data'
|
'msg' => 'Cannot find attributes in post data'
|
||||||
@ -486,7 +489,12 @@ if (isset($_GET['query'])) {
|
|||||||
case "domain":
|
case "domain":
|
||||||
switch ($object) {
|
switch ($object) {
|
||||||
case "all":
|
case "all":
|
||||||
$domains = mailbox('get', 'domains');
|
$tags = null;
|
||||||
|
if (isset($_GET['tags']) && $_GET['tags'] != '')
|
||||||
|
$tags = explode(',', $_GET['tags']);
|
||||||
|
|
||||||
|
$domains = mailbox('get', 'domains', null, $tags);
|
||||||
|
|
||||||
if (!empty($domains)) {
|
if (!empty($domains)) {
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
if ($details = mailbox('get', 'domain_details', $domain)) {
|
if ($details = mailbox('get', 'domain_details', $domain)) {
|
||||||
@ -952,23 +960,20 @@ if (isset($_GET['query'])) {
|
|||||||
switch ($object) {
|
switch ($object) {
|
||||||
case "all":
|
case "all":
|
||||||
case "reduced":
|
case "reduced":
|
||||||
if (empty($extra)) {
|
$tags = null;
|
||||||
$domains = mailbox('get', 'domains');
|
if (isset($_GET['tags']) && $_GET['tags'] != '')
|
||||||
}
|
$tags = explode(',', $_GET['tags']);
|
||||||
else {
|
|
||||||
$domains = explode(',', $extra);
|
if (empty($extra)) $domains = mailbox('get', 'domains');
|
||||||
}
|
else $domains = explode(',', $extra);
|
||||||
|
|
||||||
if (!empty($domains)) {
|
if (!empty($domains)) {
|
||||||
foreach ($domains as $domain) {
|
foreach ($domains as $domain) {
|
||||||
$mailboxes = mailbox('get', 'mailboxes', $domain);
|
$mailboxes = mailbox('get', 'mailboxes', $domain, $tags);
|
||||||
if (!empty($mailboxes)) {
|
if (!empty($mailboxes)) {
|
||||||
foreach ($mailboxes as $mailbox) {
|
foreach ($mailboxes as $mailbox) {
|
||||||
if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) {
|
if ($details = mailbox('get', 'mailbox_details', $mailbox, $object)) $data[] = $details;
|
||||||
$data[] = $details;
|
else continue;
|
||||||
}
|
|
||||||
else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -980,7 +985,17 @@ if (isset($_GET['query'])) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$data = mailbox('get', 'mailbox_details', $object);
|
$tags = null;
|
||||||
|
if (isset($_GET['tags']) && $_GET['tags'] != '')
|
||||||
|
$tags = explode(',', $_GET['tags']);
|
||||||
|
|
||||||
|
$mailboxes = mailbox('get', 'mailboxes', $object, $tags);
|
||||||
|
if (!empty($mailboxes)) {
|
||||||
|
foreach ($mailboxes as $mailbox) {
|
||||||
|
if ($details = mailbox('get', 'mailbox_details', $mailbox)) $data[] = $details;
|
||||||
|
else continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
process_get_return($data);
|
process_get_return($data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1580,13 +1595,25 @@ if (isset($_GET['query'])) {
|
|||||||
process_delete_return(dkim('delete', array('domains' => $items)));
|
process_delete_return(dkim('delete', array('domains' => $items)));
|
||||||
break;
|
break;
|
||||||
case "domain":
|
case "domain":
|
||||||
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
|
switch ($object){
|
||||||
|
case "tag":
|
||||||
|
process_delete_return(mailbox('delete', 'tags_domain', array('tags' => $items, 'domain' => $extra)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "alias-domain":
|
case "alias-domain":
|
||||||
process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
|
process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
|
||||||
break;
|
break;
|
||||||
case "mailbox":
|
case "mailbox":
|
||||||
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
|
switch ($object){
|
||||||
|
case "tag":
|
||||||
|
process_delete_return(mailbox('delete', 'tags_mailbox', array('tags' => $items, 'username' => $extra)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "resource":
|
case "resource":
|
||||||
process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
|
process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
|
||||||
|
@ -99,6 +99,7 @@
|
|||||||
"subscribeall": "Subscribe all folders",
|
"subscribeall": "Subscribe all folders",
|
||||||
"syncjob": "Add sync job",
|
"syncjob": "Add sync job",
|
||||||
"syncjob_hint": "Be aware that passwords need to be saved plain-text!",
|
"syncjob_hint": "Be aware that passwords need to be saved plain-text!",
|
||||||
|
"tags": "Tags",
|
||||||
"target_address": "Goto addresses",
|
"target_address": "Goto addresses",
|
||||||
"target_address_info": "<small>Full email address/es (comma-separated).</small>",
|
"target_address_info": "<small>Full email address/es (comma-separated).</small>",
|
||||||
"target_domain": "Target domain",
|
"target_domain": "Target domain",
|
||||||
|
@ -23,6 +23,22 @@
|
|||||||
<input type="text" class="form-control" name="description" value="{{ result.description }}">
|
<input type="text" class="form-control" name="description" value="{{ result.description }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-control tag-box">
|
||||||
|
{% for tag in domain_details.tags %}
|
||||||
|
<span data-action='delete_selected' data-item="{{ tag|url_encode }}" data-id="domain_tag_{{ tag }}" data-api-url='delete/domain/tag/{{ domain }}' class="badge badge-primary tag-badge btn-badge">
|
||||||
|
<i class="bi bi-tag-fill"></i>
|
||||||
|
{{ tag }}
|
||||||
|
</span>
|
||||||
|
{% endfor %}
|
||||||
|
<input type="text" class="tag-input">
|
||||||
|
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
|
||||||
|
<input type="hidden" value="" name="tags" class="tag-values" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
|
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
@ -22,6 +22,22 @@
|
|||||||
<input type="text" class="form-control" name="name" value="{{ result.name }}">
|
<input type="text" class="form-control" name="name" value="{{ result.name }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-control tag-box">
|
||||||
|
{% for tag in mailbox_details.tags %}
|
||||||
|
<span data-action='delete_selected' data-item="{{ tag }}" data-id="mailbox_tag_{{ tag }}" data-api-url='delete/mailbox/tag/{{ mailbox }}' class="badge badge-primary tag-badge btn-badge">
|
||||||
|
<i class="bi bi-tag-fill"></i>
|
||||||
|
{{ tag }}
|
||||||
|
</span>
|
||||||
|
{% endfor %}
|
||||||
|
<input type="text" class="tag-input">
|
||||||
|
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
|
||||||
|
<input type="hidden" value="" name="tags" class="tag-values" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
|
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
|
||||||
<br><span id="quotaBadge" class="badge">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
|
<br><span id="quotaBadge" class="badge">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
|
||||||
|
@ -30,6 +30,16 @@
|
|||||||
<input type="text" class="form-control" name="name">
|
<input type="text" class="form-control" name="name">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-control tag-box">
|
||||||
|
<input type="text" class="tag-input">
|
||||||
|
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
|
||||||
|
<input type="hidden" value="" name="tags" class="tag-values" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="addInputQuota">{{ lang.add.quota_mb }}
|
<label class="control-label col-sm-2" for="addInputQuota">{{ lang.add.quota_mb }}
|
||||||
<br /><span id="quotaBadge" class="badge">max. - MiB</span>
|
<br /><span id="quotaBadge" class="badge">max. - MiB</span>
|
||||||
@ -94,6 +104,16 @@
|
|||||||
<input type="text" class="form-control" name="description">
|
<input type="text" class="form-control" name="description">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2">{{ lang.add.tags }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-control tag-box">
|
||||||
|
<input type="text" class="tag-input">
|
||||||
|
<span class="btn tag-add"><i class="bi bi-plus-lg"></i></span>
|
||||||
|
<input type="hidden" value="" name="tags" class="tag-values" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="aliases">{{ lang.add.max_aliases }}</label>
|
<label class="control-label col-sm-2" for="aliases">{{ lang.add.max_aliases }}</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
@ -188,11 +208,11 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10 btn-group">
|
<div class="col-sm-offset-2 col-sm-10 btn-group">
|
||||||
{% if not skip_sogo %}
|
{% if not skip_sogo %}
|
||||||
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#">{{ lang.add.add_domain_only }}</button>
|
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"tags": []}' href="#">{{ lang.add.add_domain_only }}</button>
|
||||||
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1"}' href="#">{{ lang.add.add_domain_restart }}</button>
|
<button class="btn btn-xs-lg btn-xs-half visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1", "tags": []}' href="#">{{ lang.add.add_domain_restart }}</button>
|
||||||
<div class="clearfix visible-xs"></div>
|
<div class="clearfix visible-xs"></div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#">{{ lang.add.add }}</button>
|
<button class="btn btn-xs-lg visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-success" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"tags": []}' href="#">{{ lang.add.add }}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user