diff --git a/data/web/css/site/quarantine.css b/data/web/css/site/quarantine.css index 98a74d66..0455b7c1 100644 --- a/data/web/css/site/quarantine.css +++ b/data/web/css/site/quarantine.css @@ -1,102 +1,104 @@ -.pagination a { - text-decoration: none !important; -} - -.panel.panel-default { - overflow: visible !important; -} - -.table-responsive { - overflow: visible !important; -} - -.table-responsive { - overflow-x: scroll !important; -} - -.footer-add-item { - display: block; - text-align: center; - font-style: italic; - padding: 10px; - background: #F5F5F5; -} - -@media (min-width: 992px) { - .container { - width: 100%; - } -} -@media (min-width: 1920px) { - .container { - width: 80%; - } -} - -.mass-actions-quarantine { - user-select: none; -} - -.inputMissingAttr { - border-color: #FF4136; -} - -.modal#qidDetailModal p { - word-break: break-all; -} - -span#qid_detail_score { - font-weight: 700; - margin-left: 5px; -} - -span.rspamd-symbol { - display: inline-block; - margin: 2px 6px 2px 0; - border-radius: 4px; - padding: 0 7px; -} - -span.rspamd-symbol.positive { - background: #4CAF50; - border: 1px solid #4CAF50; - color: white; -} - -span.rspamd-symbol.negative { - background: #ff4136; - border: 1px solid #ff4136; - color: white; -} - -span.rspamd-symbol.neutral { - background: #f5f5f5; - color: #333; - border: 1px solid #ccc; -} - -span.rspamd-symbol span.score { - font-weight: 700; -} - -span.mail-address-item { - background-color: #f5f5f5; - border-radius: 4px; - border: 1px solid #ccc; - padding: 2px 7px; - display: inline-block; - margin: 2px 6px 2px 0; -} - -table tbody tr { - cursor: pointer; -} - -table tbody tr td input[type="checkbox"] { - cursor: pointer; -} -.label-rspamd-action { - font-size:110%; - margin:20px; -} - +.pagination a { + text-decoration: none !important; +} + +.panel.panel-default { + overflow: visible !important; +} + +.table-responsive { + overflow: visible !important; +} + +.table-responsive { + overflow-x: scroll !important; +} + +.footer-add-item { + display: block; + text-align: center; + font-style: italic; + padding: 10px; + background: #F5F5F5; +} + +@media (min-width: 992px) { + .container { + width: 100%; + } +} +@media (min-width: 1920px) { + .container { + width: 80%; + } +} + +.mass-actions-quarantine { + user-select: none; +} + +.inputMissingAttr { + border-color: #FF4136; +} + +.modal#qidDetailModal p { + word-break: break-all; +} + +span#qid_detail_score { + font-weight: 700; + margin-left: 5px; +} + +span.rspamd-symbol { + display: inline-block; + margin: 2px 6px 2px 0; + border-radius: 4px; + padding: 0 7px; +} + +span.rspamd-symbol.positive { + background: #4CAF50; + border: 1px solid #4CAF50; + color: white; +} + +span.rspamd-symbol.negative { + background: #ff4136; + border: 1px solid #ff4136; + color: white; +} + +span.rspamd-symbol.neutral { + background: #f5f5f5; + color: #333; + border: 1px solid #ccc; +} + +span.rspamd-symbol span.score { + font-weight: 700; +} + +span.mail-address-item { + background-color: #f5f5f5; + border-radius: 4px; + border: 1px solid #ccc; + padding: 2px 7px; + display: inline-block; + margin: 2px 6px 2px 0; +} + +table tbody tr { + cursor: pointer; +} + +table tbody tr td input[type="checkbox"] { + cursor: pointer; +} +.label-rspamd-action { + font-size:110%; + margin:20px; +} +.senders-mw220 { + max-width: 220px; +} diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index 0dba1aa8..0e5a9ae6 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -1,731 +1,737 @@ -// Base64 functions -var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; -jQuery(function($){ - // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery - var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; - function jq(myid) {return "#" + myid.replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1" );} - function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} - function validateRegex(e){var t=e.split("/"),n=e,r="";t.length>1&&(n=t[1],r=t[2]);try{return new RegExp(n,r),!0}catch(e){return!1}} - 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 hashCode(t){for(var n=0,r=0;r<t.length;r++)n=t.charCodeAt(r)+((n<<5)-n);return n} - function intToRGB(t){var n=(16777215&t).toString(16).toUpperCase();return"00000".substring(0,6-n.length)+n} - $("#dkim_missing_keys").on('click', function(e) { - e.preventDefault(); - var domains = []; - $('.dkim_missing').each(function() { - domains.push($(this).val()); - }); - $('#dkim_add_domains').val(domains); - }); - $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); - $("#mass_exclude").change(function(){ $("#mass_include").selectpicker('deselectAll'); }); - $("#mass_include").change(function(){ $("#mass_exclude").selectpicker('deselectAll'); }); - $("#mass_disarm").click(function() { $("#mass_send").attr("disabled", !this.checked); }); - $(".admin-ays-dialog").click(function() { return confirm(lang.ays); }); - $(".validate_rspamd_regex").click(function( event ) { - event.preventDefault(); - var regex_map_id = $(this).data('regex-map'); - var regex_data = $(jq(regex_map_id)).val().split(/\r?\n/); - var regex_valid = true; - for(var i = 0;i < regex_data.length;i++){ - if(regex_data[i].startsWith('#') || !regex_data[i]){ - continue; - } - if(!validateRegex(regex_data[i])) { - mailcow_alert_box('Cannot build regex from line ' + (i+1), 'danger'); - var regex_valid = false; - break; - } - if(!regex_data[i].startsWith('/') || !/\/[ims]?$/.test(regex_data[i])){ - mailcow_alert_box('Line ' + (i+1) + ' is invalid', 'danger'); - var regex_valid = false; - break; - } - } - if (regex_valid) { - mailcow_alert_box('Regex OK', 'success'); - $('button[data-id="' + regex_map_id + '"]').attr({"disabled": false}); - } - }); - $('.textarea-code').on('keyup', function() { - $('.submit_rspamd_regex').attr({"disabled": true}); - }); - $("#show_rspamd_global_filters").click(function() { - $.get("inc/ajax/show_rspamd_global_filters.php"); - $("#confirm_show_rspamd_global_filters").hide(); - $("#rspamd_global_filters").removeClass("d-none"); - }); - $("#super_delete").click(function() { return confirm(lang.queue_ays); }); - - $(".refresh_table").on('click', function(e) { - e.preventDefault(); - var table_name = $(this).data('table'); - $('#' + table_name).DataTable().ajax.reload(); - }); - function draw_domain_admins() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#domainadminstable') ) { - $('#domainadminstable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#domainadminstable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/domain-admin/all", - dataSrc: function(data){ - return process_table_data(data, 'domainadminstable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: lang.username, - data: 'username', - defaultContent: '' - }, - { - title: lang.admin_domains, - data: 'selected_domains', - defaultContent: '', - }, - { - title: "TFA", - data: 'tfa_active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ], - initComplete: function(settings, json){ - } - }); - } - function draw_oauth2_clients() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) { - $('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#oauth2clientstable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/oauth2-client/all", - dataSrc: function(data){ - return process_table_data(data, 'oauth2clientstable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'id', - defaultContent: '' - }, - { - title: lang.oauth2_client_id, - data: 'client_id', - defaultContent: '' - }, - { - title: lang.oauth2_client_secret, - data: 'client_secret', - defaultContent: '' - }, - { - title: lang.oauth2_redirect_uri, - data: 'redirect_uri', - defaultContent: '' - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ] - }); - } - function draw_admins() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#adminstable') ) { - $('#adminstable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#adminstable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/admin/all", - dataSrc: function(data){ - return process_table_data(data, 'adminstable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: lang.username, - data: 'username', - defaultContent: '' - }, - { - title: "TFA", - data: 'tfa_active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.action, - data: 'action', - defaultContent: '', - className: 'text-md-end dt-sm-head-hidden dt-body-right' - }, - ] - }); - } - function draw_fwd_hosts() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) { - $('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#forwardinghoststable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/fwdhost/all", - dataSrc: function(data){ - return process_table_data(data, 'forwardinghoststable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: lang.host, - data: 'host', - defaultContent: '' - }, - { - title: lang.source, - data: 'source', - defaultContent: '' - }, - { - title: lang.spamfilter, - data: 'keep_spam', - defaultContent: '', - render: function(data, type){ - return 'yes'==data?'<i class="bi bi-x-lg"></i>':'no'==data&&'<i class="bi bi-check-lg"></i>'; - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ] - }); - } - function draw_relayhosts() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#relayhoststable') ) { - $('#relayhoststable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#relayhoststable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/relayhost/all", - dataSrc: function(data){ - return process_table_data(data, 'relayhoststable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'id', - defaultContent: '' - }, - { - title: lang.host, - data: 'hostname', - defaultContent: '' - }, - { - title: lang.username, - data: 'username', - defaultContent: '' - }, - { - title: lang.in_use_by, - data: 'in_use_by', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ] - }); - } - function draw_transport_maps() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#transportstable') ) { - $('#transportstable').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#transportstable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/transport/all", - dataSrc: function(data){ - return process_table_data(data, 'transportstable'); - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'id', - defaultContent: '' - }, - { - title: lang.destination, - data: 'destination', - defaultContent: '' - }, - { - title: lang.nexthop, - data: 'nexthop', - defaultContent: '' - }, - { - title: lang.username, - data: 'username', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - if(data == 1) return '<i class="bi bi-check-lg"></i>'; - else return '<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ] - }); - } - - function process_table_data(data, table) { - if (table == 'relayhoststable') { - $.each(data, function (i, item) { - item.action = '<div class="btn-group">' + - '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' + - '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; } - else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; } - else { item.in_use_by = item.used_by_mailboxes + '<hr style="margin:5px 0px 5px 0px;">' + item.used_by_domains; } - item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />'; - }); - } else if (table == 'transportstable') { - $.each(data, function (i, item) { - if (item.is_mx_based) { - item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-bs-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>'; - } - if (item.username) { - item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username; - } - item.action = '<div class="btn-group">' + - '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' + - '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />'; - }); - } else if (table == 'queuetable') { - $.each(data, function (i, item) { - item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />'; - rcpts = $.map(item.recipients, function(i) { - return escapeHtml(i); - }); - item.recipients = rcpts.join('<hr style="margin:1px!important">'); - item.action = '<div class="btn-group">' + - '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.queue_show_message + '</a>' + - '</div>'; - }); - } else if (table == 'forwardinghoststable') { - $.each(data, function (i, item) { - item.action = '<div class="btn-group">' + - '<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />'; - }); - } else if (table == 'oauth2clientstable') { - $.each(data, function (i, item) { - item.action = '<div class="btn-group">' + - '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.scope = "profile"; - item.grant_types = 'refresh_token password authorization_code'; - item.chkbox = '<input type="checkbox" data-id="oauth2_clients" name="multi_select" value="' + item.id + '" />'; - }); - } else if (table == 'domainadminstable') { - $.each(data, function (i, item) { - item.selected_domains = escapeHtml(item.selected_domains); - item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>"); - item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />'; - item.action = '<div class="btn-group">' + - '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' + - '</div>'; - }); - } else if (table == 'adminstable') { - $.each(data, function (i, item) { - if (admin_username.toLowerCase() == item.username.toLowerCase()) { - item.usr = '<i class="bi bi-person-check"></i> ' + item.username; - } else { - item.usr = item.username; - } - item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />'; - item.action = '<div class="btn-group">' + - '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - }); - } - return data - }; - - // detect element visibility changes - function onVisible(element, callback) { - $(document).ready(function() { - element_object = document.querySelector(element); - if (element_object === null) return; - - new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - if(entry.intersectionRatio > 0) { - callback(element_object); - } - }); - }).observe(element_object); - }); - } - // Draw Table if tab is active - onVisible("[id^=adminstable]", () => draw_admins()); - onVisible("[id^=domainadminstable]", () => draw_domain_admins()); - onVisible("[id^=oauth2clientstable]", () => draw_oauth2_clients()); - onVisible("[id^=forwardinghoststable]", () => draw_fwd_hosts()); - onVisible("[id^=relayhoststable]", () => draw_relayhosts()); - onVisible("[id^=transportstable]", () => draw_transport_maps()); - - - $('body').on('click', 'span.footable-toggle', function () { - event.stopPropagation(); - }) - - // API IP check toggle - $("#skip_ip_check_ro").click(function( event ) { - $("#skip_ip_check_ro").not(this).prop('checked', false); - if ($("#skip_ip_check_ro:checked").length > 0) { - $('#allow_from_ro').prop('disabled', true); - } - else { - $("#allow_from_ro").removeAttr('disabled'); - } - }); - $("#skip_ip_check_rw").click(function( event ) { - $("#skip_ip_check_rw").not(this).prop('checked', false); - if ($("#skip_ip_check_rw:checked").length > 0) { - $('#allow_from_rw').prop('disabled', true); - } - else { - $("#allow_from_rw").removeAttr('disabled'); - } - }); - // Relayhost - $('#testRelayhostModal').on('show.bs.modal', function (e) { - $('#test_relayhost_result').text("-"); - button = $(e.relatedTarget) - if (button != null) { - $('#relayhost_id').val(button.data('relayhost-id')); - } - }) - $('#test_relayhost').on('click', function (e) { - e.preventDefault(); - prev = $('#test_relayhost').text(); - $(this).prop("disabled",true); - $(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> '); - $.ajax({ - type: 'GET', - url: 'inc/ajax/relay_check.php', - dataType: 'text', - data: $('#test_relayhost_form').serialize(), - complete: function (data) { - $('#test_relayhost_result').html(data.responseText); - $('#test_relayhost').prop("disabled",false); - $('#test_relayhost').text(prev); - } - }); - }) - // Transport - $('#testTransportModal').on('show.bs.modal', function (e) { - $('#test_transport_result').text("-"); - button = $(e.relatedTarget) - if (button != null) { - $('#transport_id').val(button.data('transport-id')); - $('#transport_type').val(button.data('transport-type')); - } - }) - $('#test_transport').on('click', function (e) { - e.preventDefault(); - prev = $('#test_transport').text(); - $(this).prop("disabled",true); - $(this).html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div> '); - $.ajax({ - type: 'GET', - url: 'inc/ajax/transport_check.php', - dataType: 'text', - data: $('#test_transport_form').serialize(), - complete: function (data) { - $('#test_transport_result').html(data.responseText); - $('#test_transport').prop("disabled",false); - $('#test_transport').text(prev); - } - }); - }) - // DKIM private key modal - $('#showDKIMprivKey').on('show.bs.modal', function (e) { - $('#priv_key_pre').text("-"); - p_related = $(e.relatedTarget) - if (p_related != null) { - var decoded_key = Base64.decode((p_related.data('priv-key'))); - $('#priv_key_pre').text(decoded_key); - } - }) - // FIDO2 friendly name modal - $('#fido2ChangeFn').on('show.bs.modal', function (e) { - rename_link = $(e.relatedTarget) - if (rename_link != null) { - $('#fido2_cid').val(rename_link.data('cid')); - $('#fido2_subject_desc').text(Base64.decode(rename_link.data('subject'))); - } - }) - // App links - function add_table_row(table_id, type) { - var row = $('<tr />'); - if (type == "app_link") { - cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>'; - cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>'; - cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>'; - } else if (type == "f2b_regex") { - cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>'; - cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>'; - cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>'; - } - row.append(cols); - table_id.append(row); - } - $('#app_link_table').on('click', 'tr a', function (e) { - e.preventDefault(); - $(this).parents('tr').remove(); - }); - $('#f2b_regex_table').on('click', 'tr a', function (e) { - e.preventDefault(); - $(this).parents('tr').remove(); - }); - $('#add_app_link_row').click(function() { - add_table_row($('#app_link_table'), "app_link"); - }); - $('#add_f2b_regex_row').click(function() { - add_table_row($('#f2b_regex_table'), "f2b_regex"); - }); -}); +// Base64 functions +var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; +jQuery(function($){ + // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery + var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; + function jq(myid) {return "#" + myid.replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1" );} + function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})} + function validateRegex(e){var t=e.split("/"),n=e,r="";t.length>1&&(n=t[1],r=t[2]);try{return new RegExp(n,r),!0}catch(e){return!1}} + 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 hashCode(t){for(var n=0,r=0;r<t.length;r++)n=t.charCodeAt(r)+((n<<5)-n);return n} + function intToRGB(t){var n=(16777215&t).toString(16).toUpperCase();return"00000".substring(0,6-n.length)+n} + $("#dkim_missing_keys").on('click', function(e) { + e.preventDefault(); + var domains = []; + $('.dkim_missing').each(function() { + domains.push($(this).val()); + }); + $('#dkim_add_domains').val(domains); + }); + $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); + $("#mass_exclude").change(function(){ $("#mass_include").selectpicker('deselectAll'); }); + $("#mass_include").change(function(){ $("#mass_exclude").selectpicker('deselectAll'); }); + $("#mass_disarm").click(function() { $("#mass_send").attr("disabled", !this.checked); }); + $(".admin-ays-dialog").click(function() { return confirm(lang.ays); }); + $(".validate_rspamd_regex").click(function( event ) { + event.preventDefault(); + var regex_map_id = $(this).data('regex-map'); + var regex_data = $(jq(regex_map_id)).val().split(/\r?\n/); + var regex_valid = true; + for(var i = 0;i < regex_data.length;i++){ + if(regex_data[i].startsWith('#') || !regex_data[i]){ + continue; + } + if(!validateRegex(regex_data[i])) { + mailcow_alert_box('Cannot build regex from line ' + (i+1), 'danger'); + var regex_valid = false; + break; + } + if(!regex_data[i].startsWith('/') || !/\/[ims]?$/.test(regex_data[i])){ + mailcow_alert_box('Line ' + (i+1) + ' is invalid', 'danger'); + var regex_valid = false; + break; + } + } + if (regex_valid) { + mailcow_alert_box('Regex OK', 'success'); + $('button[data-id="' + regex_map_id + '"]').attr({"disabled": false}); + } + }); + $('.textarea-code').on('keyup', function() { + $('.submit_rspamd_regex').attr({"disabled": true}); + }); + $("#show_rspamd_global_filters").click(function() { + $.get("inc/ajax/show_rspamd_global_filters.php"); + $("#confirm_show_rspamd_global_filters").hide(); + $("#rspamd_global_filters").removeClass("d-none"); + }); + $("#super_delete").click(function() { return confirm(lang.queue_ays); }); + + $(".refresh_table").on('click', function(e) { + e.preventDefault(); + var table_name = $(this).data('table'); + $('#' + table_name).DataTable().ajax.reload(); + }); + function draw_domain_admins() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#domainadminstable') ) { + $('#domainadminstable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#domainadminstable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/domain-admin/all", + dataSrc: function(data){ + return process_table_data(data, 'domainadminstable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: lang.username, + data: 'username', + defaultContent: '' + }, + { + title: lang.admin_domains, + data: 'selected_domains', + defaultContent: '', + }, + { + title: "TFA", + data: 'tfa_active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ], + initComplete: function(settings, json){ + } + }); + } + function draw_oauth2_clients() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) { + $('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#oauth2clientstable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/oauth2-client/all", + dataSrc: function(data){ + return process_table_data(data, 'oauth2clientstable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'id', + defaultContent: '' + }, + { + title: lang.oauth2_client_id, + data: 'client_id', + defaultContent: '' + }, + { + title: lang.oauth2_client_secret, + data: 'client_secret', + defaultContent: '' + }, + { + title: lang.oauth2_redirect_uri, + data: 'redirect_uri', + defaultContent: '' + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ] + }); + } + function draw_admins() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#adminstable') ) { + $('#adminstable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#adminstable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/admin/all", + dataSrc: function(data){ + return process_table_data(data, 'adminstable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: lang.username, + data: 'username', + defaultContent: '' + }, + { + title: "TFA", + data: 'tfa_active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + defaultContent: '', + className: 'text-md-end dt-sm-head-hidden dt-body-right' + }, + ] + }); + } + function draw_fwd_hosts() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) { + $('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#forwardinghoststable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/fwdhost/all", + dataSrc: function(data){ + return process_table_data(data, 'forwardinghoststable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: lang.host, + data: 'host', + defaultContent: '' + }, + { + title: lang.source, + data: 'source', + defaultContent: '' + }, + { + title: lang.spamfilter, + data: 'keep_spam', + defaultContent: '', + render: function(data, type){ + return 'yes'==data?'<i class="bi bi-x-lg"></i>':'no'==data&&'<i class="bi bi-check-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ] + }); + } + function draw_relayhosts() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#relayhoststable') ) { + $('#relayhoststable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#relayhoststable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/relayhost/all", + dataSrc: function(data){ + return process_table_data(data, 'relayhoststable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'id', + defaultContent: '' + }, + { + title: lang.host, + data: 'hostname', + defaultContent: '' + }, + { + title: lang.username, + data: 'username', + defaultContent: '' + }, + { + title: lang.in_use_by, + data: 'in_use_by', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ] + }); + } + function draw_transport_maps() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#transportstable') ) { + $('#transportstable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#transportstable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/transport/all", + dataSrc: function(data){ + return process_table_data(data, 'transportstable'); + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'id', + defaultContent: '' + }, + { + title: lang.destination, + data: 'destination', + defaultContent: '' + }, + { + title: lang.nexthop, + data: 'nexthop', + defaultContent: '' + }, + { + title: lang.username, + data: 'username', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + if(data == 1) return '<i class="bi bi-check-lg"></i>'; + else return '<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ] + }); + } + + function process_table_data(data, table) { + if (table == 'relayhoststable') { + $.each(data, function (i, item) { + item.action = '<div class="btn-group">' + + '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' + + '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; } + else if (item.used_by_domains == '') { item.in_use_by = item.used_by_mailboxes; } + else { item.in_use_by = item.used_by_mailboxes + '<hr style="margin:5px 0px 5px 0px;">' + item.used_by_domains; } + item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />'; + }); + } else if (table == 'transportstable') { + $.each(data, function (i, item) { + if (item.is_mx_based) { + item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-bs-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>'; + } + if (item.username) { + item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username; + } + item.action = '<div class="btn-group">' + + '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' + + '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />'; + }); + } else if (table == 'queuetable') { + $.each(data, function (i, item) { + item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />'; + rcpts = $.map(item.recipients, function(i) { + return escapeHtml(i); + }); + item.recipients = rcpts.join('<hr style="margin:1px!important">'); + item.action = '<div class="btn-group">' + + '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.queue_show_message + '</a>' + + '</div>'; + }); + } else if (table == 'forwardinghoststable') { + $.each(data, function (i, item) { + item.action = '<div class="btn-group">' + + '<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />'; + }); + } else if (table == 'oauth2clientstable') { + $.each(data, function (i, item) { + item.action = '<div class="btn-group">' + + '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.scope = "profile"; + item.grant_types = 'refresh_token password authorization_code'; + item.chkbox = '<input type="checkbox" data-id="oauth2_clients" name="multi_select" value="' + item.id + '" />'; + }); + } else if (table == 'domainadminstable') { + $.each(data, function (i, item) { + item.selected_domains = escapeHtml(item.selected_domains); + item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>"); + item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />'; + item.action = '<div class="btn-group">' + + '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' + + '</div>'; + }); + } else if (table == 'adminstable') { + $.each(data, function (i, item) { + if (admin_username.toLowerCase() == item.username.toLowerCase()) { + item.usr = '<i class="bi bi-person-check"></i> ' + item.username; + } else { + item.usr = item.username; + } + item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />'; + item.action = '<div class="btn-group">' + + '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + }); + } + return data + }; + + // detect element visibility changes + function onVisible(element, callback) { + $(document).ready(function() { + element_object = document.querySelector(element); + if (element_object === null) return; + + new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if(entry.intersectionRatio > 0) { + callback(element_object); + } + }); + }).observe(element_object); + }); + } + // Draw Table if tab is active + onVisible("[id^=adminstable]", () => draw_admins()); + onVisible("[id^=domainadminstable]", () => draw_domain_admins()); + onVisible("[id^=oauth2clientstable]", () => draw_oauth2_clients()); + onVisible("[id^=forwardinghoststable]", () => draw_fwd_hosts()); + onVisible("[id^=relayhoststable]", () => draw_relayhosts()); + onVisible("[id^=transportstable]", () => draw_transport_maps()); + + + $('body').on('click', 'span.footable-toggle', function () { + event.stopPropagation(); + }) + + // API IP check toggle + $("#skip_ip_check_ro").click(function( event ) { + $("#skip_ip_check_ro").not(this).prop('checked', false); + if ($("#skip_ip_check_ro:checked").length > 0) { + $('#allow_from_ro').prop('disabled', true); + } + else { + $("#allow_from_ro").removeAttr('disabled'); + } + }); + $("#skip_ip_check_rw").click(function( event ) { + $("#skip_ip_check_rw").not(this).prop('checked', false); + if ($("#skip_ip_check_rw:checked").length > 0) { + $('#allow_from_rw').prop('disabled', true); + } + else { + $("#allow_from_rw").removeAttr('disabled'); + } + }); + // Relayhost + $('#testRelayhostModal').on('show.bs.modal', function (e) { + $('#test_relayhost_result').text("-"); + button = $(e.relatedTarget) + if (button != null) { + $('#relayhost_id').val(button.data('relayhost-id')); + } + }) + $('#test_relayhost').on('click', function (e) { + e.preventDefault(); + prev = $('#test_relayhost').text(); + $(this).prop("disabled",true); + $(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> '); + $.ajax({ + type: 'GET', + url: 'inc/ajax/relay_check.php', + dataType: 'text', + data: $('#test_relayhost_form').serialize(), + complete: function (data) { + $('#test_relayhost_result').html(data.responseText); + $('#test_relayhost').prop("disabled",false); + $('#test_relayhost').text(prev); + } + }); + }) + // Transport + $('#testTransportModal').on('show.bs.modal', function (e) { + $('#test_transport_result').text("-"); + button = $(e.relatedTarget) + if (button != null) { + $('#transport_id').val(button.data('transport-id')); + $('#transport_type').val(button.data('transport-type')); + } + }) + $('#test_transport').on('click', function (e) { + e.preventDefault(); + prev = $('#test_transport').text(); + $(this).prop("disabled",true); + $(this).html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div> '); + $.ajax({ + type: 'GET', + url: 'inc/ajax/transport_check.php', + dataType: 'text', + data: $('#test_transport_form').serialize(), + complete: function (data) { + $('#test_transport_result').html(data.responseText); + $('#test_transport').prop("disabled",false); + $('#test_transport').text(prev); + } + }); + }) + // DKIM private key modal + $('#showDKIMprivKey').on('show.bs.modal', function (e) { + $('#priv_key_pre').text("-"); + p_related = $(e.relatedTarget) + if (p_related != null) { + var decoded_key = Base64.decode((p_related.data('priv-key'))); + $('#priv_key_pre').text(decoded_key); + } + }) + // FIDO2 friendly name modal + $('#fido2ChangeFn').on('show.bs.modal', function (e) { + rename_link = $(e.relatedTarget) + if (rename_link != null) { + $('#fido2_cid').val(rename_link.data('cid')); + $('#fido2_subject_desc').text(Base64.decode(rename_link.data('subject'))); + } + }) + // App links + function add_table_row(table_id, type) { + var row = $('<tr />'); + if (type == "app_link") { + cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>'; + cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>'; + cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>'; + } else if (type == "f2b_regex") { + cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>'; + cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>'; + cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>'; + } + row.append(cols); + table_id.append(row); + } + $('#app_link_table').on('click', 'tr a', function (e) { + e.preventDefault(); + $(this).parents('tr').remove(); + }); + $('#f2b_regex_table').on('click', 'tr a', function (e) { + e.preventDefault(); + $(this).parents('tr').remove(); + }); + $('#add_app_link_row').click(function() { + add_table_row($('#app_link_table'), "app_link"); + }); + $('#add_f2b_regex_row').click(function() { + add_table_row($('#f2b_regex_table'), "f2b_regex"); + }); +}); diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index a7b06e5a..e0b9a5ab 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -34,7 +34,7 @@ $(document).ready(function() { }); // set update loop container list - containersToUpdate = {} + containersToUpdate = {}; // set default ChartJs Font Color Chart.defaults.color = '#999'; // create host cpu and mem charts @@ -44,14 +44,13 @@ $(document).ready(function() { check_update(mailcow_info.version_tag, mailcow_info.project_url); } $("#maiclow_version").click(function(){ - if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || - mailcow_info.branch !== "master") + if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" || mailcow_info.branch !== "master") return; showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag); }) // get public ips - $("#host_show_ip").click(function(){ + $("#host_show_ip").click(function(){ $("#host_show_ip").find(".text").addClass("d-none"); $("#host_show_ip").find(".spinner-border").removeClass("d-none"); @@ -76,7 +75,7 @@ $(document).ready(function() { $("#host_ipv6").addClass("d-block"); }).catch(function(error){ console.log(error); - + $("#host_ipv6").removeClass("d-none"); $("#host_ipv6").addClass("d-block"); $("#host_ipv6").addClass("text-danger"); @@ -119,10 +118,11 @@ jQuery(function($){ } var table = $('#autodiscover_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -188,10 +188,11 @@ jQuery(function($){ } var table = $('#postfix_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -242,10 +243,11 @@ jQuery(function($){ } var table = $('#watchdog_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -300,10 +302,11 @@ jQuery(function($){ } var table = $('#api_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -352,7 +355,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-api-logs', '#api_log'); }); @@ -365,10 +368,11 @@ jQuery(function($){ } var table = $('#rl_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -455,7 +459,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-rl-logs', '#rl_log'); }); @@ -468,10 +472,11 @@ jQuery(function($){ } var table = $('#ui_logs').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -538,7 +543,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-ui-logs', '#ui_log'); }); @@ -551,10 +556,11 @@ jQuery(function($){ } var table = $('#sasl_logs').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -598,7 +604,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-sasl-logs', '#sasl_logs'); }); @@ -611,10 +617,11 @@ jQuery(function($){ } var table = $('#acme_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -647,7 +654,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-acme-logs', '#acme_log'); }); @@ -660,10 +667,11 @@ jQuery(function($){ } var table = $('#netfilter_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -701,7 +709,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-netfilter-logs', '#netfilter_log'); }); @@ -714,10 +722,11 @@ jQuery(function($){ } var table = $('#sogo_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -755,7 +764,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-sogo-logs', '#sogo_log'); }); @@ -768,10 +777,11 @@ jQuery(function($){ } var table = $('#dovecot_log').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -883,10 +893,11 @@ jQuery(function($){ } var table = $('#rspamd_history').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: log_pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -983,7 +994,7 @@ jQuery(function($){ } ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-rspamd-history', '#rspamd_history'); }); @@ -998,31 +1009,31 @@ jQuery(function($){ item.rcpt = escapeHtml(item.rcpt_smtp.join(", ")); } item.symbols = Object.keys(item.symbols).sort(function (a, b) { - if (item.symbols[a].score === 0) return 1 - if (item.symbols[b].score === 0) return -1 + if (item.symbols[a].score === 0) return 1; + if (item.symbols[b].score === 0) return -1; if (item.symbols[b].score < 0 && item.symbols[a].score < 0) { - return item.symbols[a].score - item.symbols[b].score + return item.symbols[a].score - item.symbols[b].score; } if (item.symbols[b].score > 0 && item.symbols[a].score > 0) { - return item.symbols[b].score - item.symbols[a].score + return item.symbols[b].score - item.symbols[a].score; } - return item.symbols[b].score - item.symbols[a].score + return item.symbols[b].score - item.symbols[a].score; }).map(function(key) { var sym = item.symbols[key]; if (sym.score < 0) { - sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)' + sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'; } else if (sym.score === 0) { - sym.score_formatted = '(<span><b>' + sym.score + '</b></span>)' + sym.score_formatted = '(<span><b>' + sym.score + '</b></span>)'; } else { - sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)' + sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'; } var str = '<strong>' + key + '</strong> ' + sym.score_formatted; if (sym.options) { str += ' [' + escapeHtml(sym.options.join(", ")) + "]"; } - return str + return str; }).join('<br>\n'); item.subject = escapeHtml(item.subject); var scan_time = item.time_real.toFixed(3); @@ -1155,14 +1166,14 @@ jQuery(function($){ } }); } - return data + return data; }; $('.add_log_lines').on('click', function (e) { e.preventDefault(); - var log_table= $(this).data("table") - var new_nrows = $(this).data("nrows") - var post_process = $(this).data("post-process") - var log_url = $(this).data("log-url") + var log_table= $(this).data("table"); + var new_nrows = $(this).data("nrows"); + var post_process = $(this).data("post-process"); + var log_url = $(this).data("log-url"); if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) { console.log("no data-table or data-nrows or log_url or data-post-process attr found"); return; @@ -1184,9 +1195,9 @@ jQuery(function($){ }) function hideTableExpandCollapseBtn(tab, table){ if ($(table).hasClass('collapsed')) - $(tab).find(".table_collapse_option").show(); + $(tab).find(".table_collapse_option").show(); else - $(tab).find(".table_collapse_option").hide(); + $(tab).find(".table_collapse_option").hide(); } // detect element visibility changes @@ -1220,7 +1231,6 @@ jQuery(function($){ onVisible("[id^=rspamd_donut]", () => rspamd_pie_graph()); - // start polling host stats if tab is active onVisible("[id^=tab-containers]", () => update_stats()); // start polling container stats if collapse is active @@ -1303,9 +1313,9 @@ function update_stats(timeout=5){ if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift(); cpu_chart.data.datasets[0].data.push(data.cpu.usage); - if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift(); + if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift(); mem_chart.data.datasets[0].data.push(data.memory.usage); - if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift(); + if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift(); cpu_chart.update(); mem_chart.update(); @@ -1464,23 +1474,23 @@ function createReadWriteChart(chart_id, read_lable, write_lable){ }; var optionsNet = { interaction: { - mode: 'index' + mode: 'index' }, scales: { yAxis: { min: 0, grid: { - display: false + display: false }, ticks: { callback: function(i, index, ticks) { - return formatBytes(i); + return formatBytes(i); } } }, xAxis: { grid: { - display: false + display: false } } } @@ -1528,13 +1538,13 @@ function createHostCpuAndMemChart(){ }; var optionsCpu = { interaction: { - mode: 'index' + mode: 'index' }, scales: { yAxis: { min: 0, grid: { - display: false + display: false }, ticks: { callback: function(i, index, ticks) { @@ -1544,7 +1554,7 @@ function createHostCpuAndMemChart(){ }, xAxis: { grid: { - display: false + display: false } } } @@ -1566,13 +1576,13 @@ function createHostCpuAndMemChart(){ }; var optionsMem = { interaction: { - mode: 'index' + mode: 'index' }, scales: { yAxis: { min: 0, grid: { - display: false + display: false }, ticks: { callback: function(i, index, ticks) { @@ -1582,7 +1592,7 @@ function createHostCpuAndMemChart(){ }, xAxis: { grid: { - display: false + display: false } } } @@ -1678,22 +1688,22 @@ function parseGithubMarkdownLinks(inputText) { 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]; + 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; - } + // 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 '<a href="' + matched + '" target="_blank">' + last_uri_path + '</a><br>'; - }; + return '<a href="' + matched + '" target="_blank">' + last_uri_path + '</a><br>'; + }; - // if it's not a github link, return complete link - return '<a href="' + matched + '" target="_blank">' + matched + '</a>'; + // if it's not a github link, return complete link + return '<a href="' + matched + '" target="_blank">' + matched + '</a>'; }); return replacedText; diff --git a/data/web/js/site/edit.js b/data/web/js/site/edit.js index 4c57b35e..4680bdfa 100644 --- a/data/web/js/site/edit.js +++ b/data/web/js/site/edit.js @@ -1,220 +1,222 @@ -$(document).ready(function() { - $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); - $("#pushover_delete").click(function() { return confirm(lang.delete_ays); }); - $(".goto_checkbox").click(function( event ) { - $("form[data-id='editalias'] .goto_checkbox").not(this).prop('checked', false); - if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { - $('#textarea_alias_goto').prop('disabled', true); - } - else { - $("#textarea_alias_goto").removeAttr('disabled'); - } - }); - $("#disable_sender_check").click(function( event ) { - if ($("form[data-id='editmailbox'] #disable_sender_check:checked").length > 0) { - $('#editSelectSenderACL').prop('disabled', true); - $('#editSelectSenderACL').selectpicker('refresh'); - } - else { - $('#editSelectSenderACL').prop('disabled', false); - $('#editSelectSenderACL').selectpicker('refresh'); - } - }); - if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { - $('#textarea_alias_goto').prop('disabled', true); - } - - $("#mailbox-password-warning-close").click(function( event ) { - $('#mailbox-passwd-hidden-info').addClass('hidden'); - $('#mailbox-passwd-form-groups').removeClass('hidden'); - }); - // Sender ACL - if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ - $("#sender_acl_disabled").show(); - } - $('#editSelectSenderACL').change(function() { - if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ - $("#sender_acl_disabled").show(); - } - else { - $("#sender_acl_disabled").hide(); - } - }); - // Resources - if ($("#editSelectMultipleBookings").val() == "custom") { - $("#multiple_bookings_custom_div").show(); - $('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); - } - $("#editSelectMultipleBookings").change(function() { - $('input[name=multiple_bookings]').val($("#editSelectMultipleBookings").val()); - if ($('input[name=multiple_bookings]').val() == "custom") { - $("#multiple_bookings_custom_div").show(); - } - else { - $("#multiple_bookings_custom_div").hide(); - } - }); - $("#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($){ - // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript - function validateEmail(email) { - var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(email); - } - function draw_wl_policy_domain_table() { - $('#wl_policy_domain_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/policy_wl_domain/' + table_for_domain, - dataSrc: function(data){ - $.each(data, function (i, item) { - if (!validateEmail(item.object)) { - item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />'; - } - else { - item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'prefid', - defaultContent: '' - }, - { - title: lang_user.spamfilter_table_rule, - data: 'value', - defaultContent: '' - }, - { - title: 'Scope', - data: 'object', - defaultContent: '' - } - ] - }); - } - function draw_bl_policy_domain_table() { - $('#bl_policy_domain_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/policy_bl_domain/' + table_for_domain, - dataSrc: function(data){ - $.each(data, function (i, item) { - if (!validateEmail(item.object)) { - item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />'; - } - else { - item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'prefid', - defaultContent: '' - }, - { - title: lang_user.spamfilter_table_rule, - data: 'value', - defaultContent: '' - }, - { - title: 'Scope', - data: 'object', - defaultContent: '' - } - ] - }); - } - - - // detect element visibility changes - function onVisible(element, callback) { - $(document).ready(function() { - element_object = document.querySelector(element); - if (element_object === null) return; - - new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - if(entry.intersectionRatio > 0) { - callback(element_object); - observer.disconnect(); - } - }); - }).observe(element_object); - }); - } - // Draw Table if tab is active - onVisible("[id^=wl_policy_domain_table]", () => draw_wl_policy_domain_table()); - onVisible("[id^=bl_policy_domain_table]", () => draw_bl_policy_domain_table()); -}); +$(document).ready(function() { + $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); + $("#pushover_delete").click(function() { return confirm(lang.delete_ays); }); + $(".goto_checkbox").click(function( event ) { + $("form[data-id='editalias'] .goto_checkbox").not(this).prop('checked', false); + if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { + $('#textarea_alias_goto').prop('disabled', true); + } + else { + $("#textarea_alias_goto").removeAttr('disabled'); + } + }); + $("#disable_sender_check").click(function( event ) { + if ($("form[data-id='editmailbox'] #disable_sender_check:checked").length > 0) { + $('#editSelectSenderACL').prop('disabled', true); + $('#editSelectSenderACL').selectpicker('refresh'); + } + else { + $('#editSelectSenderACL').prop('disabled', false); + $('#editSelectSenderACL').selectpicker('refresh'); + } + }); + if ($("form[data-id='editalias'] .goto_checkbox:checked").length > 0) { + $('#textarea_alias_goto').prop('disabled', true); + } + + $("#mailbox-password-warning-close").click(function( event ) { + $('#mailbox-passwd-hidden-info').addClass('hidden'); + $('#mailbox-passwd-form-groups').removeClass('hidden'); + }); + // Sender ACL + if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ + $("#sender_acl_disabled").show(); + } + $('#editSelectSenderACL').change(function() { + if ($("#editSelectSenderACL option[value='\*']:selected").length > 0){ + $("#sender_acl_disabled").show(); + } + else { + $("#sender_acl_disabled").hide(); + } + }); + // Resources + if ($("#editSelectMultipleBookings").val() == "custom") { + $("#multiple_bookings_custom_div").show(); + $('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val()); + } + $("#editSelectMultipleBookings").change(function() { + $('input[name=multiple_bookings]').val($("#editSelectMultipleBookings").val()); + if ($('input[name=multiple_bookings]').val() == "custom") { + $("#multiple_bookings_custom_div").show(); + } + else { + $("#multiple_bookings_custom_div").hide(); + } + }); + $("#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($){ + // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript + function validateEmail(email) { + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(email); + } + function draw_wl_policy_domain_table() { + $('#wl_policy_domain_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/policy_wl_domain/' + table_for_domain, + dataSrc: function(data){ + $.each(data, function (i, item) { + if (!validateEmail(item.object)) { + item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />'; + } + else { + item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'prefid', + defaultContent: '' + }, + { + title: lang_user.spamfilter_table_rule, + data: 'value', + defaultContent: '' + }, + { + title: 'Scope', + data: 'object', + defaultContent: '' + } + ] + }); + } + function draw_bl_policy_domain_table() { + $('#bl_policy_domain_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/policy_bl_domain/' + table_for_domain, + dataSrc: function(data){ + $.each(data, function (i, item) { + if (!validateEmail(item.object)) { + item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />'; + } + else { + item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'prefid', + defaultContent: '' + }, + { + title: lang_user.spamfilter_table_rule, + data: 'value', + defaultContent: '' + }, + { + title: 'Scope', + data: 'object', + defaultContent: '' + } + ] + }); + } + + + // detect element visibility changes + function onVisible(element, callback) { + $(document).ready(function() { + element_object = document.querySelector(element); + if (element_object === null) return; + + new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if(entry.intersectionRatio > 0) { + callback(element_object); + observer.disconnect(); + } + }); + }).observe(element_object); + }); + } + // Draw Table if tab is active + onVisible("[id^=wl_policy_domain_table]", () => draw_wl_policy_domain_table()); + onVisible("[id^=bl_policy_domain_table]", () => draw_bl_policy_domain_table()); +}); diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index b93b1819..49cce1b2 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -77,7 +77,7 @@ $(document).ready(function() { $('.dns-modal-body').html(xhr.responseText); } }); - }); + }); // @Open Domain add modal $('#addDomainModal').on('show.bs.modal', function(e) { $.ajax({ @@ -85,24 +85,24 @@ $(document).ready(function() { data: {}, dataType: 'json', success: async function(data){ - $('#domain_templates').find('option').remove(); + $('#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($('<option>', { - 'value': data[i].id, - 'text': data[i].template, - 'data-attributes': JSON.stringify(data[i].attributes), - 'selected': true + $('#domain_templates').prepend($('<option>', { + 'value': data[i].id, + 'text': data[i].template, + 'data-attributes': JSON.stringify(data[i].attributes), + 'selected': true })); setDomainTemplateData(data[i].attributes); } else { - $('#domain_templates').append($('<option>', { - 'value': data[i].id, - 'text': data[i].template, - 'data-attributes': JSON.stringify(data[i].attributes), - 'selected': false + $('#domain_templates').append($('<option>', { + 'value': data[i].id, + 'text': data[i].template, + 'data-attributes': JSON.stringify(data[i].attributes), + 'selected': false })); } }; @@ -127,24 +127,24 @@ $(document).ready(function() { data: {}, dataType: 'json', success: async function(data){ - $('#mailbox_templates').find('option').remove(); + $('#mailbox_templates').find('option').remove(); $('#mailbox_templates').selectpicker('destroy'); $('#mailbox_templates').selectpicker(); for (var i = 0; i < data.length; i++){ if (data[i].template === "Default"){ - $('#mailbox_templates').prepend($('<option>', { - 'value': data[i].id, - 'text': data[i].template, - 'data-attributes': JSON.stringify(data[i].attributes), - 'selected': true + $('#mailbox_templates').prepend($('<option>', { + 'value': data[i].id, + 'text': data[i].template, + 'data-attributes': JSON.stringify(data[i].attributes), + 'selected': true })); setMailboxTemplateData(data[i].attributes); } else { - $('#mailbox_templates').append($('<option>', { - value: data[i].id, - text : data[i].template, - 'data-attributes': JSON.stringify(data[i].attributes), - 'selected': false + $('#mailbox_templates').append($('<option>', { + value: data[i].id, + text : data[i].template, + 'data-attributes': JSON.stringify(data[i].attributes), + 'selected': false })); } }; @@ -229,20 +229,20 @@ $(document).ready(function() { } else { $('#addDomain_gal').prop('checked', false); } - + if (template.active == 1){ $('#addDomain_active').prop('checked', true); } else { $('#addDomain_active').prop('checked', false); } - + $("#addDomain_rl_value").val(template.rl_value); $('#addDomain_rl_frame').selectpicker('val', template.rl_frame); $("#dkim_selector").val(template.dkim_selector); if (!template.key_size) template.key_size = 2048; $('#key_size').selectpicker('val', template.key_size.toString()); - + if (template.backupmx == 1){ $('#addDomain_relay_domain').prop('checked', true); } else { @@ -259,7 +259,7 @@ $(document).ready(function() { $('#addDomain_relay_unknown_only').prop('checked', false); } - + // load tags $('#addDomain_tags').val(""); $($('#addDomain_tags').parent().find(".tag-values")[0]).val(""); @@ -404,7 +404,7 @@ $(document).ready(function() { } else { $('#sogo_access').prop('checked', false); } - + // load tags $('#addMailbox_tags').val(""); $($('#addMailbox_tags').parent().find(".tag-values")[0]).val(""); @@ -417,11 +417,11 @@ jQuery(function($){ // 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 unix_time_format(i){return""==i?'<i class="bi bi-x"></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"})} - + $(".refresh_table").on('click', function(e) { e.preventDefault(); var table_name = $(this).data('table'); - + if ($.fn.DataTable.isDataTable('#' + table_name)) $('#' + table_name).DataTable().ajax.reload(); }); @@ -433,10 +433,11 @@ jQuery(function($){ } var table = $('#domain_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -617,8 +618,8 @@ jQuery(function($){ defaultContent: '' }, ] - }); - + }); + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-domains', '#domain_table'); }); @@ -631,15 +632,16 @@ jQuery(function($){ } var table = $('#templates_domain_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-templates-domains', '#templates_domain_table'); }, @@ -666,13 +668,13 @@ jQuery(function($){ } item.attributes.rl_value = escapeHtml(item.attributes.rl_value); - + if (item.template.toLowerCase() == "default"){ item.action = '<div class="btn-group">' + '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '</div>'; } - else{ + else { item.action = '<div class="btn-group">' + '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + '<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/domain/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + @@ -693,138 +695,138 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: "ID", - data: 'id', - responsivePriority: 2, - defaultContent: '' - }, - { - title: lang.template, - data: 'template', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.max_aliases, - data: 'attributes.max_num_aliases_for_domain', - defaultContent: '', - }, - { - title: lang.max_mailboxes, - data: 'attributes.max_num_mboxes_for_domain', - defaultContent: '', - }, - { - title: lang.mailbox_defquota, - data: 'attributes.def_quota_for_mbox', - defaultContent: '', - }, - { - title: lang.max_quota, - data: 'attributes.max_quota_for_mbox', - defaultContent: '', - }, - { - title: lang.domain_quota_total, - data: 'attributes.max_quota_for_domain', - defaultContent: '', - }, - { - title: lang.gal, - data: 'attributes.gal', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.backup_mx, - data: 'attributes.backupmx', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.relay_all, - data: 'attributes.relay_all_recipients', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.relay_unknown, - data: 'attributes.relay_unknown_only', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.active, - data: 'attributes.active', - defaultContent: '', - responsivePriority: 4, - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: 'rl_frame', - data: 'attributes.rl_frame', - defaultContent: '', - class: 'none', - }, - { - title: 'rl_value', - data: 'attributes.rl_value', - defaultContent: '', - class: 'none', - }, - { - title: lang.dkim_domains_selector, - data: 'attributes.dkim_selector', - defaultContent: '', - class: 'none', - }, - { - title: lang.dkim_key_length, - data: 'attributes.key_size', - defaultContent: '', - class: 'none', - }, - { - title: 'Tags', - data: 'attributes.tags', - defaultContent: '', - className: 'none' - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md', - responsivePriority: 6, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: "ID", + data: 'id', + responsivePriority: 2, + defaultContent: '' + }, + { + title: lang.template, + data: 'template', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.max_aliases, + data: 'attributes.max_num_aliases_for_domain', + defaultContent: '', + }, + { + title: lang.max_mailboxes, + data: 'attributes.max_num_mboxes_for_domain', + defaultContent: '', + }, + { + title: lang.mailbox_defquota, + data: 'attributes.def_quota_for_mbox', + defaultContent: '', + }, + { + title: lang.max_quota, + data: 'attributes.max_quota_for_mbox', + defaultContent: '', + }, + { + title: lang.domain_quota_total, + data: 'attributes.max_quota_for_domain', + defaultContent: '', + }, + { + title: lang.gal, + data: 'attributes.gal', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.backup_mx, + data: 'attributes.backupmx', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.relay_all, + data: 'attributes.relay_all_recipients', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.relay_unknown, + data: 'attributes.relay_unknown_only', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.active, + data: 'attributes.active', + defaultContent: '', + responsivePriority: 4, + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: 'rl_frame', + data: 'attributes.rl_frame', + defaultContent: '', + class: 'none', + }, + { + title: 'rl_value', + data: 'attributes.rl_value', + defaultContent: '', + class: 'none', + }, + { + title: lang.dkim_domains_selector, + data: 'attributes.dkim_selector', + defaultContent: '', + class: 'none', + }, + { + title: lang.dkim_key_length, + data: 'attributes.key_size', + defaultContent: '', + class: 'none', + }, + { + title: 'Tags', + data: 'attributes.tags', + defaultContent: '', + className: 'none' + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md', + responsivePriority: 6, + defaultContent: '' + }, ] }); @@ -840,10 +842,11 @@ jQuery(function($){ } var table = $('#mailbox_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -927,7 +930,7 @@ 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" ' + 'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>'; item.username = escapeHtml(item.username); - + if (Array.isArray(item.tags)){ var tags = ''; for (var i = 0; i < item.tags.length; i++) @@ -942,167 +945,167 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: lang.username, - data: 'username', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.domain_quota, - data: 'quota.value', - responsivePriority: 8, - defaultContent: '', - orderData: 23 - }, - { - title: lang.last_mail_login, - data: 'last_mail_login', - defaultContent: '', - responsivePriority: 7, - render: function (data, type) { - res = data.split("/"); - return '<div class="badge bg-info mb-2">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' + - '<div class="badge bg-info mb-2">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' + - '<div class="badge bg-info">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>'; - } - }, - { - title: lang.last_pw_change, - data: 'last_pw_change', - defaultContent: '' - }, - { - title: lang.in_use, - data: 'in_use', - defaultContent: '', - responsivePriority: 9, - className: 'dt-data-w100' - }, - { - title: lang.fname, - data: 'name', - defaultContent: '', - className: 'none' - }, - { - title: lang.domain, - data: 'domain', - defaultContent: '', - className: 'none' - }, - { - title: lang.tls_enforce_in, - data: 'tls_enforce_in', - defaultContent: '', - className: 'none' - }, - { - title: lang.tls_enforce_out, - data: 'tls_enforce_out', - defaultContent: '', - className: 'none' - }, - { - title: 'SMTP', - data: 'smtp_access', - defaultContent: '', - className: 'none' - }, - { - title: 'IMAP', - data: 'imap_access', - defaultContent: '', - className: 'none' - }, - { - title: 'POP3', - data: 'pop3_access', - defaultContent: '', - className: 'none' - }, - { - title: 'SIEVE', - data: 'sieve_access', - defaultContent: '', - className: 'none' - }, - { - title: lang.quarantine_notification, - data: 'quarantine_notification', - defaultContent: '', - className: 'none' - }, - { - title: lang.quarantine_category, - data: 'quarantine_category', - defaultContent: '', - className: 'none' - }, - { - title: lang.msg_num, - data: 'messages', - defaultContent: '', - responsivePriority: 5 - }, - { - title: lang.created_on, - data: 'created', - defaultContent: '', - className: 'none' - }, - { - title: lang.last_modified, - data: 'modified', - defaultContent: '', - className: 'none' - }, - { - title: 'Tags', - data: 'tags', - defaultContent: '', - className: 'none' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - responsivePriority: 4, - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md', - responsivePriority: 6, - defaultContent: '' - }, - { - title: "", - data: 'quota.sortBy', - responsivePriority: 8, - defaultContent: '', - className: "d-none" - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: lang.username, + data: 'username', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.domain_quota, + data: 'quota.value', + responsivePriority: 8, + defaultContent: '', + orderData: 23 + }, + { + title: lang.last_mail_login, + data: 'last_mail_login', + defaultContent: '', + responsivePriority: 7, + render: function (data, type) { + res = data.split("/"); + return '<div class="badge bg-info mb-2">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' + + '<div class="badge bg-info mb-2">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' + + '<div class="badge bg-info">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>'; + } + }, + { + title: lang.last_pw_change, + data: 'last_pw_change', + defaultContent: '' + }, + { + title: lang.in_use, + data: 'in_use', + defaultContent: '', + responsivePriority: 9, + className: 'dt-data-w100' + }, + { + title: lang.fname, + data: 'name', + defaultContent: '', + className: 'none' + }, + { + title: lang.domain, + data: 'domain', + defaultContent: '', + className: 'none' + }, + { + title: lang.tls_enforce_in, + data: 'tls_enforce_in', + defaultContent: '', + className: 'none' + }, + { + title: lang.tls_enforce_out, + data: 'tls_enforce_out', + defaultContent: '', + className: 'none' + }, + { + title: 'SMTP', + data: 'smtp_access', + defaultContent: '', + className: 'none' + }, + { + title: 'IMAP', + data: 'imap_access', + defaultContent: '', + className: 'none' + }, + { + title: 'POP3', + data: 'pop3_access', + defaultContent: '', + className: 'none' + }, + { + title: 'SIEVE', + data: 'sieve_access', + defaultContent: '', + className: 'none' + }, + { + title: lang.quarantine_notification, + data: 'quarantine_notification', + defaultContent: '', + className: 'none' + }, + { + title: lang.quarantine_category, + data: 'quarantine_category', + defaultContent: '', + className: 'none' + }, + { + title: lang.msg_num, + data: 'messages', + defaultContent: '', + responsivePriority: 5 + }, + { + title: lang.created_on, + data: 'created', + defaultContent: '', + className: 'none' + }, + { + title: lang.last_modified, + data: 'modified', + defaultContent: '', + className: 'none' + }, + { + title: 'Tags', + data: 'tags', + defaultContent: '', + className: 'none' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + responsivePriority: 4, + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md', + responsivePriority: 6, + defaultContent: '' + }, + { + title: "", + data: 'quota.sortBy', + responsivePriority: 8, + defaultContent: '', + className: "d-none" + }, ] }); @@ -1118,15 +1121,16 @@ jQuery(function($){ } var table = $('#templates_mbox_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-templates-mbox', '#templates_mbox_table'); }, @@ -1175,17 +1179,17 @@ jQuery(function($){ item.attributes.quarantine_category = lang.q_all; } - + if (item.template.toLowerCase() == "default"){ - item.action = '<div class="btn-group">' + - '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '</div>'; + item.action = '<div class="btn-group">' + + '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '</div>'; } else { - item.action = '<div class="btn-group">' + - '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/mailbox/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; + item.action = '<div class="btn-group">' + + '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/mailbox/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; } if (Array.isArray(item.attributes.tags)){ @@ -1230,12 +1234,12 @@ jQuery(function($){ data: 'template', responsivePriority: 3, defaultContent: '' - }, + }, { title: lang.domain_quota, data: 'attributes.quota', defaultContent: '', - }, + }, { title: lang.tls_enforce_in, data: 'attributes.tls_enforce_in', @@ -1282,7 +1286,7 @@ jQuery(function($){ data: 'attributes.quarantine_category', defaultContent: '', className: 'none' - }, + }, { title: lang.force_pw_update, data: 'attributes.force_pw_update', @@ -1291,25 +1295,25 @@ jQuery(function($){ render: function (data, type) { return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; } - }, + }, { title: "rl_frame", data: 'attributes.rl_frame', defaultContent: '', class: 'none', - }, + }, { title: 'rl_value', data: 'attributes.rl_value', defaultContent: '', class: 'none', - }, + }, { title: 'Tags', data: 'attributes.tags', defaultContent: '', className: 'none' - }, + }, { title: lang.active, data: 'attributes.active', @@ -1318,7 +1322,7 @@ jQuery(function($){ render: function (data, type) { return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); } - }, + }, { title: lang.action, data: 'action', @@ -1328,7 +1332,7 @@ jQuery(function($){ }, ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-templates-mbox', '#templates_mbox_table'); }); @@ -1341,10 +1345,11 @@ jQuery(function($){ } var table = $('#resource_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -1377,65 +1382,65 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: lang.description, - data: 'description', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.alias, - data: 'name', - defaultContent: '' - }, - { - title: lang.kind, - data: 'kind', - defaultContent: '' - }, - { - title: lang.domain, - data: 'domain', - responsivePriority: 4, - defaultContent: '' - }, - { - title: lang.multiple_bookings, - data: 'multiple_bookings', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); - } - }, - { - title: lang.action, - data: 'action', - responsivePriority: 5, - defaultContent: '', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: lang.description, + data: 'description', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.alias, + data: 'name', + defaultContent: '' + }, + { + title: lang.kind, + data: 'kind', + defaultContent: '' + }, + { + title: lang.domain, + data: 'domain', + responsivePriority: 4, + defaultContent: '' + }, + { + title: lang.multiple_bookings, + data: 'multiple_bookings', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); + } + }, + { + title: lang.action, + data: 'action', + responsivePriority: 5, + defaultContent: '', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right' + }, ] }); @@ -1448,14 +1453,14 @@ jQuery(function($){ // Domains var optgroup = "<optgroup label='" + lang.domains + "'>"; $.each(data.domains, function(index, domain){ - optgroup += "<option value='" + domain + "'>" + domain + "</option>" + optgroup += "<option value='" + domain + "'>" + domain + "</option>"; }); - optgroup += "</optgroup>" + optgroup += "</optgroup>"; $('#bcc-local-dest').append(optgroup); // Alias domains var optgroup = "<optgroup label='" + lang.domain_aliases + "'>"; $.each(data.alias_domains, function(index, alias_domain){ - optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>" + optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"; }); optgroup += "</optgroup>" $('#bcc-local-dest').append(optgroup); @@ -1463,9 +1468,9 @@ jQuery(function($){ $.each(data.mailboxes, function(mailbox, aliases){ var optgroup = "<optgroup label='" + mailbox + "'>"; $.each(aliases, function(index, alias){ - optgroup += "<option value='" + alias + "'>" + alias + "</option>" + optgroup += "<option value='" + alias + "'>" + alias + "</option>"; }); - optgroup += "</optgroup>" + optgroup += "</optgroup>"; $('#bcc-local-dest').append(optgroup); }); // Finish @@ -1477,17 +1482,18 @@ jQuery(function($){ $('#bcc_table').DataTable().columns.adjust().responsive.recalc(); return; } - + var table = $('#bcc_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#collapse-tab-bcc', '#bcc_table'); }, @@ -1514,65 +1520,65 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.bcc_type, - data: 'type', - defaultContent: '' - }, - { - title: lang.bcc_local_dest, - data: 'local_dest', - defaultContent: '' - }, - { - title: lang.bcc_destinations, - data: 'bcc_dest', - defaultContent: '' - }, - { - title: lang.domain, - data: 'domain', - responsivePriority: 4, - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.bcc_type, + data: 'type', + defaultContent: '' + }, + { + title: lang.bcc_local_dest, + data: 'local_dest', + defaultContent: '' + }, + { + title: lang.bcc_destinations, + data: 'bcc_dest', + defaultContent: '' + }, + { + title: lang.domain, + data: 'domain', + responsivePriority: 4, + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—'); + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); @@ -1588,15 +1594,16 @@ jQuery(function($){ } var table = $('#recipient_map_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#collapse-tab-bcc-filters', '#recipient_map_table'); }, @@ -1605,7 +1612,7 @@ jQuery(function($){ url: "/api/v1/get/recipient_map/all", dataSrc: function(json){ if (role !== "admin") return null; - + $.each(json, function (i, item) { item.recipient_map_old = escapeHtml(item.recipient_map_old); item.recipient_map_new = escapeHtml(item.recipient_map_new); @@ -1620,58 +1627,58 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.recipient_map_old, - data: 'recipient_map_old', - defaultContent: '' - }, - { - title: lang.recipient_map_new, - data: 'recipient_map_new', - defaultContent: '', - responsivePriority: 4 - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.recipient_map_old, + data: 'recipient_map_old', + defaultContent: '' + }, + { + title: lang.recipient_map_new, + data: 'recipient_map_new', + defaultContent: '', + responsivePriority: 4 + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#collapse-tab-bcc-filters', '#recipient_map_table'); }); @@ -1684,15 +1691,16 @@ jQuery(function($){ } var table = $('#tls_policy_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-tls-policy', '#tls_policy_table'); }, @@ -1701,7 +1709,7 @@ jQuery(function($){ url: "/api/v1/get/tls-policy-map/all", dataSrc: function(json){ if (role !== "admin") return null; - + $.each(json, function (i, item) { item.dest = escapeHtml(item.dest); item.policy = '<b>' + escapeHtml(item.policy) + '</b>'; @@ -1721,63 +1729,63 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.tls_map_dest, - data: 'dest', - defaultContent: '', - responsivePriority: 4 - }, - { - title: lang.tls_map_policy, - data: 'policy', - defaultContent: '' - }, - { - title: lang.tls_map_parameters, - data: 'parameters', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.tls_map_dest, + data: 'dest', + defaultContent: '', + responsivePriority: 4 + }, + { + title: lang.tls_map_policy, + data: 'policy', + defaultContent: '' + }, + { + title: lang.tls_map_parameters, + data: 'parameters', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-tls-policy', '#tls_policy_table'); }); @@ -1790,15 +1798,16 @@ jQuery(function($){ } var table = $('#alias_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table'); }, @@ -1849,88 +1858,88 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.alias, - data: 'address', - responsivePriority: 4, - defaultContent: '' - }, - { - title: lang.target_address, - data: 'goto', - defaultContent: '' - }, - { - title: lang.domain, - data: 'domain', - defaultContent: '', - responsivePriority: 5, - }, - { - title: lang.bcc_destinations, - data: 'bcc_dest', - defaultContent: '' - }, - { - title: lang.sogo_visible, - data: 'sogo_visible', - defaultContent: '', - render: function(data, type){ - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.public_comment, - data: 'public_comment', - defaultContent: '' - }, - { - title: lang.private_comment, - data: 'private_comment', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - responsivePriority: 6, - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.alias, + data: 'address', + responsivePriority: 4, + defaultContent: '' + }, + { + title: lang.target_address, + data: 'goto', + defaultContent: '' + }, + { + title: lang.domain, + data: 'domain', + defaultContent: '', + responsivePriority: 5, + }, + { + title: lang.bcc_destinations, + data: 'bcc_dest', + defaultContent: '' + }, + { + title: lang.sogo_visible, + data: 'sogo_visible', + defaultContent: '', + render: function(data, type){ + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.public_comment, + data: 'public_comment', + defaultContent: '' + }, + { + title: lang.private_comment, + data: 'private_comment', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + responsivePriority: 6, + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); - + table.on('responsive-resize', function (e, datatable, columns){ hideTableExpandCollapseBtn('#tab-mbox-aliases', '#alias_table'); }); @@ -1943,10 +1952,11 @@ jQuery(function($){ } var table = $('#aliasdomain_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", @@ -1978,50 +1988,50 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: lang.alias, - data: 'alias_domain', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.target_domain, - data: 'target_domain', - responsivePriority: 4, - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: lang.alias, + data: 'alias_domain', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.target_domain, + data: 'target_domain', + responsivePriority: 4, + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); @@ -2037,15 +2047,16 @@ jQuery(function($){ } var table = $('#sync_job_table').DataTable({ - responsive: true, + responsive: true, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-syncjobs', '#sync_job_table'); }, @@ -2082,9 +2093,9 @@ jQuery(function($){ item.success = '<i class="text-' + (item.success == 1 ? 'success' : 'danger') + ' bi bi-' + (item.success == 1 ? 'check-lg' : 'x-lg') + '"></i>'; } if (lang['syncjob_'+item.exit_status]) { - item.exit_status = lang['syncjob_'+item.exit_status]; + item.exit_status = lang['syncjob_'+item.exit_status]; } else if (item.success != '-') { - item.exit_status = lang.syncjob_check_log; + item.exit_status = lang.syncjob_check_log; } item.exit_status = item.success + ' ' + item.exit_status; }); @@ -2093,87 +2104,87 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 3, - defaultContent: '' - }, - { - title: lang.owner, - data: 'user2', - responsivePriority: 4, - defaultContent: '' - }, - { - title: 'Server', - data: 'server_w_port', - defaultContent: '' - }, - { - title: lang.last_run, - data: 'last_run', - defaultContent: '' - }, - { - title: lang.syncjob_last_run_result, - data: 'exit_status', - defaultContent: '' - }, - { - title: 'Log', - data: 'log', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; - } - }, - { - title: lang.status, - data: 'is_running', - defaultContent: '' - }, - { - title: lang.excludes, - data: 'exclude', - defaultContent: '', - className: 'none' - }, - { - title: lang.mins_interval, - data: 'mins_interval', - defaultContent: '', - className: 'none' - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 3, + defaultContent: '' + }, + { + title: lang.owner, + data: 'user2', + responsivePriority: 4, + defaultContent: '' + }, + { + title: 'Server', + data: 'server_w_port', + defaultContent: '' + }, + { + title: lang.last_run, + data: 'last_run', + defaultContent: '' + }, + { + title: lang.syncjob_last_run_result, + data: 'exit_status', + defaultContent: '' + }, + { + title: 'Log', + data: 'log', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'; + } + }, + { + title: lang.status, + data: 'is_running', + defaultContent: '' + }, + { + title: lang.excludes, + data: 'exclude', + defaultContent: '', + className: 'none' + }, + { + title: lang.mins_interval, + data: 'mins_interval', + defaultContent: '', + className: 'none' + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); @@ -2189,16 +2200,17 @@ jQuery(function($){ } var table = $('#filter_table').DataTable({ - responsive: true, + responsive: true, autoWidth: false, processing: true, serverSide: false, stateSave: true, + pageLength: pagination_size, dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + "tr" + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", language: lang_datatables, - order:[[2, 'desc']], + order: [[2, 'desc']], initComplete: function(){ hideTableExpandCollapseBtn('#tab-filters', '#filter_table'); }, @@ -2226,64 +2238,64 @@ jQuery(function($){ } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - responsivePriority: 2, - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - responsivePriority: 3, - defaultContent: '' - }, - { - title: 'Type', - data: 'filter_type', - responsivePriority: 4, - defaultContent: '' - }, - { - title: lang.owner, - data: 'username', - defaultContent: '' - }, - { - title: lang.description, - data: 'script_desc', - defaultContent: '' - }, - { - title: 'Script', - data: 'script_data', - defaultContent: '', - className: 'none' - }, - { - title: lang.action, - data: 'action', - className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', - responsivePriority: 5, - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + responsivePriority: 2, + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + responsivePriority: 3, + defaultContent: '' + }, + { + title: 'Type', + data: 'filter_type', + responsivePriority: 4, + defaultContent: '' + }, + { + title: lang.owner, + data: 'username', + defaultContent: '' + }, + { + title: lang.description, + data: 'script_desc', + defaultContent: '' + }, + { + title: 'Script', + data: 'script_data', + defaultContent: '', + className: 'none' + }, + { + title: lang.action, + data: 'action', + className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right', + responsivePriority: 5, + defaultContent: '' + }, ] }); @@ -2294,11 +2306,11 @@ jQuery(function($){ function hideTableExpandCollapseBtn(tab, table){ if ($(table).hasClass('collapsed')) - $(tab).find(".table_collapse_option").show(); + $(tab).find(".table_collapse_option").show(); else - $(tab).find(".table_collapse_option").hide(); + $(tab).find(".table_collapse_option").hide(); } - + // detect element visibility changes function onVisible(element, callback) { $(document).ready(function() { diff --git a/data/web/js/site/qhandler.js b/data/web/js/site/qhandler.js index 4fcc9634..8a8471f2 100644 --- a/data/web/js/site/qhandler.js +++ b/data/web/js/site/qhandler.js @@ -1,71 +1,71 @@ -jQuery(function($){ - var qitem = $('legend').data('hash'); - var qError = $("#qid_error"); - $.ajax({ - url: '/inc/ajax/qitem_details.php', - data: { hash: qitem }, - dataType: 'json', - success: function(data){ - $('[data-id="qitems_single"]').each(function(index) { - $(this).attr("data-item", qitem); - }); - $('#qid_detail_subj').text(data.subject); - $('#qid_detail_hfrom').text(data.header_from); - $('#qid_detail_efrom').text(data.env_from); - $('#qid_detail_score').html(''); - $('#qid_detail_symbols').html(''); - $('#qid_detail_recipients').html(''); - $('#qid_detail_fuzzy').html(''); - if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) { - $.each(data.fuzzy_hashes, function (index, value) { - $('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + value + '</p>'); - }); - } else { - $('#qid_detail_fuzzy').append('-'); - } - if (typeof data.symbols !== 'undefined') { - data.symbols.sort(function (a, b) { - if (a.score === 0) return 1 - if (b.score === 0) return -1 - if (b.score < 0 && a.score < 0) { - return a.score - b.score - } - if (b.score > 0 && a.score > 0) { - return b.score - a.score - } - return b.score - a.score - }) - $.each(data.symbols, function (index, value) { - var highlightClass = '' - if (value.score > 0) highlightClass = 'negative' - else if (value.score < 0) highlightClass = 'positive' - else highlightClass = 'neutral' - $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>'); - }); - $('[data-bs-toggle="tooltip"]').tooltip() - } - if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') { - if (data.action === "add header") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>'); - } else if (data.action === "reject") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>'); - } else if (data.action === "rewrite subject") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>'); - } - } - if (typeof data.recipients !== 'undefined') { - $.each(data.recipients, function(index, value) { - var elem = $('<span class="mail-address-item"></span>'); - elem.text(value.address + ' (' + value.type.toUpperCase() + ')'); - $('#qid_detail_recipients').append(elem); - }); - } - }, - error: function(data){ - if (typeof data.error !== 'undefined') { - qError.text("Error loading quarantine item"); - qError.show(); - } - } - }); -}); +jQuery(function($){ + var qitem = $('legend').data('hash'); + var qError = $("#qid_error"); + $.ajax({ + url: '/inc/ajax/qitem_details.php', + data: { hash: qitem }, + dataType: 'json', + success: function(data){ + $('[data-id="qitems_single"]').each(function(index) { + $(this).attr("data-item", qitem); + }); + $('#qid_detail_subj').text(data.subject); + $('#qid_detail_hfrom').text(data.header_from); + $('#qid_detail_efrom').text(data.env_from); + $('#qid_detail_score').html(''); + $('#qid_detail_symbols').html(''); + $('#qid_detail_recipients').html(''); + $('#qid_detail_fuzzy').html(''); + if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) { + $.each(data.fuzzy_hashes, function (index, value) { + $('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + value + '</p>'); + }); + } else { + $('#qid_detail_fuzzy').append('-'); + } + if (typeof data.symbols !== 'undefined') { + data.symbols.sort(function (a, b) { + if (a.score === 0) return 1; + if (b.score === 0) return -1; + if (b.score < 0 && a.score < 0) { + return a.score - b.score; + } + if (b.score > 0 && a.score > 0) { + return b.score - a.score; + } + return b.score - a.score; + }) + $.each(data.symbols, function (index, value) { + var highlightClass = ''; + if (value.score > 0) highlightClass = 'negative'; + else if (value.score < 0) highlightClass = 'positive'; + else highlightClass = 'neutral'; + $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>'); + }); + $('[data-bs-toggle="tooltip"]').tooltip(); + } + if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') { + if (data.action === "add header") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>'); + } else if (data.action === "reject") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>'); + } else if (data.action === "rewrite subject") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>'); + } + } + if (typeof data.recipients !== 'undefined') { + $.each(data.recipients, function(index, value) { + var elem = $('<span class="mail-address-item"></span>'); + elem.text(value.address + ' (' + value.type.toUpperCase() + ')'); + $('#qid_detail_recipients').append(elem); + }); + } + }, + error: function(data){ + if (typeof data.error !== 'undefined') { + qError.text("Error loading quarantine item"); + qError.show(); + } + } + }); +}); diff --git a/data/web/js/site/quarantine.js b/data/web/js/site/quarantine.js index 7da3a7dd..e69863f7 100644 --- a/data/web/js/site/quarantine.js +++ b/data/web/js/site/quarantine.js @@ -1,286 +1,297 @@ -// Base64 functions -var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; - -jQuery(function($){ - acl_data = JSON.parse(acl); - // 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]})} - 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]} - $(".refresh_table").on('click', function(e) { - e.preventDefault(); - var table_name = $(this).data('table'); - $('#' + table_name).DataTable().ajax.reload(); - }); - function draw_quarantine_table() { - var table = $('#quarantinetable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - initComplete: function(){ - hideTableExpandCollapseBtn('#quarantinetable'); - }, - ajax: { - type: "GET", - url: "/api/v1/get/quarantine/all", - dataSrc: function(data){ - $.each(data, function (i, item) { - if (item.subject === null) { - item.subject = ''; - } else { - item.subject = escapeHtml(item.subject); - } - if (item.score === null) { - item.score = '-'; - } - if (item.virus_flag > 0) { - item.virus = '<span class="badge fs-6 bg-danger">' + lang.high_danger + '</span>'; - } else { - item.virus = '<span class="badge fs-6 bg-secondary">' + lang.neutral_danger + '</span>'; - } - if (item.action === "reject") { - item.rspamdaction = '<span class="badge fs-6 bg-danger">' + lang.rejected + '</span>'; - } else if (item.action === "add header") { - item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.junk_folder + '</span>'; - } else if (item.action === "rewrite subject") { - item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.rewrite_subject + '</span>'; - } - if(item.notified > 0) { - item.notified = '✔'; - } else { - item.notified = '✖'; - } - if (acl_data.login_as === 1) { - item.action = '<div class="btn-group">' + - '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' + - '<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - } - else { - item.action = '<div class="btn-group">' + - '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><i class="bi bi-file-earmark-text"></i> ' + lang.show_item + '</a>' + - '</div>'; - } - item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />'; - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'id', - defaultContent: '' - }, - { - title: lang.qid, - data: 'qid', - defaultContent: '' - }, - { - title: lang.sender, - data: 'sender', - defaultContent: '' - }, - { - title: lang.subj, - data: 'subject', - defaultContent: '' - }, - { - title: lang.rspamd_result, - data: 'rspamdaction', - defaultContent: '' - }, - { - title: lang.rcpt, - data: 'rcpt', - defaultContent: '' - }, - { - title: lang.danger, - data: 'virus', - defaultContent: '' - }, - { - title: lang.spam_score, - data: 'score', - defaultContent: '' - }, - { - title: lang.notified, - data: 'notified', - defaultContent: '' - }, - { - title: lang.received, - data: 'created', - defaultContent: '', - createdCell: function(td, cellData) { - $(td).attr({ - "data-order": cellData, - "data-sort": cellData - }); - - var date = new Date(cellData ? cellData * 1000 : 0); - var dateString = date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - $(td).html(dateString); - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, - ] - }); - - table.on('responsive-resize', function (e, datatable, columns){ - hideTableExpandCollapseBtn('#quarantinetable'); - }); - } - - $('body').on('click', '.show_qid_info', function (e) { - e.preventDefault(); - var qitem = $(this).attr('data-item'); - var qError = $("#qid_error"); - - $('#qidDetailModal').modal('show'); - qError.hide(); - - $.ajax({ - url: '/inc/ajax/qitem_details.php', - data: { id: qitem }, - dataType: 'json', - success: function(data){ - - $('[data-id="qitems_single"]').each(function(index) { - $(this).attr("data-item", qitem); - }); - - $("#quick_download_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&eml', '_blank')"); - $("#quick_release_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&quick_release', '_blank')"); - $("#quick_delete_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&quick_delete', '_blank')"); - - $('#qid_detail_subj').text(data.subject); - $('#qid_detail_hfrom').text(data.header_from); - $('#qid_detail_efrom').text(data.env_from); - $('#qid_detail_score').html(''); - $('#qid_detail_recipients').html(''); - $('#qid_detail_symbols').html(''); - $('#qid_detail_fuzzy').html(''); - if (typeof data.symbols !== 'undefined') { - data.symbols.sort(function (a, b) { - if (a.score === 0) return 1 - if (b.score === 0) return -1 - if (b.score < 0 && a.score < 0) { - return a.score - b.score - } - if (b.score > 0 && a.score > 0) { - return b.score - a.score - } - return b.score - a.score - }) - $.each(data.symbols, function (index, value) { - var highlightClass = '' - if (value.score > 0) highlightClass = 'negative' - else if (value.score < 0) highlightClass = 'positive' - else highlightClass = 'neutral' - $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>'); - }); - $('[data-bs-toggle="tooltip"]').tooltip() - } - if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) { - $.each(data.fuzzy_hashes, function (index, value) { - $('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + value + '</p>'); - }); - } else { - $('#qid_detail_fuzzy').append('-'); - } - if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') { - if (data.action == "add header") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>'); - } else if (data.action == "reject") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>'); - } else if (data.action == "rewrite subject") { - $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>'); - } - } - if (typeof data.recipients !== 'undefined') { - $.each(data.recipients, function(index, value) { - var elem = $('<span class="mail-address-item"></span>'); - elem.text(value.address + ' (' + value.type.toUpperCase() + ')'); - $('#qid_detail_recipients').append(elem); - }); - } - $('#qid_detail_text').text(data.text_plain); - $('#qid_detail_text_from_html').text(data.text_html); - var qAtts = $("#qid_detail_atts"); - if (typeof data.attachments !== 'undefined') { - qAtts.text(''); - $.each(data.attachments, function(index, value) { - qAtts.append( - '<p><a href="/inc/ajax/qitem_details.php?id=' + qitem + '&att=' + index + '" target="_blank">' + value[0] + '</a> (' + value[1] + ')' + - ' - <small><a href="' + value[3] + '" target="_blank">' + lang.check_hash + '</a></small></p>' - ); - }); - } - else { - qAtts.text('-'); - } - }, - error: function(data){ - if (typeof data.error !== 'undefined') { - $('#qid_detail_subj').text('-'); - $('#qid_detail_hfrom').text('-'); - $('#qid_detail_efrom').text('-'); - $('#qid_detail_score').html('-'); - $('#qid_detail_recipients').html('-'); - $('#qid_detail_symbols').html('-'); - $('#qid_detail_fuzzy').html('-'); - $('#qid_detail_text').text('-'); - $('#qid_detail_text_from_html').text('-'); - qError.text("Error loading quarantine item"); - qError.show(); - } - } - }); - }); - - $('body').on('click', 'span.footable-toggle', function () { - event.stopPropagation(); - }) - - // Initial table drawings - draw_quarantine_table(); - - - function hideTableExpandCollapseBtn(table){ - if ($(table).hasClass('collapsed')) - $(".table_collapse_option").show(); - else - $(".table_collapse_option").hide(); - } -}); +// Base64 functions +var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; + +jQuery(function($){ + acl_data = JSON.parse(acl); + // 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]})} + 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]} + $(".refresh_table").on('click', function(e) { + e.preventDefault(); + var table_name = $(this).data('table'); + $('#' + table_name).DataTable().ajax.reload(); + }); + function draw_quarantine_table() { + var table = $('#quarantinetable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + order: [[2, 'desc']], + lengthMenu: [ + [10, 25, 50, 100, -1], + [10, 25, 50, 100, 'all'] + ], + pagingType: 'first_last_numbers', + aColumns: [ + { sWidth: '8.25%' }, + { sClass: 'classDataTable' } + ], + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + initComplete: function(){ + hideTableExpandCollapseBtn('#quarantinetable'); + }, + ajax: { + type: "GET", + url: "/api/v1/get/quarantine/all", + dataSrc: function(data){ + $.each(data, function (i, item) { + if (item.subject === null) { + item.subject = ''; + } else { + item.subject = escapeHtml(item.subject); + } + if (item.score === null) { + item.score = '-'; + } + if (item.virus_flag > 0) { + item.virus = '<span class="badge fs-6 bg-danger">' + lang.high_danger + '</span>'; + } else { + item.virus = '<span class="badge fs-6 bg-secondary">' + lang.neutral_danger + '</span>'; + } + if (item.action === "reject") { + item.rspamdaction = '<span class="badge fs-6 bg-danger">' + lang.rejected + '</span>'; + } else if (item.action === "add header") { + item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.junk_folder + '</span>'; + } else if (item.action === "rewrite subject") { + item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.rewrite_subject + '</span>'; + } + if(item.notified > 0) { + item.notified = '✔'; + } else { + item.notified = '✖'; + } + if (acl_data.login_as === 1) { + item.action = '<div class="btn-group">' + + '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' + + '<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + } + else { + item.action = '<div class="btn-group">' + + '<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-info show_qid_info"><i class="bi bi-file-earmark-text"></i> ' + lang.show_item + '</a>' + + '</div>'; + } + item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />'; + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'id', + defaultContent: '' + }, + { + title: lang.qid, + data: 'qid', + defaultContent: '' + }, + { + title: lang.sender, + data: 'sender', + className: 'senders-mw220', + defaultContent: '' + }, + { + title: lang.subj, + data: 'subject', + defaultContent: '' + }, + { + title: lang.rspamd_result, + data: 'rspamdaction', + defaultContent: '' + }, + { + title: lang.rcpt, + data: 'rcpt', + defaultContent: '' + }, + { + title: lang.danger, + data: 'virus', + defaultContent: '' + }, + { + title: lang.spam_score, + data: 'score', + defaultContent: '' + }, + { + title: lang.notified, + data: 'notified', + defaultContent: '' + }, + { + title: lang.received, + data: 'created', + defaultContent: '', + createdCell: function(td, cellData) { + $(td).attr({ + "data-order": cellData, + "data-sort": cellData + }); + + var date = new Date(cellData ? cellData * 1000 : 0); + var dateString = date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + $(td).html(dateString); + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, + ] + }); + + table.on('responsive-resize', function (e, datatable, columns){ + hideTableExpandCollapseBtn('#quarantinetable'); + }); + } + + $('body').on('click', '.show_qid_info', function (e) { + e.preventDefault(); + var qitem = $(this).attr('data-item'); + var qError = $("#qid_error"); + + $('#qidDetailModal').modal('show'); + qError.hide(); + + $.ajax({ + url: '/inc/ajax/qitem_details.php', + data: { id: qitem }, + dataType: 'json', + success: function(data){ + + $('[data-id="qitems_single"]').each(function(index) { + $(this).attr("data-item", qitem); + }); + + $("#quick_download_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&eml', '_blank')"); + $("#quick_release_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&quick_release', '_blank')"); + $("#quick_delete_link").attr("onclick", "window.open('/inc/ajax/qitem_details.php?id=" + qitem + "&quick_delete', '_blank')"); + + $('#qid_detail_subj').text(data.subject); + $('#qid_detail_hfrom').text(data.header_from); + $('#qid_detail_efrom').text(data.env_from); + $('#qid_detail_score').html(''); + $('#qid_detail_recipients').html(''); + $('#qid_detail_symbols').html(''); + $('#qid_detail_fuzzy').html(''); + if (typeof data.symbols !== 'undefined') { + data.symbols.sort(function (a, b) { + if (a.score === 0) return 1; + if (b.score === 0) return -1; + if (b.score < 0 && a.score < 0) { + return a.score - b.score; + } + if (b.score > 0 && a.score > 0) { + return b.score - a.score; + } + return b.score - a.score; + }) + $.each(data.symbols, function (index, value) { + var highlightClass = ''; + if (value.score > 0) highlightClass = 'negative'; + else if (value.score < 0) highlightClass = 'positive'; + else highlightClass = 'neutral'; + $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>'); + }); + $('[data-bs-toggle="tooltip"]').tooltip(); + } + if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) { + $.each(data.fuzzy_hashes, function (index, value) { + $('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + value + '</p>'); + }); + } else { + $('#qid_detail_fuzzy').append('-'); + } + if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') { + if (data.action == "add header") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>'); + } else if (data.action == "reject") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>'); + } else if (data.action == "rewrite subject") { + $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>'); + } + } + if (typeof data.recipients !== 'undefined') { + $.each(data.recipients, function(index, value) { + var elem = $('<span class="mail-address-item"></span>'); + elem.text(value.address + ' (' + value.type.toUpperCase() + ')'); + $('#qid_detail_recipients').append(elem); + }); + } + $('#qid_detail_text').text(data.text_plain); + $('#qid_detail_text_from_html').text(data.text_html); + var qAtts = $("#qid_detail_atts"); + if (typeof data.attachments !== 'undefined') { + qAtts.text(''); + $.each(data.attachments, function(index, value) { + qAtts.append( + '<p><a href="/inc/ajax/qitem_details.php?id=' + qitem + '&att=' + index + '" target="_blank">' + value[0] + '</a> (' + value[1] + ')' + + ' - <small><a href="' + value[3] + '" target="_blank">' + lang.check_hash + '</a></small></p>' + ); + }); + } + else { + qAtts.text('-'); + } + }, + error: function(data){ + if (typeof data.error !== 'undefined') { + $('#qid_detail_subj').text('-'); + $('#qid_detail_hfrom').text('-'); + $('#qid_detail_efrom').text('-'); + $('#qid_detail_score').html('-'); + $('#qid_detail_recipients').html('-'); + $('#qid_detail_symbols').html('-'); + $('#qid_detail_fuzzy').html('-'); + $('#qid_detail_text').text('-'); + $('#qid_detail_text_from_html').text('-'); + qError.text("Error loading quarantine item"); + qError.show(); + } + } + }); + }); + + $('body').on('click', 'span.footable-toggle', function () { + event.stopPropagation(); + }) + + // Initial table drawings + draw_quarantine_table(); + + function hideTableExpandCollapseBtn(table){ + if ($(table).hasClass('collapsed')) + $(".table_collapse_option").show(); + else + $(".table_collapse_option").hide(); + } +}); diff --git a/data/web/js/site/queue.js b/data/web/js/site/queue.js index ebebaff8..bc4c7369 100644 --- a/data/web/js/site/queue.js +++ b/data/web/js/site/queue.js @@ -1,127 +1,128 @@ jQuery(function($){ - $(".refresh_table").on('click', function(e) { - e.preventDefault(); - var table_name = $(this).data('table'); - $('#' + table_name).DataTable().ajax.reload(); - }); + $(".refresh_table").on('click', function(e) { + e.preventDefault(); + var table_name = $(this).data('table'); + $('#' + table_name).DataTable().ajax.reload(); + }); - 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]} - // Queue item - $('#showQueuedMsg').on('show.bs.modal', function (e) { - $('#queue_msg_content').text(lang.loading); - button = $(e.relatedTarget) - if (button != null) { - $('#queue_id').text(button.data('queue-id')); - } - $.ajax({ - type: 'GET', - url: '/api/v1/get/postcat/' + button.data('queue-id'), - dataType: 'text', - complete: function (data) { - $('#queue_msg_content').text(data.responseText); - } - }); - }) - - function draw_queue() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#queuetable') ) { - $('#queuetable').DataTable().columns.adjust().responsive.recalc(); - return; + // Queue item + $('#showQueuedMsg').on('show.bs.modal', function (e) { + $('#queue_msg_content').text(lang.loading); + button = $(e.relatedTarget) + if (button != null) { + $('#queue_id').text(button.data('queue-id')); } + $.ajax({ + type: 'GET', + url: '/api/v1/get/postcat/' + button.data('queue-id'), + dataType: 'text', + complete: function (data) { + $('#queue_msg_content').text(data.responseText); + } + }); + }) - $('#queuetable').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/mailq/all", - dataSrc: function(data){ - $.each(data, function (i, item) { - item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />'; - rcpts = $.map(item.recipients, function(i) { - return escapeHtml(i); - }); - item.recipients = rcpts.join('<hr style="margin:1px!important">'); - item.action = '<div class="btn-group">' + - '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.show_message + '</a>' + + function draw_queue() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#queuetable') ) { + $('#queuetable').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#queuetable').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/mailq/all", + dataSrc: function(data){ + $.each(data, function (i, item) { + item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />'; + rcpts = $.map(item.recipients, function(i) { + return escapeHtml(i); + }); + item.recipients = rcpts.join('<hr style="margin:1px!important">'); + item.action = '<div class="btn-group">' + + '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.show_message + '</a>' + '</div>'; }); return data; } }, columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'QID', - data: 'queue_id', - defaultContent: '' - }, - { - title: 'Queue', - data: 'queue_name', - defaultContent: '' - }, - { - title: lang_admin.arrival_time, - data: 'arrival_time', - defaultContent: '', - render: function (data, type){ - var date = new Date(data ? data * 1000 : 0); - return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - } - }, - { - title: lang_admin.message_size, - data: 'message_size', - defaultContent: '', - render: function (data, type){ - return humanFileSize(data); - } - }, - { - title: lang_admin.sender, - data: 'sender', - defaultContent: '' - }, - { - title: lang_admin.recipients, - data: 'recipients', - defaultContent: '' - }, - { - title: lang_admin.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - }, + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'QID', + data: 'queue_id', + defaultContent: '' + }, + { + title: 'Queue', + data: 'queue_name', + defaultContent: '' + }, + { + title: lang_admin.arrival_time, + data: 'arrival_time', + defaultContent: '', + render: function (data, type){ + var date = new Date(data ? data * 1000 : 0); + return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + } + }, + { + title: lang_admin.message_size, + data: 'message_size', + defaultContent: '', + render: function (data, type){ + return humanFileSize(data); + } + }, + { + title: lang_admin.sender, + data: 'sender', + defaultContent: '' + }, + { + title: lang_admin.recipients, + data: 'recipients', + defaultContent: '' + }, + { + title: lang_admin.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + }, ] }); } draw_queue(); -}) \ No newline at end of file +}) diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index d1b9780f..d93e692f 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -1,662 +1,667 @@ -// Base64 functions -var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; -$(document).ready(function() { - // Spam score slider - var spam_slider = $('#spam_score')[0]; - if (typeof spam_slider !== 'undefined') { - noUiSlider.create(spam_slider, { - start: user_spam_score, - connect: [true, true, true], - range: { - 'min': [0], //stepsize is 50.000 - '50%': [10], - '70%': [20, 5], - '80%': [50, 10], - '90%': [100, 100], - '95%': [1000, 1000], - 'max': [5000] - }, - }); - var connect = spam_slider.querySelectorAll('.noUi-connect'); - var classes = ['c-1-color', 'c-2-color', 'c-3-color']; - for (var i = 0; i < connect.length; i++) { - connect[i].classList.add(classes[i]); - } - spam_slider.noUiSlider.on('update', function (values, handle) { - $('.spam-ham-score').text('< ' + Math.round(values[0] * 10) / 10); - $('.spam-spam-score').text(Math.round(values[0] * 10) / 10 + ' - ' + Math.round(values[1] * 10) / 10); - $('.spam-reject-score').text('> ' + Math.round(values[1] * 10) / 10); - $('#spam_score_value').val((Math.round(values[0] * 10) / 10) + ',' + (Math.round(values[1] * 10) / 10)); - }); - } - // syncjobLogModal - $('#syncjobLogModal').on('show.bs.modal', function(e) { - var syncjob_id = $(e.relatedTarget).data('syncjob-id'); - $.ajax({ - url: '/inc/ajax/syncjob_logs.php', - data: { id: syncjob_id }, - dataType: 'text', - success: function(data){ - $(e.currentTarget).find('#logText').text(data); - }, - error: function(xhr, status, error) { - $(e.currentTarget).find('#logText').text(xhr.responseText); - } - }); - }); - $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); - $("#pushover_delete").click(function() { return confirm(lang.delete_ays); }); - -}); -jQuery(function($){ - // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery - var entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/', - '`': '`', - '=': '=' - }; - function escapeHtml(string) { - return String(string).replace(/[&<>"'`=\/]/g, function (s) { - return entityMap[s]; - }); - } - // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript - function validateEmail(email) { - var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(email); - } - function unix_time_format(tm) { - var date = new Date(tm ? tm * 1000 : 0); - return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - } - acl_data = JSON.parse(acl); - - $('.clear-last-logins').on('click', function () {if (confirm(lang.delete_ays)) {last_logins('reset');}}) - $(".login-history").on('click', function(e) {e.preventDefault(); last_logins('get', $(this).data('days'));$(this).addClass('active').siblings().removeClass('active');}); - - function last_logins(action, days = 7) { - if (action == 'get') { - $('.last-login').html('<i class="bi bi-hourglass"></i>' + lang.waiting); - $.ajax({ - dataType: 'json', - url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username) + '/' + days, - jsonp: false, - error: function () { - console.log('error reading last logins'); - }, - success: function (data) { - $('.last-login').html(); - if (data.ui.time) { - $('.last-login').html('<i class="bi bi-person-fill"></i> ' + lang.last_ui_login + ': ' + unix_time_format(data.ui.time)); - } else { - $('.last-login').text(lang.no_last_login); - } - if (data.sasl) { - $('.last-login').append('<ul class="list-group">'); - $.each(data.sasl, function (i, item) { - var datetime = new Date(item.datetime.replace(/-/g, "/")); - var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - var service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>'; - var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : ''; - var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.he.net/ip/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>"; - var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : ''; - var ip_data = real_rip + ip_location + app_password; - $(".last-login").append('<li class="list-group-item">' + local_datetime + " " + service + " " + lang.from + " " + ip_data + "</li>"); - }) - $('.last-login').append('</ul>'); - } - } - }) - } else if (action == 'reset') { - $.ajax({ - dataType: 'json', - url: '/api/v1/get/reset-last-login/' + encodeURIComponent(mailcow_cc_username), - jsonp: false, - error: function () { - console.log('cannot reset last logins'); - }, - success: function (data) { - last_logins('get'); - } - }) - } - } - - function draw_tla_table() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#tla_table') ) { - $('#tla_table').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#tla_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: "/api/v1/get/time_limited_aliases", - dataSrc: function(data){ - console.log(data); - $.each(data, function (i, item) { - if (acl_data.spam_alias === 1) { - item.action = '<div class="btn-group">' + - '<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />'; - item.address = escapeHtml(item.address); - } - else { - item.chkbox = '<input type="checkbox" disabled />'; - item.action = '<span>-</span>'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: lang.alias, - data: 'address', - defaultContent: '' - }, - { - title: lang.alias_valid_until, - data: 'validity', - defaultContent: '', - render: function (data, type) { - var date = new Date(data ? data * 1000 : 0); - return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - } - }, - { - title: lang.created_on, - data: 'created', - defaultContent: '', - render: function (data, type) { - var date = new Date(data.replace(/-/g, "/")); - return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - } - ] - }); - } - function draw_sync_job_table() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#sync_job_table') ) { - $('#sync_job_table').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#sync_job_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log', - dataSrc: function(data){ - console.log(data); - $.each(data, function (i, item) { - item.user1 = escapeHtml(item.user1); - item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>' - if (!item.exclude > 0) { - item.exclude = '-'; - } else { - item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>'; - } - item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1); - if (acl_data.syncjobs === 1) { - item.action = '<div class="btn-group">' + - '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />'; - } - else { - item.action = '<span>-</span>'; - item.chkbox = '<input type="checkbox" disabled />'; - } - if (item.is_running == 1) { - item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>'; - } else { - item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>'; - } - if (!item.last_run > 0) { - item.last_run = lang.waiting; - } - if (item.success == null) { - item.success = '-'; - item.exit_status = ''; - } else { - item.success = '<i class="text-' + (item.success == 1 ? 'success' : 'danger') + ' bi bi-' + (item.success == 1 ? 'check-lg' : 'x-lg') + '"></i>'; - } - if (lang['syncjob_'+item.exit_status]) { - item.exit_status = lang['syncjob_'+item.exit_status]; - } else if (item.success != '-') { - item.exit_status = lang.syncjob_check_log; - } - item.exit_status = item.success + ' ' + item.exit_status; - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 1 - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '', - responsivePriority: 2 - }, - { - title: 'ID', - data: 'id', - defaultContent: '', - responsivePriority: 3 - }, - { - title: 'Server', - data: 'server_w_port', - defaultContent: '' - }, - { - title: lang.username, - data: 'user1', - defaultContent: '', - responsivePriority: 3 - }, - { - title: lang.last_run, - data: 'last_run', - defaultContent: '' - }, - { - title: lang.syncjob_last_run_result, - data: 'exit_status', - defaultContent: '' - }, - { - title: 'Log', - data: 'log', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.status, - data: 'is_running', - defaultContent: '', - responsivePriority: 5 - }, - { - title: lang.encryption, - data: 'enc1', - defaultContent: '' - }, - { - title: lang.excludes, - data: 'exclude', - defaultContent: '' - }, - { - title: lang.interval + " (min)", - data: 'mins_interval', - defaultContent: '' - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '', - responsivePriority: 5 - } - ] - }); - } - function draw_app_passwd_table() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#app_passwd_table') ) { - $('#app_passwd_table').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#app_passwd_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/app-passwd/all', - dataSrc: function(data){ - console.log(data); - $.each(data, function (i, item) { - item.name = escapeHtml(item.name) - item.protocols = [] - if (item.imap_access == 1) { item.protocols.push("<code>IMAP</code>"); } - if (item.smtp_access == 1) { item.protocols.push("<code>SMTP</code>"); } - if (item.eas_access == 1) { item.protocols.push("<code>EAS/ActiveSync</code>"); } - if (item.dav_access == 1) { item.protocols.push("<code>DAV</code>"); } - if (item.pop3_access == 1) { item.protocols.push("<code>POP3</code>"); } - if (item.sieve_access == 1) { item.protocols.push("<code>Sieve</code>"); } - item.protocols = item.protocols.join(" ") - if (acl_data.app_passwds === 1) { - item.action = '<div class="btn-group">' + - '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + - '<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + - '</div>'; - item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />'; - } - else { - item.action = '<span>-</span>'; - item.chkbox = '<input type="checkbox" disabled />'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'id', - defaultContent: '' - }, - { - title: lang.app_name, - data: 'name', - defaultContent: '' - }, - { - title: lang.allowed_protocols, - data: 'protocols', - defaultContent: '' - }, - { - title: lang.active, - data: 'active', - defaultContent: '', - render: function (data, type) { - return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>' - } - }, - { - title: lang.action, - data: 'action', - className: 'text-md-end dt-sm-head-hidden dt-body-right', - defaultContent: '' - } - ] - }); - } - function draw_wl_policy_mailbox_table() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#wl_policy_mailbox_table') ) { - $('#wl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#wl_policy_mailbox_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/policy_wl_mailbox', - dataSrc: function(data){ - console.log(data); - $.each(data, function (i, item) { - if (validateEmail(item.object)) { - item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />'; - } - else { - item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />'; - } - if (acl_data.spam_policy === 0) { - item.chkbox = '<input type="checkbox" disabled />'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'prefid', - defaultContent: '' - }, - { - title: lang.spamfilter_table_rule, - data: 'value', - defaultContent: '' - }, - { - title:'Scope', - data: 'object', - defaultContent: '' - } - ] - }); - } - function draw_bl_policy_mailbox_table() { - // just recalc width if instance already exists - if ($.fn.DataTable.isDataTable('#bl_policy_mailbox_table') ) { - $('#bl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc(); - return; - } - - $('#bl_policy_mailbox_table').DataTable({ - responsive: true, - processing: true, - serverSide: false, - stateSave: true, - dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + - "tr" + - "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", - language: lang_datatables, - ajax: { - type: "GET", - url: '/api/v1/get/policy_bl_mailbox', - dataSrc: function(data){ - console.log(data); - $.each(data, function (i, item) { - if (validateEmail(item.object)) { - item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />'; - } - else { - item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />'; - } - if (acl_data.spam_policy === 0) { - item.chkbox = '<input type="checkbox" disabled />'; - } - }); - - return data; - } - }, - columns: [ - { - // placeholder, so checkbox will not block child row toggle - title: '', - data: null, - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: '', - data: 'chkbox', - searchable: false, - orderable: false, - defaultContent: '' - }, - { - title: 'ID', - data: 'prefid', - defaultContent: '' - }, - { - title: lang.spamfilter_table_rule, - data: 'value', - defaultContent: '' - }, - { - title:'Scope', - data: 'object', - defaultContent: '' - } - ] - }); - } - - // FIDO2 friendly name modal - $('#fido2ChangeFn').on('show.bs.modal', function (e) { - rename_link = $(e.relatedTarget) - if (rename_link != null) { - $('#fido2_cid').val(rename_link.data('cid')); - $('#fido2_subject_desc').text(Base64.decode(rename_link.data('subject'))); - } - }) - - // Sieve data modal - $('#userFilterModal').on('show.bs.modal', function(e) { - $('#user_sieve_filter').text(lang.loading); - $.ajax({ - dataType: 'json', - url: '/api/v1/get/active-user-sieve/' + encodeURIComponent(mailcow_cc_username), - jsonp: false, - error: function () { - console.log('Cannot get active sieve script'); - }, - complete: function (data) { - if (data.responseText == '{}') { - $('#user_sieve_filter').text(lang.no_active_filter); - } else { - $('#user_sieve_filter').text(JSON.parse(data.responseText)); - } - } - }) - }); - $('#userFilterModal').on('hidden.bs.modal', function () { - $('#user_sieve_filter').text(lang.loading); - }); - - // detect element visibility changes - function onVisible(element, callback) { - $(document).ready(function() { - element_object = document.querySelector(element); - if (element_object === null) return; - - new IntersectionObserver((entries, observer) => { - entries.forEach(entry => { - if(entry.intersectionRatio > 0) { - callback(element_object); - } - }); - }).observe(element_object); - }); - } - - // Load only if the tab is visible - onVisible("[id^=tla_table]", () => draw_tla_table()); - onVisible("[id^=bl_policy_mailbox_table]", () => draw_bl_policy_mailbox_table()); - onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table()); - onVisible("[id^=sync_job_table]", () => draw_sync_job_table()); - onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table()); - last_logins('get'); -}); +// Base64 functions +var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}}; +$(document).ready(function() { + // Spam score slider + var spam_slider = $('#spam_score')[0]; + if (typeof spam_slider !== 'undefined') { + noUiSlider.create(spam_slider, { + start: user_spam_score, + connect: [true, true, true], + range: { + 'min': [0], //stepsize is 50.000 + '50%': [10], + '70%': [20, 5], + '80%': [50, 10], + '90%': [100, 100], + '95%': [1000, 1000], + 'max': [5000] + }, + }); + var connect = spam_slider.querySelectorAll('.noUi-connect'); + var classes = ['c-1-color', 'c-2-color', 'c-3-color']; + for (var i = 0; i < connect.length; i++) { + connect[i].classList.add(classes[i]); + } + spam_slider.noUiSlider.on('update', function (values, handle) { + $('.spam-ham-score').text('< ' + Math.round(values[0] * 10) / 10); + $('.spam-spam-score').text(Math.round(values[0] * 10) / 10 + ' - ' + Math.round(values[1] * 10) / 10); + $('.spam-reject-score').text('> ' + Math.round(values[1] * 10) / 10); + $('#spam_score_value').val((Math.round(values[0] * 10) / 10) + ',' + (Math.round(values[1] * 10) / 10)); + }); + } + // syncjobLogModal + $('#syncjobLogModal').on('show.bs.modal', function(e) { + var syncjob_id = $(e.relatedTarget).data('syncjob-id'); + $.ajax({ + url: '/inc/ajax/syncjob_logs.php', + data: { id: syncjob_id }, + dataType: 'text', + success: function(data){ + $(e.currentTarget).find('#logText').text(data); + }, + error: function(xhr, status, error) { + $(e.currentTarget).find('#logText').text(xhr.responseText); + } + }); + }); + $(".arrow-toggle").on('click', function(e) { e.preventDefault(); $(this).find('.arrow').toggleClass("animation"); }); + $("#pushover_delete").click(function() { return confirm(lang.delete_ays); }); + +}); +jQuery(function($){ + // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery + var entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '/': '/', + '`': '`', + '=': '=' + }; + function escapeHtml(string) { + return String(string).replace(/[&<>"'`=\/]/g, function (s) { + return entityMap[s]; + }); + } + // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript + function validateEmail(email) { + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(email); + } + function unix_time_format(tm) { + var date = new Date(tm ? tm * 1000 : 0); + return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + } + acl_data = JSON.parse(acl); + + $('.clear-last-logins').on('click', function () {if (confirm(lang.delete_ays)) {last_logins('reset');}}) + $(".login-history").on('click', function(e) {e.preventDefault(); last_logins('get', $(this).data('days'));$(this).addClass('active').siblings().removeClass('active');}); + + function last_logins(action, days = 7) { + if (action == 'get') { + $('.last-login').html('<i class="bi bi-hourglass"></i>' + lang.waiting); + $.ajax({ + dataType: 'json', + url: '/api/v1/get/last-login/' + encodeURIComponent(mailcow_cc_username) + '/' + days, + jsonp: false, + error: function () { + console.log('error reading last logins'); + }, + success: function (data) { + $('.last-login').html(); + if (data.ui.time) { + $('.last-login').html('<i class="bi bi-person-fill"></i> ' + lang.last_ui_login + ': ' + unix_time_format(data.ui.time)); + } else { + $('.last-login').text(lang.no_last_login); + } + if (data.sasl) { + $('.last-login').append('<ul class="list-group">'); + $.each(data.sasl, function (i, item) { + var datetime = new Date(item.datetime.replace(/-/g, "/")); + var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + var service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>'; + var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : ''; + var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.he.net/ip/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>"; + var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : ''; + var ip_data = real_rip + ip_location + app_password; + $(".last-login").append('<li class="list-group-item">' + local_datetime + " " + service + " " + lang.from + " " + ip_data + "</li>"); + }) + $('.last-login').append('</ul>'); + } + } + }) + } else if (action == 'reset') { + $.ajax({ + dataType: 'json', + url: '/api/v1/get/reset-last-login/' + encodeURIComponent(mailcow_cc_username), + jsonp: false, + error: function () { + console.log('cannot reset last logins'); + }, + success: function (data) { + last_logins('get'); + } + }) + } + } + + function draw_tla_table() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#tla_table') ) { + $('#tla_table').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#tla_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: "/api/v1/get/time_limited_aliases", + dataSrc: function(data){ + console.log(data); + $.each(data, function (i, item) { + if (acl_data.spam_alias === 1) { + item.action = '<div class="btn-group">' + + '<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />'; + item.address = escapeHtml(item.address); + } + else { + item.chkbox = '<input type="checkbox" disabled />'; + item.action = '<span>-</span>'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: lang.alias, + data: 'address', + defaultContent: '' + }, + { + title: lang.alias_valid_until, + data: 'validity', + defaultContent: '', + render: function (data, type) { + var date = new Date(data ? data * 1000 : 0); + return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + } + }, + { + title: lang.created_on, + data: 'created', + defaultContent: '', + render: function (data, type) { + var date = new Date(data.replace(/-/g, "/")); + return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"}); + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + } + ] + }); + } + function draw_sync_job_table() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#sync_job_table') ) { + $('#sync_job_table').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#sync_job_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log', + dataSrc: function(data){ + console.log(data); + $.each(data, function (i, item) { + item.user1 = escapeHtml(item.user1); + item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>' + if (!item.exclude > 0) { + item.exclude = '-'; + } else { + item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>'; + } + item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1); + if (acl_data.syncjobs === 1) { + item.action = '<div class="btn-group">' + + '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />'; + } + else { + item.action = '<span>-</span>'; + item.chkbox = '<input type="checkbox" disabled />'; + } + if (item.is_running == 1) { + item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>'; + } else { + item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>'; + } + if (!item.last_run > 0) { + item.last_run = lang.waiting; + } + if (item.success == null) { + item.success = '-'; + item.exit_status = ''; + } else { + item.success = '<i class="text-' + (item.success == 1 ? 'success' : 'danger') + ' bi bi-' + (item.success == 1 ? 'check-lg' : 'x-lg') + '"></i>'; + } + if (lang['syncjob_'+item.exit_status]) { + item.exit_status = lang['syncjob_'+item.exit_status]; + } else if (item.success != '-') { + item.exit_status = lang.syncjob_check_log; + } + item.exit_status = item.success + ' ' + item.exit_status; + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 1 + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '', + responsivePriority: 2 + }, + { + title: 'ID', + data: 'id', + defaultContent: '', + responsivePriority: 3 + }, + { + title: 'Server', + data: 'server_w_port', + defaultContent: '' + }, + { + title: lang.username, + data: 'user1', + defaultContent: '', + responsivePriority: 3 + }, + { + title: lang.last_run, + data: 'last_run', + defaultContent: '' + }, + { + title: lang.syncjob_last_run_result, + data: 'exit_status', + defaultContent: '' + }, + { + title: 'Log', + data: 'log', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>' + } + }, + { + title: lang.status, + data: 'is_running', + defaultContent: '', + responsivePriority: 5 + }, + { + title: lang.encryption, + data: 'enc1', + defaultContent: '' + }, + { + title: lang.excludes, + data: 'exclude', + defaultContent: '' + }, + { + title: lang.interval + " (min)", + data: 'mins_interval', + defaultContent: '' + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '', + responsivePriority: 5 + } + ] + }); + } + function draw_app_passwd_table() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#app_passwd_table') ) { + $('#app_passwd_table').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#app_passwd_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/app-passwd/all', + dataSrc: function(data){ + console.log(data); + $.each(data, function (i, item) { + item.name = escapeHtml(item.name) + item.protocols = [] + if (item.imap_access == 1) { item.protocols.push("<code>IMAP</code>"); } + if (item.smtp_access == 1) { item.protocols.push("<code>SMTP</code>"); } + if (item.eas_access == 1) { item.protocols.push("<code>EAS/ActiveSync</code>"); } + if (item.dav_access == 1) { item.protocols.push("<code>DAV</code>"); } + if (item.pop3_access == 1) { item.protocols.push("<code>POP3</code>"); } + if (item.sieve_access == 1) { item.protocols.push("<code>Sieve</code>"); } + item.protocols = item.protocols.join(" ") + if (acl_data.app_passwds === 1) { + item.action = '<div class="btn-group">' + + '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' + + '<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' + + '</div>'; + item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />'; + } + else { + item.action = '<span>-</span>'; + item.chkbox = '<input type="checkbox" disabled />'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'id', + defaultContent: '' + }, + { + title: lang.app_name, + data: 'name', + defaultContent: '' + }, + { + title: lang.allowed_protocols, + data: 'protocols', + defaultContent: '' + }, + { + title: lang.active, + data: 'active', + defaultContent: '', + render: function (data, type) { + return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>' + } + }, + { + title: lang.action, + data: 'action', + className: 'text-md-end dt-sm-head-hidden dt-body-right', + defaultContent: '' + } + ] + }); + } + function draw_wl_policy_mailbox_table() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#wl_policy_mailbox_table') ) { + $('#wl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#wl_policy_mailbox_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/policy_wl_mailbox', + dataSrc: function(data){ + console.log(data); + $.each(data, function (i, item) { + if (validateEmail(item.object)) { + item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />'; + } + else { + item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />'; + } + if (acl_data.spam_policy === 0) { + item.chkbox = '<input type="checkbox" disabled />'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'prefid', + defaultContent: '' + }, + { + title: lang.spamfilter_table_rule, + data: 'value', + defaultContent: '' + }, + { + title:'Scope', + data: 'object', + defaultContent: '' + } + ] + }); + } + function draw_bl_policy_mailbox_table() { + // just recalc width if instance already exists + if ($.fn.DataTable.isDataTable('#bl_policy_mailbox_table') ) { + $('#bl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc(); + return; + } + + $('#bl_policy_mailbox_table').DataTable({ + responsive: true, + processing: true, + serverSide: false, + stateSave: true, + pageLength: pagination_size, + dom: "<'row'<'col-sm-12 col-md-6'f><'col-sm-12 col-md-6'l>>" + + "tr" + + "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>", + language: lang_datatables, + ajax: { + type: "GET", + url: '/api/v1/get/policy_bl_mailbox', + dataSrc: function(data){ + console.log(data); + $.each(data, function (i, item) { + if (validateEmail(item.object)) { + item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />'; + } + else { + item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />'; + } + if (acl_data.spam_policy === 0) { + item.chkbox = '<input type="checkbox" disabled />'; + } + }); + + return data; + } + }, + columns: [ + { + // placeholder, so checkbox will not block child row toggle + title: '', + data: null, + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: '', + data: 'chkbox', + searchable: false, + orderable: false, + defaultContent: '' + }, + { + title: 'ID', + data: 'prefid', + defaultContent: '' + }, + { + title: lang.spamfilter_table_rule, + data: 'value', + defaultContent: '' + }, + { + title:'Scope', + data: 'object', + defaultContent: '' + } + ] + }); + } + + // FIDO2 friendly name modal + $('#fido2ChangeFn').on('show.bs.modal', function (e) { + rename_link = $(e.relatedTarget) + if (rename_link != null) { + $('#fido2_cid').val(rename_link.data('cid')); + $('#fido2_subject_desc').text(Base64.decode(rename_link.data('subject'))); + } + }) + + // Sieve data modal + $('#userFilterModal').on('show.bs.modal', function(e) { + $('#user_sieve_filter').text(lang.loading); + $.ajax({ + dataType: 'json', + url: '/api/v1/get/active-user-sieve/' + encodeURIComponent(mailcow_cc_username), + jsonp: false, + error: function () { + console.log('Cannot get active sieve script'); + }, + complete: function (data) { + if (data.responseText == '{}') { + $('#user_sieve_filter').text(lang.no_active_filter); + } else { + $('#user_sieve_filter').text(JSON.parse(data.responseText)); + } + } + }) + }); + $('#userFilterModal').on('hidden.bs.modal', function () { + $('#user_sieve_filter').text(lang.loading); + }); + + // detect element visibility changes + function onVisible(element, callback) { + $(document).ready(function() { + element_object = document.querySelector(element); + if (element_object === null) return; + + new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if(entry.intersectionRatio > 0) { + callback(element_object); + } + }); + }).observe(element_object); + }); + } + + // Load only if the tab is visible + onVisible("[id^=tla_table]", () => draw_tla_table()); + onVisible("[id^=bl_policy_mailbox_table]", () => draw_bl_policy_mailbox_table()); + onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table()); + onVisible("[id^=sync_job_table]", () => draw_sync_job_table()); + onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table()); + last_logins('get'); +}); diff --git a/data/web/templates/admin.twig b/data/web/templates/admin.twig index 863f87e9..33f2422b 100644 --- a/data/web/templates/admin.twig +++ b/data/web/templates/admin.twig @@ -57,7 +57,7 @@ </div> </div> <!-- /col-md-12 --> </div> <!-- /row --> -</div> +</div> {% include 'modals/admin.twig' %} @@ -66,7 +66,7 @@ var lang = {{ lang_admin|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var admin_username = '{{ mailcow_cc_username }}'; var csrf_token = '{{ csrf_token }}'; -var pagination_size = '{{ pagination_size }}'; -var log_pagination_size = '{{ log_pagination_size }}'; +var pagination_size = Math.trunc('{{ pagination_size }}'); +var log_pagination_size = Math.trunc('{{ log_pagination_size }}'); </script> {% endblock %} diff --git a/data/web/templates/debug.twig b/data/web/templates/debug.twig index 1e011c8b..006703fb 100644 --- a/data/web/templates/debug.twig +++ b/data/web/templates/debug.twig @@ -41,7 +41,7 @@ </div> <div class="col-sm-12 col-md-8"> <div class="table-responsive" style="margin-top: 10px;"> - <table class="table table-striped table-condensed"> + <table class="table table-striped table-condensed w-100"> <tbody> <tr> <td>Hostname</td> @@ -59,7 +59,7 @@ <span class="text">{{ lang.debug.show_ip }}</span> <div class="spinner-border spinner-border-sm d-none" role="status"> <span class="visually-hidden">Loading...</span> - </div> + </div> </button> {% else %} <span class="d-block">{{ lang.admin.ip_check_disabled|raw }}</span> @@ -71,7 +71,7 @@ <td class="text-break"> <div class="fw-bolder"> <p ><a href="#" id="maiclow_version">{{ mailcow_info.version_tag }}</a></p> - <p id="mailcow_update"></p> + <p id="mailcow_update"></p> </div> </td> </tr> @@ -198,10 +198,10 @@ <i class="bi bi-caret-down-fill caret"></i> </button> </div> - {% endif %} + {% endif %} </div> {% if containers["solr-mailcow"].State.Running == 1 %} - <div class="collapse p-0 list-group-details container-details-collapse" id="solr-mailcowCollapse" data-id="{{ containers["solr-mailcow"].Id }}"> + <div class="collapse p-0 list-group-details container-details-collapse" id="solr-mailcowCollapse" data-id="{{ containers["solr-mailcow"].Id }}"> <div class="row p-2 pt-4"> <div class="col-sm-3"> <p><img class="img-responsive" alt="Solr Logo" width="128px" src="data:image/png;base64,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" /></p> @@ -238,10 +238,10 @@ <canvas class="d-none" id="solr-mailcow_NetIOChart" width="400" height="200"></canvas> </div> <div class="col-sm-12 d-flex" style="height: 40px"> - <a href data-bs-toggle="modal" - data-container="solr-mailcow" - data-bs-target="#RestartContainer" - class="btn btn-sm btn-secondary d-flex align-items-center justify-content-center mb-2 ms-auto" + <a href data-bs-toggle="modal" + data-container="solr-mailcow" + data-bs-target="#RestartContainer" + class="btn btn-sm btn-secondary d-flex align-items-center justify-content-center mb-2 ms-auto" style="height: 30px;">{{ lang.debug.restart_container }} <i class="ms-1 bi {% if containers["solr-mailcow"].State.Running == 1 %} @@ -255,7 +255,7 @@ ></i> </a> </div> - </div> + </div> </div> {% endif %} </div> @@ -291,8 +291,8 @@ </button> </div> </div> - <div class="collapse p-0 list-group-details container-details-collapse" id="{{ container }}Collapse" data-id="{{ container_info.Id }}"> - <div class="row p-2 pt-4"> + <div class="collapse p-0 list-group-details container-details-collapse" id="{{ container }}Collapse" data-id="{{ container_info.Id }}"> + <div class="row p-2 pt-4"> <div class="mt-4 col-sm-12 col-md-6 d-flex flex-column"> <h6>Disk I/O</h6> <div class="spinner-border my-4 mx-auto" role="status"> @@ -306,12 +306,12 @@ <span class="visually-hidden">Loading...</span> </div> <canvas class="d-none" id="{{ container }}_NetIOChart" width="400" height="200"></canvas> - </div> - <div class="col-12 d-flex" style="height: 40px"> - <a href data-bs-toggle="modal" - data-container="{{ container }}" - data-bs-target="#RestartContainer" - class="btn btn-sm btn-secondary d-flex align-items-center justify-content-center mb-2 ms-auto" + </div> + <div class="col-12 d-flex" style="height: 40px"> + <a href data-bs-toggle="modal" + data-container="{{ container }}" + data-bs-target="#RestartContainer" + class="btn btn-sm btn-secondary d-flex align-items-center justify-content-center mb-2 ms-auto" style="height: 30px;">{{ lang.debug.restart_container }} <i class="ms-1 bi {% if container_info.State.Running == 1 %} @@ -340,7 +340,7 @@ <div class="debug-log-info">{{ lang.debug.log_info|format(log_lines+1)|raw }}</div> <div class="card"> <div class="card-header d-flex align-items-center fs-5"> - <span class="mt-2 ms-2">Postfix</span> + <span class="mt-2 ms-2">Postfix</span> <div class="btn-group ms-auto"> <button class="btn btn-sm btn-secondary refresh_table" data-draw="draw_postfix_logs" data-table="postfix_log">{{ lang.admin.refresh }}</button> </div> @@ -627,6 +627,6 @@ var lang_debug = {{ lang_debug|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var csrf_token = '{{ csrf_token }}'; - var log_pagination_size = '{{ log_pagination_size }}'; + var log_pagination_size = Math.trunc('{{ log_pagination_size }}'); </script> {% endblock %} diff --git a/data/web/templates/domainadmin.twig b/data/web/templates/domainadmin.twig index 56f5e75f..070bf00c 100644 --- a/data/web/templates/domainadmin.twig +++ b/data/web/templates/domainadmin.twig @@ -46,7 +46,7 @@ <div class="col-sm-3 col-5 text-end">{{ lang.fido2.known_ids }}:</div> <div class="col-sm-9 col-7"> <div class="table-responsive"> - <table class="table table-striped table-hover table-condensed" id="fido2_keys"> + <table class="table table-striped table-hover table-condensed w-100" id="fido2_keys"> <tr> <th>ID</th> <th style="min-width:240px;text-align: right">{{ lang.admin.action }}</th> diff --git a/data/web/templates/edit.twig b/data/web/templates/edit.twig index 29f36435..af83a31d 100644 --- a/data/web/templates/edit.twig +++ b/data/web/templates/edit.twig @@ -26,7 +26,7 @@ var lang_user = {{ lang_user|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var csrf_token = '{{ csrf_token }}'; - var pagination_size = '{{ pagination_size }}'; + var pagination_size = Math.trunc('{{ pagination_size }}'); var table_for_domain = '{{ domain }}'; </script> {% endblock %} diff --git a/data/web/templates/mailbox.twig b/data/web/templates/mailbox.twig index d1044288..1312441c 100644 --- a/data/web/templates/mailbox.twig +++ b/data/web/templates/mailbox.twig @@ -58,7 +58,7 @@ var lang_rl = {{ lang_rl|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var csrf_token = '{{ csrf_token }}'; - var pagination_size = '{{ pagination_size }}'; + var pagination_size = Math.trunc('{{ pagination_size }}'); var role = '{{ role }}'; var is_dual = {{ is_dual }}; var ALLOW_ADMIN_EMAIL_LOGIN = {{ allow_admin_email_login }}; diff --git a/data/web/templates/quarantine.twig b/data/web/templates/quarantine.twig index 5ff7fe66..79b5ea16 100644 --- a/data/web/templates/quarantine.twig +++ b/data/web/templates/quarantine.twig @@ -37,7 +37,7 @@ </p> {% endif %} </p> - <table id="quarantinetable" class="table table-striped"></table> + <table id="quarantinetable" class="table table-striped w-100"></table> <div class="mass-actions-quarantine mt-4"> <div class="btn-group" data-acl="{{ acl.quarantine }}"> <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="qitems" href="#"><i class="bi bi-check-all"></i> {{ lang.quarantine.toggle_all }}</a> @@ -66,7 +66,7 @@ var acl = '{{ acl_json|raw }}'; var lang = {{ lang_quarantine|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var csrf_token = '{{ csrf_token }}'; -var pagination_size = '{{ pagination_size }}'; +var pagination_size = Math.trunc('{{ pagination_size }}'); var role = '{{ role }}'; </script> {% endblock %} diff --git a/data/web/templates/queue.twig b/data/web/templates/queue.twig index 1a5d4ff9..e843c18e 100644 --- a/data/web/templates/queue.twig +++ b/data/web/templates/queue.twig @@ -55,7 +55,7 @@ var lang = {{ lang_queue|raw }}; var lang_datatables = {{ lang_datatables|raw }}; var csrf_token = '{{ csrf_token }}'; - var pagination_size = '{{ pagination_size }}'; + var pagination_size = Math.trunc('{{ pagination_size }}'); var table_for_domain = '{{ domain }}'; </script> {% endblock %} diff --git a/data/web/templates/user_domainadmin_common.twig b/data/web/templates/user_domainadmin_common.twig index 8a7ace39..64a2205d 100644 --- a/data/web/templates/user_domainadmin_common.twig +++ b/data/web/templates/user_domainadmin_common.twig @@ -4,7 +4,7 @@ var acl = '{{ acl_json|raw }}'; var lang = {{ lang_user|raw }}; var csrf_token = '{{ csrf_token }}'; - var pagination_size = '{{ pagination_size }}'; + var pagination_size = Math.trunc('{{ pagination_size }}'); var mailcow_cc_username = '{{ mailcow_cc_username }}'; var user_spam_score = [{{ user_spam_score }}]; var lang_datatables = {{ lang_datatables|raw }};