diff --git a/data/Dockerfiles/dockerapi/dockerapi.py b/data/Dockerfiles/dockerapi/dockerapi.py index 03ed5ef0..304c1781 100644 --- a/data/Dockerfiles/dockerapi/dockerapi.py +++ b/data/Dockerfiles/dockerapi/dockerapi.py @@ -499,6 +499,7 @@ class DockerUtils: async with rspamd_password_exec.start(detach=False) as stream: rspamd_password_return = await stream.read_out() + matched = False if "OK" in rspamd_password_return.data.decode('utf-8'): matched = True await container.restart() diff --git a/data/web/edit.php b/data/web/edit.php index ff1ccc44..09db796d 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -38,24 +38,46 @@ if (isset($_SESSION['mailcow_cc_role'])) { $template = 'edit/admin.twig'; $template_data = ['admin' => $admin]; } - elseif (isset($_GET['domain']) && - is_valid_domain_name($_GET["domain"]) && - !empty($_GET["domain"])) { - $domain = $_GET["domain"]; - $result = mailbox('get', 'domain_details', $domain); - $quota_notification_bcc = quota_notification_bcc('get', $domain); - $rl = ratelimit('get', 'domain', $domain); - $rlyhosts = relayhost('get'); - $template = 'edit/domain.twig'; + elseif (isset($_GET['domain'])) { + if (is_valid_domain_name($_GET["domain"]) && + !empty($_GET["domain"])) { + // edit domain + $domain = $_GET["domain"]; + $result = mailbox('get', 'domain_details', $domain); + $quota_notification_bcc = quota_notification_bcc('get', $domain); + $rl = ratelimit('get', 'domain', $domain); + $rlyhosts = relayhost('get'); + $template = 'edit/domain.twig'; + $template_data = [ + 'acl' => $_SESSION['acl'], + 'domain' => $domain, + 'quota_notification_bcc' => $quota_notification_bcc, + 'rl' => $rl, + 'rlyhosts' => $rlyhosts, + 'dkim' => dkim('details', $domain), + 'domain_details' => $result, + ]; + } + } + elseif (isset($_GET["template"])){ + $domain_template = mailbox('get', 'domain_templates', $_GET["template"]); + if ($domain_template){ $template_data = [ - 'acl' => $_SESSION['acl'], - 'domain' => $domain, - 'quota_notification_bcc' => $quota_notification_bcc, - 'rl' => $rl, - 'rlyhosts' => $rlyhosts, - 'dkim' => dkim('details', $domain), - 'domain_details' => $result, + 'template' => $domain_template ]; + $template = 'edit/domain-templates.twig'; + $result = true; + } + else { + $mailbox_template = mailbox('get', 'mailbox_templates', $_GET["template"]); + if ($mailbox_template){ + $template_data = [ + 'template' => $mailbox_template + ]; + $template = 'edit/mailbox-templates.twig'; + $result = true; + } + } } elseif (isset($_GET['oauth2client']) && is_numeric($_GET["oauth2client"]) && @@ -79,29 +101,32 @@ if (isset($_SESSION['mailcow_cc_role'])) { 'dkim' => dkim('details', $alias_domain), ]; } - elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) { - $mailbox = html_entity_decode(rawurldecode($_GET["mailbox"])); - $result = mailbox('get', 'mailbox_details', $mailbox); - $rl = ratelimit('get', 'mailbox', $mailbox); - $pushover_data = pushover('get', $mailbox); - $quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox); - $quarantine_category = mailbox('get', 'quarantine_category', $mailbox); - $get_tls_policy = mailbox('get', 'tls_policy', $mailbox); - $rlyhosts = relayhost('get'); - $template = 'edit/mailbox.twig'; - $template_data = [ - 'acl' => $_SESSION['acl'], - 'mailbox' => $mailbox, - 'rl' => $rl, - 'pushover_data' => $pushover_data, - 'quarantine_notification' => $quarantine_notification, - 'quarantine_category' => $quarantine_category, - 'get_tls_policy' => $get_tls_policy, - 'rlyhosts' => $rlyhosts, - 'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox), - 'user_acls' => acl('get', 'user', $mailbox), - 'mailbox_details' => $result - ]; + elseif (isset($_GET['mailbox'])){ + if(filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) { + // edit mailbox + $mailbox = html_entity_decode(rawurldecode($_GET["mailbox"])); + $result = mailbox('get', 'mailbox_details', $mailbox); + $rl = ratelimit('get', 'mailbox', $mailbox); + $pushover_data = pushover('get', $mailbox); + $quarantine_notification = mailbox('get', 'quarantine_notification', $mailbox); + $quarantine_category = mailbox('get', 'quarantine_category', $mailbox); + $get_tls_policy = mailbox('get', 'tls_policy', $mailbox); + $rlyhosts = relayhost('get'); + $template = 'edit/mailbox.twig'; + $template_data = [ + 'acl' => $_SESSION['acl'], + 'mailbox' => $mailbox, + 'rl' => $rl, + 'pushover_data' => $pushover_data, + 'quarantine_notification' => $quarantine_notification, + 'quarantine_category' => $quarantine_category, + 'get_tls_policy' => $get_tls_policy, + 'rlyhosts' => $rlyhosts, + 'sender_acl_handles' => mailbox('get', 'sender_acl_handles', $mailbox), + 'user_acls' => acl('get', 'user', $mailbox), + 'mailbox_details' => $result + ]; + } } elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) { $relayhost = intval($_GET["relayhost"]); diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 2cf9f6c6..55c8d6bc 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -1020,6 +1020,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { if (empty($name)) { $name = $local_part; } + if (isset($_data['protocol_access'])) { + $_data['protocol_access'] = (array)$_data['protocol_access']; + $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0; + $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0; + $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0; + $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0; + } $active = intval($_data['active']); $force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']); $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']); @@ -1200,10 +1207,63 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':domain' => $domain, ':active' => $active )); - $stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)"); - $stmt->execute(array( - ':username' => $username - )); + + + if (isset($_data['acl'])) { + $_data['acl'] = (array)$_data['acl']; + $_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0; + $_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0; + $_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0; + $_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0; + $_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0; + $_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; + $_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; + $_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; + $_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; + $_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; + $_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0; + $_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0; + $_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0; + + $stmt = $pdo->prepare("INSERT INTO `user_acl` + (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`, + `pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`) + VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset, + :pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) "); + $stmt->execute(array( + ':username' => $username, + ':spam_alias' => $_data['spam_alias'], + ':tls_policy' => $_data['tls_policy'], + ':spam_score' => $_data['spam_score'], + ':spam_policy' => $_data['spam_policy'], + ':delimiter_action' => $_data['delimiter_action'], + ':syncjobs' => $_data['syncjobs'], + ':eas_reset' => $_data['eas_reset'], + ':sogo_profile_reset' => $_data['sogo_profile_reset'], + ':pushover' => $_data['pushover'], + ':quarantine' => $_data['quarantine'], + ':quarantine_attachments' => $_data['quarantine_attachments'], + ':quarantine_notification' => $_data['quarantine_notification'], + ':quarantine_category' => $_data['quarantine_category'], + ':app_passwds' => $_data['app_passwds'] + )); + } + else { + $stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)"); + $stmt->execute(array( + ':username' => $username + )); + } + + if (isset($_data['rl_frame']) && isset($_data['rl_value'])){ + ratelimit('edit', 'mailbox', array( + 'object' => $username, + 'rl_frame' => $_data['rl_frame'], + 'rl_value' => $_data['rl_value'] + )); + } + $_SESSION['return'][] = array( 'type' => 'success', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), @@ -1322,6 +1382,191 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'msg' => array('resource_added', htmlspecialchars($name)) ); break; + case 'domain_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'access_denied' + ); + return false; + } + if (empty($_data["template"])){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'template_name_invalid' + ); + return false; + } + + // check if template name exists, return false + $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template"); + $stmt->execute(array( + ":type" => "domain", + ":template" => $_data["template"] + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!empty($row)){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => array('template_exists', $_data["template"]) + ); + return false; + } + + // check attributes + $attr = array(); + $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array(); + $attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0; + $attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0; + $attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0; + $attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0; + $attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0; + $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s"; + $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : ""; + $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1; + $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1; + $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0; + $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0; + $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0; + $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim"; + $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048; + + + // save template + $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) + VALUES (:type, :template, :attributes)"); + $stmt->execute(array( + ":type" => "domain", + ":template" => $_data["template"], + ":attributes" => json_encode($attr) + )); + + // success + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('template_added', $_data["template"]) + ); + return true; + break; + case 'mailbox_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'access_denied' + ); + return false; + } + if (empty($_data["template"])){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'template_name_invalid' + ); + return false; + } + + // check if template name exists, return false + $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template"); + $stmt->execute(array( + ":type" => "mailbox", + ":template" => $_data["template"] + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!empty($row)){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => array('template_exists', $_data["template"]) + ); + return false; + } + + + // check attributes + $attr = array(); + $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0; + $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array(); + $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']); + $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']); + $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s"; + $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : ""; + $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']); + $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']); + $attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1; + $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']); + $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']); + if (isset($_data['protocol_access'])) { + $_data['protocol_access'] = (array)$_data['protocol_access']; + $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']); + $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']); + $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']); + $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']); + } + else { + $attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']); + $attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']); + $attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']); + $attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']); + } + if (isset($_data['acl'])) { + $_data['acl'] = (array)$_data['acl']; + $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0; + $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0; + $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0; + $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0; + $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0; + $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; + $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0; + $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0; + } else { + $_data['acl'] = (array)$_data['acl']; + $attr['acl_spam_alias'] = 1; + $attr['acl_tls_policy'] = 1; + $attr['acl_spam_score'] = 1; + $attr['acl_spam_policy'] = 1; + $attr['acl_delimiter_action'] = 1; + $attr['acl_syncjobs'] = 0; + $attr['acl_eas_reset'] = 1; + $attr['acl_sogo_profile_reset'] = 0; + $attr['acl_pushover'] = 1; + $attr['acl_quarantine'] = 1; + $attr['acl_quarantine_attachments'] = 1; + $attr['acl_quarantine_notification'] = 1; + $attr['acl_quarantine_category'] = 1; + $attr['acl_app_passwds'] = 1; + } + + + + // save template + $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) + VALUES (:type, :template, :attributes)"); + $stmt->execute(array( + ":type" => "mailbox", + ":template" => $_data["template"], + ":attributes" => json_encode($attr) + )); + + // success + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('template_added', $_data["template"]) + ); + return true; + break; } break; case 'edit': @@ -2472,6 +2717,79 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { } } break; + case 'domain_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'access_denied' + ); + return false; + } + if (!is_array($_data['ids'])) { + $ids = array(); + $ids[] = $_data['ids']; + } + else { + $ids = $_data['ids']; + } + foreach ($ids as $id) { + $is_now = mailbox("get", "domain_templates", $id); + if (empty($is_now) || + $is_now["type"] != "domain"){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'template_id_invalid' + ); + continue; + } + + // check name + if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){ + // keep template name of Default template + $_data["template"] = $is_now["template"]; + } + else { + $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"]; + } + // check attributes + $attr = array(); + $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array(); + $attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0; + $attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0; + $attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0; + $attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0; + $attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0; + $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s"; + $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : ""; + $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1; + $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1; + $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0; + $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0; + $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0; + $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim"; + $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048; + + // update template + $stmt = $pdo->prepare("UPDATE `templates` + SET `template` = :template, `attributes` = :attributes + WHERE id = :id"); + $stmt->execute(array( + ":id" => $id , + ":template" => $_data["template"] , + ":attributes" => json_encode($attr) + )); + } + + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('template_modified', $_data["template"]) + ); + return true; + break; case 'mailbox': if (!is_array($_data['username'])) { $usernames = array(); @@ -2814,6 +3132,110 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); } break; + case 'mailbox_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'access_denied' + ); + return false; + } + if (!is_array($_data['ids'])) { + $ids = array(); + $ids[] = $_data['ids']; + } + else { + $ids = $_data['ids']; + } + foreach ($ids as $id) { + $is_now = mailbox("get", "mailbox_templates", $id); + if (empty($is_now) || + $is_now["type"] != "mailbox"){ + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra), + 'msg' => 'template_id_invalid' + ); + continue; + } + + + // check name + if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){ + // keep template name of Default template + $_data["template"] = $is_now["template"]; + } + else { + $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"]; + } + // check attributes + $attr = array(); + $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0; + $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags']; + $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification']; + $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category']; + $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame']; + $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value']; + $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update']; + $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access']; + $attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active']; + $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in']; + $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out']; + if (isset($_data['protocol_access'])) { + $_data['protocol_access'] = (array)$_data['protocol_access']; + $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0; + $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0; + $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0; + $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0; + } + else { + foreach ($is_now as $key => $value){ + $attr[$key] = $is_now[$key]; + } + } + if (isset($_data['acl'])) { + $_data['acl'] = (array)$_data['acl']; + $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0; + $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0; + $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0; + $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0; + $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0; + $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0; + $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0; + $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0; + $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0; + $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0; + } else { + foreach ($is_now as $key => $value){ + $attr[$key] = $is_now[$key]; + } + } + + + // update template + $stmt = $pdo->prepare("UPDATE `templates` + SET `template` = :template, `attributes` = :attributes + WHERE id = :id"); + $stmt->execute(array( + ":id" => $id , + ":template" => $_data["template"] , + ":attributes" => json_encode($attr) + )); + } + + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => array('template_modified', $_data["template"]) + ); + return true; + break; case 'resource': if (!is_array($_data['name'])) { $names = array(); @@ -3606,6 +4028,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `mailboxes`, `defquota`, `maxquota`, + `created`, + `modified`, `quota`, `relayhost`, `relay_all_recipients`, @@ -3678,6 +4102,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $domaindata['relay_all_recipients_int'] = $row['relay_all_recipients']; $domaindata['relay_unknown_only'] = $row['relay_unknown_only']; $domaindata['relay_unknown_only_int'] = $row['relay_unknown_only']; + $domaindata['created'] = $row['created']; + $domaindata['modified'] = $row['modified']; $stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias` WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2)) AND `address` NOT IN ( @@ -3711,6 +4137,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { return $domaindata; break; + case 'domain_templates': + if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { + return false; + } + $_data = (isset($_data)) ? intval($_data) : null; + + if (isset($_data)){ + $stmt = $pdo->prepare("SELECT * FROM `templates` + WHERE `id` = :id AND type = :type"); + $stmt->execute(array( + ":id" => $_data, + ":type" => "domain" + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if (empty($row)){ + return false; + } + + $row["attributes"] = json_decode($row["attributes"], true); + return $row; + } + else { + $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'"); + $stmt->execute(); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (empty($rows)){ + return false; + } + + foreach($rows as $key => $row){ + $rows[$key]["attributes"] = json_decode($row["attributes"], true); + } + return $rows; + } + break; case 'mailbox_details': if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { return false; @@ -3725,6 +4188,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `mailbox`.`domain`, `mailbox`.`local_part`, `mailbox`.`quota`, + `mailbox`.`created`, + `mailbox`.`modified`, `quota2`.`bytes`, `attributes`, `quota2`.`messages` @@ -3743,6 +4208,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { `mailbox`.`domain`, `mailbox`.`local_part`, `mailbox`.`quota`, + `mailbox`.`created`, + `mailbox`.`modified`, `quota2replica`.`bytes`, `attributes`, `quota2replica`.`messages` @@ -3769,6 +4236,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { $mailboxdata['attributes'] = json_decode($row['attributes'], true); $mailboxdata['quota_used'] = intval($row['bytes']); $mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100); + $mailboxdata['created'] = $row['created']; + $mailboxdata['modified'] = $row['modified']; if ($mailboxdata['percent_in_use'] === '- ') { $mailboxdata['percent_class'] = "info"; @@ -3856,6 +4325,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { return $mailboxdata; break; + case 'mailbox_templates': + if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { + return false; + } + $_data = (isset($_data)) ? intval($_data) : null; + + if (isset($_data)){ + $stmt = $pdo->prepare("SELECT * FROM `templates` + WHERE `id` = :id AND type = :type"); + $stmt->execute(array( + ":id" => $_data, + ":type" => "mailbox" + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + + if (empty($row)){ + return false; + } + + $row["attributes"] = json_decode($row["attributes"], true); + return $row; + } + else { + $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'"); + $stmt->execute(); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (empty($rows)){ + return false; + } + + foreach($rows as $key => $row){ + $rows[$key]["attributes"] = json_decode($row["attributes"], true); + } + return $rows; + } + break; case 'resource_details': $resourcedata = array(); if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { @@ -4224,6 +4730,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); } break; + case 'domain_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' + ); + return false; + } + if (!is_array($_data['ids'])) { + $ids = array(); + $ids[] = $_data['ids']; + } + else { + $ids = $_data['ids']; + } + + + foreach ($ids as $id) { + // delete template + $stmt = $pdo->prepare("DELETE FROM `templates` + WHERE id = :id AND type = :type AND NOT template = :template"); + $stmt->execute(array( + ":id" => $id, + ":type" => "domain", + ":template" => "Default" + )); + } + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'template_removed' + ); + return true; + break; case 'alias': if (!is_array($_data['id'])) { $ids = array(); @@ -4518,6 +5060,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); } break; + case 'mailbox_templates': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'access_denied' + ); + return false; + } + if (!is_array($_data['ids'])) { + $ids = array(); + $ids[] = $_data['ids']; + } + else { + $ids = $_data['ids']; + } + + + foreach ($ids as $id) { + // delete template + $stmt = $pdo->prepare("DELETE FROM `templates` + WHERE id = :id AND type = :type AND NOT template = :template"); + $stmt->execute(array( + ":id" => $id, + ":type" => "mailbox", + ":template" => "Default" + )); + } + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), + 'msg' => 'template_removed' + ); + return true; + break; case 'resource': if (!is_array($_data['name'])) { $names = array(); diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index b47bd5c2..d43c9060 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "25072022_2300"; + $db_version = "16112022_1325"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -225,6 +225,22 @@ function init_db_schema() { ), "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" ), + "templates" => array( + "cols" => array( + "id" => "INT NOT NULL AUTO_INCREMENT", + "template" => "VARCHAR(255) NOT NULL", + "type" => "VARCHAR(255) NOT NULL", + "attributes" => "JSON", + "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", + "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP" + ), + "keys" => array( + "primary" => array( + "" => array("id") + ) + ), + "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC" + ), "domain" => array( // Todo: Move some attributes to json "cols" => array( @@ -1292,6 +1308,95 @@ function init_db_schema() { // Fix domain_admins $pdo->query("DELETE FROM `domain_admins` WHERE `domain` = 'ALL';"); + // add default templates + $default_domain_template = array( + "template" => "Default", + "type" => "domain", + "attributes" => array( + "tags" => array(), + "max_num_aliases_for_domain" => 400, + "max_num_mboxes_for_domain" => 10, + "def_quota_for_mbox" => 3072 * 1048576, + "max_quota_for_mbox" => 10240 * 1048576, + "max_quota_for_domain" => 10240 * 1048576, + "rl_frame" => "s", + "rl_value" => "", + "active" => 1, + "gal" => 1, + "backupmx" => 0, + "relay_all_recipients" => 0, + "relay_unknown_only" => 0, + "dkim_selector" => "dkim", + "key_size" => 2048, + "max_quota_for_domain" => 10240 * 1048576, + ) + ); + $default_mailbox_template = array( + "template" => "Default", + "type" => "mailbox", + "attributes" => array( + "tags" => array(), + "quota" => 0, + "quarantine_notification" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_notification']), + "quarantine_category" => strval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['quarantine_category']), + "rl_frame" => "s", + "rl_value" => "", + "force_pw_update" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['force_pw_update']), + "sogo_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sogo_access']), + "active" => 1, + "tls_enforce_in" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_in']), + "tls_enforce_out" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['tls_enforce_out']), + "imap_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['imap_access']), + "pop3_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['pop3_access']), + "smtp_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['smtp_access']), + "sieve_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sieve_access']), + "acl_spam_alias" => 1, + "acl_tls_policy" => 1, + "acl_spam_score" => 1, + "acl_spam_policy" => 1, + "acl_delimiter_action" => 1, + "acl_syncjobs" => 0, + "acl_eas_reset" => 1, + "acl_sogo_profile_reset" => 0, + "acl_pushover" => 1, + "acl_quarantine" => 1, + "acl_quarantine_attachments" => 1, + "acl_quarantine_notification" => 1, + "acl_quarantine_category" => 1, + "acl_app_passwds" => 1, + ) + ); + $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template"); + $stmt->execute(array( + ":type" => "domain", + ":template" => $default_domain_template["template"] + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (empty($row)){ + $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) + VALUES (:type, :template, :attributes)"); + $stmt->execute(array( + ":type" => "domain", + ":template" => $default_domain_template["template"], + ":attributes" => json_encode($default_domain_template["attributes"]) + )); + } + $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template"); + $stmt->execute(array( + ":type" => "mailbox", + ":template" => $default_mailbox_template["template"] + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (empty($row)){ + $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`) + VALUES (:type, :template, :attributes)"); + $stmt->execute(array( + ":type" => "mailbox", + ":template" => $default_mailbox_template["template"], + ":attributes" => json_encode($default_mailbox_template["attributes"]) + )); + } + if (php_sapi_name() == "cli") { echo "DB initialization completed" . PHP_EOL; } else { diff --git a/data/web/js/build/014-mailcow.js b/data/web/js/build/014-mailcow.js index a2e25547..13bc2911 100644 --- a/data/web/js/build/014-mailcow.js +++ b/data/web/js/build/014-mailcow.js @@ -289,37 +289,6 @@ $(document).ready(function() { 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()); - if (!tag) return; - var value_tags = []; - try { - value_tags = JSON.parse($(tagValuesElem).val()); - } catch {} - if (!Array.isArray(value_tags)) value_tags = []; - if (value_tags.includes(tag)) return; - - $(' ' + tag + '').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(''); - } // Dark Mode Loader $('#dark-mode-toggle').click(toggleDarkMode); @@ -343,68 +312,42 @@ $(document).ready(function() { localStorage.setItem('darkmode', 'true'); } } - - // show whats new modal - if (mailcow_cc_role === "admin" || mailcow_cc_role === "domainadmin"){ - if (mailcow_info.updatedAt > last_login){ - var parsedSeenTimestamp = parseInt(localStorage.getItem("seenChangelog")); - if (!isNaN(parsedSeenTimestamp) && mailcow_info.updatedAt < parsedSeenTimestamp) { - console.log("changelog seen"); - return; - } - $.ajax({ - type: 'GET', - url: 'https://api.github.com/repos/' + mailcow_info.project_owner + '/' + mailcow_info.project_repo + '/releases/tags/' + mailcow_info.version_tag, - dataType: 'json', - success: function (data) { - var md = window.markdownit(); - var result = md.render(data.body); - result = parseGithubMarkdownLinks(result); - - $('#showWhatsNewModal').find(".modal-body").html(` -

` + data.name + `

- ` + result + ` - `); - - localStorage.setItem("seenChangelog", Math.floor(Date.now() / 1000).toString()); - } - }); - - new bootstrap.Modal(document.getElementById("showWhatsNewModal"), { - backdrop: 'static', - keyboard: false - }).show(); - } - } - - function parseGithubMarkdownLinks(inputText) { - var replacedText, replacePattern1; - - replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; - replacedText = inputText.replace(replacePattern1, (matched, index, original, input_string) => { - if (matched.includes('github.com')){ - // return short link if it's github link - last_uri_path = matched.split('/'); - last_uri_path = last_uri_path[last_uri_path.length - 1]; - - // adjust Full Changelog link to match last git version and new git version, if link is a compare link - if (matched.includes('/compare/') && mailcow_info.last_version_tag !== ''){ - matched = matched.replace(last_uri_path, mailcow_info.last_version_tag + '...' + mailcow_info.version_tag); - last_uri_path = mailcow_info.last_version_tag + '...' + mailcow_info.version_tag; - } - - return '' + last_uri_path + '
'; - }; - - // if it's not a github link, return complete link - return '' + matched + ''; - }); - - return replacedText; - } }); // https://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]})} + +function addTag(tagAddElem, tag = null){ + var tagboxElem = $(tagAddElem).parent(); + var tagInputElem = $(tagboxElem).find(".tag-input")[0]; + var tagValuesElem = $(tagboxElem).find(".tag-values")[0]; + + if (!tag) + tag = $(tagInputElem).val(); + if (!tag) return; + var value_tags = []; + try { + value_tags = JSON.parse($(tagValuesElem).val()); + } catch {} + if (!Array.isArray(value_tags)) value_tags = []; + if (value_tags.includes(tag)) return; + + $(' ' + escapeHtml(tag) + '').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(tag); + $(tagValuesElem).val(JSON.stringify(value_tags)); + $(tagInputElem).val(''); +} \ No newline at end of file diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index dcc04210..b57f1dbc 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -47,6 +47,12 @@ $(document).ready(function() { if (mailcow_info.branch === "master"){ check_update(mailcow_info.version_tag, mailcow_info.project_url); } + $("#maiclow_version").click(function(){ + if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin") + return; + + showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); + }) // get public ips get_public_ips(); update_container_stats(); @@ -1227,11 +1233,11 @@ function get_public_ips(){ }).then(function(data) { console.log(data); - if (data){ - // display host ips + // display host ips + if (data.ipv4) $("#host_ipv4").text(data.ipv4); + if (data.ipv6) $("#host_ipv6").text(data.ipv6); - } }); } // format hosts uptime seconds to readable string @@ -1452,10 +1458,13 @@ function check_update(current_version, github_repo_url){ } else { // update available $("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning"); - $("#mailcow_update").html( - `` + lang_debug.update_available + ` - `+latest_data.tag_name+`` - ); + $("#mailcow_update").html(lang_debug.update_available + ` `+latest_data.tag_name+``); + $("#mailcow_update_changelog").click(function(){ + if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin") + return; + + showVersionModal("New Release " + latest_data.tag_name, latest_data.tag_name); + }) } }).catch(err => { // err @@ -1470,3 +1479,55 @@ function check_update(current_version, github_repo_url){ $("#mailcow_update").html(""+ lang_debug.update_failed +""); }); } +// show version changelog modal +function showVersionModal(title, version){ + $.ajax({ + type: 'GET', + url: 'https://api.github.com/repos/' + mailcow_info.project_owner + '/' + mailcow_info.project_repo + '/releases/tags/' + version, + dataType: 'json', + success: function (data) { + var md = window.markdownit(); + var result = md.render(data.body); + result = parseGithubMarkdownLinks(result); + + $('#showVersionModal').find(".modal-title").html(title); + $('#showVersionModal').find(".modal-body").html(` +

` + data.name + `

+ ` + result + ` + Github Link: + ` + version + ` + + `); + + new bootstrap.Modal(document.getElementById("showVersionModal"), { + backdrop: 'static', + keyboard: false + }).show(); + } + }); +} +function parseGithubMarkdownLinks(inputText) { + var replacedText, replacePattern1; + + replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim; + replacedText = inputText.replace(replacePattern1, (matched, index, original, input_string) => { + if (matched.includes('github.com')){ + // return short link if it's github link + last_uri_path = matched.split('/'); + last_uri_path = last_uri_path[last_uri_path.length - 1]; + + // adjust Full Changelog link to match last git version and new git version, if link is a compare link + if (matched.includes('/compare/') && mailcow_info.last_version_tag !== ''){ + matched = matched.replace(last_uri_path, mailcow_info.last_version_tag + '...' + mailcow_info.version_tag); + last_uri_path = mailcow_info.last_version_tag + '...' + mailcow_info.version_tag; + } + + return '' + last_uri_path + '
'; + }; + + // if it's not a github link, return complete link + return '' + matched + ''; + }); + + return replacedText; +} \ No newline at end of file diff --git a/data/web/js/site/edit.js b/data/web/js/site/edit.js index 31b9d08b..55a8e6b4 100644 --- a/data/web/js/site/edit.js +++ b/data/web/js/site/edit.js @@ -57,6 +57,17 @@ $(document).ready(function() { $("#multiple_bookings_custom").bind("change keypress keyup blur", function() { $('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); }); + + // load tags + if ($('#tags').length){ + var tagsEl = $('#tags').parent().find('.tag-values')[0]; + console.log($(tagsEl).val()) + var tags = JSON.parse($(tagsEl).val()); + $(tagsEl).val(""); + + for (var i = 0; i < tags.length; i++) + addTag($('#tags'), tags[i]); + } }); jQuery(function($){ diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index 77da5029..8c98e922 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -77,6 +77,90 @@ $(document).ready(function() { $('.dns-modal-body').html(xhr.responseText); } }); + }); + // @Open Domain add modal + $('#addDomainModal').on('show.bs.modal', function(e) { + $.ajax({ + url: '/api/v1/get/domain/template/all', + data: {}, + dataType: 'json', + success: async function(data){ + $('#domain_templates').find('option').remove(); + $('#domain_templates').selectpicker('destroy'); + $('#domain_templates').selectpicker(); + for (var i = 0; i < data.length; i++){ + if (data[i].template === "Default"){ + $('#domain_templates').prepend($('