mailbox.js 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  1. $(document).ready(function() {
  2. acl_data = JSON.parse(acl);
  3. // Set paging
  4. // Clone mailbox mass actions
  5. $("div").find("[data-actions-header='true'").each(function() {
  6. $(this).html($(this).nextAll('.mass-actions-mailbox:first').html());
  7. });
  8. // Auto-fill domain quota when adding new domain
  9. auto_fill_quota = function(domain) {
  10. $.get("/api/v1/get/domain/" + domain, function(data){
  11. var result = $.parseJSON(JSON.stringify(data));
  12. def_new_mailbox_quota = ( result.def_new_mailbox_quota / 1048576);
  13. max_new_mailbox_quota = ( result.max_new_mailbox_quota / 1048576);
  14. if (max_new_mailbox_quota != '0') {
  15. $('.addInputQuotaExhausted').hide();
  16. $("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
  17. $('#addInputQuota').attr({"disabled": false, "value": "", "type": "number", "max": max_new_mailbox_quota});
  18. $('#addInputQuota').val(def_new_mailbox_quota);
  19. }
  20. else {
  21. $('.addInputQuotaExhausted').show();
  22. $("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
  23. $('#addInputQuota').attr({"disabled": true, "value": "", "type": "text", "value": "n/a"});
  24. $('#addInputQuota').val(max_new_mailbox_quota);
  25. }
  26. });
  27. }
  28. $('#addSelectDomain').on('change', function() {
  29. auto_fill_quota($('#addSelectDomain').val());
  30. });
  31. auto_fill_quota($('#addSelectDomain').val());
  32. $(".goto_checkbox").click(function( event ) {
  33. $("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
  34. if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
  35. $('#textarea_alias_goto').prop('disabled', true);
  36. }
  37. else {
  38. $("#textarea_alias_goto").removeAttr('disabled');
  39. }
  40. });
  41. $('#addAliasModal').on('show.bs.modal', function(e) {
  42. if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
  43. $('#textarea_alias_goto').prop('disabled', true);
  44. }
  45. else {
  46. $("#textarea_alias_goto").removeAttr('disabled');
  47. }
  48. });
  49. // Log modal
  50. $('#syncjobLogModal').on('show.bs.modal', function(e) {
  51. var syncjob_id = $(e.relatedTarget).data('syncjob-id');
  52. $.ajax({
  53. url: '/inc/ajax/syncjob_logs.php',
  54. data: { id: syncjob_id },
  55. dataType: 'text',
  56. success: function(data){
  57. $(e.currentTarget).find('#logText').text(data);
  58. },
  59. error: function(xhr, status, error) {
  60. $(e.currentTarget).find('#logText').text(xhr.responseText);
  61. }
  62. });
  63. });
  64. // Log modal
  65. $('#dnsInfoModal').on('show.bs.modal', function(e) {
  66. var domain = $(e.relatedTarget).data('domain');
  67. $('.dns-modal-body').html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>');
  68. $.ajax({
  69. url: '/inc/ajax/dns_diagnostics.php',
  70. data: { domain: domain },
  71. dataType: 'text',
  72. success: function(data){
  73. $('.dns-modal-body').html(data);
  74. },
  75. error: function(xhr, status, error) {
  76. $('.dns-modal-body').html(xhr.responseText);
  77. }
  78. });
  79. });
  80. // Sieve data modal
  81. $('#sieveDataModal').on('show.bs.modal', function(e) {
  82. var sieveScript = $(e.relatedTarget).data('sieve-script');
  83. $(e.currentTarget).find('#sieveDataText').html('<pre style="font-size:14px;line-height:1.1">' + sieveScript + '</pre>');
  84. });
  85. // Disable submit button on script change
  86. $('.textarea-code').on('keyup', function() {
  87. // Disable all "save" buttons, could be a "related button only" function, todo
  88. $('.add_sieve_script').attr({"disabled": true});
  89. });
  90. // Validate script data
  91. $(".validate_sieve").click(function( event ) {
  92. event.preventDefault();
  93. var validation_button = $(this);
  94. // Get script_data textarea content from form the button was clicked in
  95. var script = $('textarea[name="script_data"]', $(this).parents('form:first')).val();
  96. $.ajax({
  97. dataType: 'json',
  98. url: "/inc/ajax/sieve_validation.php",
  99. type: "get",
  100. data: { script: script },
  101. complete: function(data) {
  102. var response = (data.responseText);
  103. response_obj = JSON.parse(response);
  104. if (response_obj.type == "success") {
  105. $(validation_button).next().attr({"disabled": false});
  106. }
  107. mailcow_alert_box(response_obj.msg, response_obj.type);
  108. },
  109. });
  110. });
  111. // $(document).on('DOMNodeInserted', '#prefilter_table', function () {
  112. // $("#active-script").closest('td').css('background-color','#b0f0a0');
  113. // $("#inactive-script").closest('td').css('background-color','#b0f0a0');
  114. // });
  115. $('#addResourceModal').on('shown.bs.modal', function() {
  116. $("#multiple_bookings").val($("#multiple_bookings_select").val());
  117. if ($("#multiple_bookings").val() == "custom") {
  118. $("#multiple_bookings_custom_div").show();
  119. $("#multiple_bookings").val($("#multiple_bookings_custom").val());
  120. }
  121. })
  122. $("#multiple_bookings_select").change(function() {
  123. $("#multiple_bookings").val($("#multiple_bookings_select").val());
  124. if ($("#multiple_bookings").val() == "custom") {
  125. $("#multiple_bookings_custom_div").show();
  126. }
  127. else {
  128. $("#multiple_bookings_custom_div").hide();
  129. }
  130. });
  131. $("#multiple_bookings_custom").bind ("change keypress keyup blur", function () {
  132. $("#multiple_bookings").val($("#multiple_bookings_custom").val());
  133. });
  134. });
  135. jQuery(function($){
  136. // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
  137. 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]}
  138. 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"})}
  139. $(".refresh_table").on('click', function(e) {
  140. e.preventDefault();
  141. var table_name = $(this).data('table');
  142. if ($.fn.DataTable.isDataTable('#' + table_name))
  143. $('#' + table_name).DataTable().ajax.reload();
  144. });
  145. function draw_domain_table() {
  146. // just recalc width if instance already exists
  147. if ($.fn.DataTable.isDataTable('#domain_table') ) {
  148. $('#domain_table').DataTable().columns.adjust().responsive.recalc();
  149. return;
  150. }
  151. var table = $('#domain_table').DataTable({
  152. processing: true,
  153. serverSide: false,
  154. language: lang_datatables,
  155. ajax: {
  156. type: "GET",
  157. url: "/api/v1/get/domain/all",
  158. dataSrc: function(json){
  159. $.each(json, function(i, item) {
  160. item.aliases = item.aliases_in_domain + " / " + item.max_num_aliases_for_domain;
  161. item.mailboxes = item.mboxes_in_domain + " / " + item.max_num_mboxes_for_domain;
  162. item.quota = item.quota_used_in_domain + "/" + item.max_quota_for_domain + "/" + item.bytes_total;
  163. item.stats = item.msgs_total + "/" + item.bytes_total;
  164. if (!item.rl) item.rl = '∞';
  165. else {
  166. item.rl = $.map(item.rl, function(e){
  167. return e;
  168. }).join('/1');
  169. }
  170. item.def_quota_for_mbox = humanFileSize(item.def_quota_for_mbox);
  171. item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
  172. item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
  173. item.action = '<div class="btn-group">';
  174. if (role == "admin") {
  175. item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  176. '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  177. '<a href="#dnsInfoModal" class="btn btn-sm btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
  178. }
  179. else {
  180. item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  181. '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
  182. }
  183. if (Array.isArray(item.tags)){
  184. var tags = '';
  185. for (var i = 0; i < item.tags.length; i++)
  186. tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
  187. item.tags = tags;
  188. } else {
  189. item.tags = '';
  190. }
  191. if (item.backupmx == 1) {
  192. if (item.relay_unknown_only == 1) {
  193. item.domain_name = '<div class="badge fs-6 bg-info">Relay Non-Local</div> ' + item.domain_name;
  194. } else if (item.relay_all_recipients == 1) {
  195. item.domain_name = '<div class="badge fs-6 bg-info">Relay All</div> ' + item.domain_name;
  196. } else {
  197. item.domain_name = '<div class="badge fs-6 bg-info">Relay</div> ' + item.domain_name;
  198. }
  199. }
  200. });
  201. return json;
  202. }
  203. },
  204. columns: [
  205. {
  206. // placeholder, so checkbox will not block child row toggle
  207. title: '',
  208. data: null,
  209. searchable: false,
  210. orderable: false,
  211. defaultContent: '',
  212. responsivePriority: 1
  213. },
  214. {
  215. title: '',
  216. data: 'chkbox',
  217. searchable: false,
  218. orderable: false,
  219. defaultContent: '',
  220. responsivePriority: 2
  221. },
  222. {
  223. title: lang.domain,
  224. data: 'domain_name',
  225. responsivePriority: 3,
  226. defaultContent: ''
  227. },
  228. {
  229. title: lang.aliases,
  230. data: 'aliases',
  231. defaultContent: ''
  232. },
  233. {
  234. title: lang.mailboxes,
  235. data: 'mailboxes',
  236. responsivePriority: 4,
  237. defaultContent: ''
  238. },
  239. {
  240. title: lang.domain_quota,
  241. data: 'quota',
  242. defaultContent: '',
  243. render: function (data, type) {
  244. data = data.split("/");
  245. return humanFileSize(data[0]) + " / " + humanFileSize(data[1]);
  246. }
  247. },
  248. {
  249. title: lang.stats,
  250. data: 'stats',
  251. defaultContent: '',
  252. render: function (data, type) {
  253. data = data.split("/");
  254. return '<i class="bi bi-files"></i> ' + data[0] + ' / ' + humanFileSize(data[1]);
  255. }
  256. },
  257. {
  258. title: lang.mailbox_defquota,
  259. data: 'def_quota_for_mbox',
  260. defaultContent: ''
  261. },
  262. {
  263. title: lang.mailbox_quota,
  264. data: 'max_quota_for_mbox',
  265. defaultContent: ''
  266. },
  267. {
  268. title: 'RL',
  269. data: 'rl',
  270. defaultContent: ''
  271. },
  272. {
  273. title: lang.backup_mx,
  274. data: 'backupmx',
  275. defaultContent: '',
  276. redner: function (data, type){
  277. return 1==value ? '<i class="bi bi-check-lg"></i>' : 0==value && '<i class="bi bi-x-lg"></i>';
  278. }
  279. },
  280. {
  281. title: lang.domain_admins,
  282. data: 'domain_admins',
  283. defaultContent: '',
  284. className: 'none'
  285. },
  286. {
  287. title: 'Tags',
  288. data: 'tags',
  289. defaultContent: '',
  290. className: 'none'
  291. },
  292. {
  293. title: lang.active,
  294. data: 'active',
  295. defaultContent: '',
  296. responsivePriority: 6,
  297. render: function (data, type) {
  298. return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'&#8212;');
  299. }
  300. },
  301. {
  302. title: lang.action,
  303. data: 'action',
  304. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
  305. responsivePriority: 5,
  306. defaultContent: ''
  307. },
  308. ]
  309. });
  310. }
  311. function draw_mailbox_table() {
  312. // just recalc width if instance already exists
  313. if ($.fn.DataTable.isDataTable('#mailbox_table') ) {
  314. $('#mailbox_table').DataTable().columns.adjust().responsive.recalc();
  315. return;
  316. }
  317. $('#mailbox_table').DataTable({
  318. responsive : true,
  319. processing: true,
  320. serverSide: false,
  321. language: lang_datatables,
  322. ajax: {
  323. type: "GET",
  324. url: "/api/v1/get/mailbox/reduced",
  325. dataSrc: function(json){
  326. $.each(json, function (i, item) {
  327. item.quota = item.quota_used + "/" + item.quota;
  328. item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
  329. item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login;
  330. /*
  331. if (!item.rl) {
  332. item.rl = '∞';
  333. } else {
  334. item.rl = $.map(item.rl, function(e){
  335. return e;
  336. }).join('/1');
  337. if (item.rl_scope === 'domain') {
  338. item.rl = '<i class="bi bi-arrow-return-right"></i> ' + item.rl + ' (via ' + item.domain + ')';
  339. }
  340. }
  341. */
  342. item.chkbox = '<input type="checkbox" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
  343. if (item.attributes.passwd_update != '0') {
  344. var last_pw_change = new Date(item.attributes.passwd_update.replace(/-/g, "/"));
  345. item.last_pw_change = last_pw_change.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
  346. } else {
  347. item.last_pw_change = '-';
  348. }
  349. item.tls_enforce_in = '<i class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
  350. item.tls_enforce_out = '<i class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
  351. item.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
  352. item.imap_access = '<i class="text-' + (item.attributes.imap_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.imap_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
  353. item.smtp_access = '<i class="text-' + (item.attributes.smtp_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.smtp_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
  354. item.sieve_access = '<i class="text-' + (item.attributes.sieve_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sieve_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
  355. if (item.attributes.quarantine_notification === 'never') {
  356. item.quarantine_notification = lang.never;
  357. } else if (item.attributes.quarantine_notification === 'hourly') {
  358. item.quarantine_notification = lang.hourly;
  359. } else if (item.attributes.quarantine_notification === 'daily') {
  360. item.quarantine_notification = lang.daily;
  361. } else if (item.attributes.quarantine_notification === 'weekly') {
  362. item.quarantine_notification = lang.weekly;
  363. }
  364. if (item.attributes.quarantine_category === 'reject') {
  365. item.quarantine_category = '<span class="text-danger">' + lang.q_reject + '</span>';
  366. } else if (item.attributes.quarantine_category === 'add_header') {
  367. item.quarantine_category = '<span class="text-warning">' + lang.q_add_header + '</span>';
  368. } else if (item.attributes.quarantine_category === 'all') {
  369. item.quarantine_category = lang.q_all;
  370. }
  371. if (acl_data.login_as === 1) {
  372. item.action = '<div class="btn-group">' +
  373. '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  374. '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  375. '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-success"><i class="bi bi-person-fill"></i> Login</a>';
  376. if (ALLOW_ADMIN_EMAIL_LOGIN) {
  377. item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
  378. }
  379. item.action += '</div>';
  380. }
  381. else {
  382. item.action = '<div class="btn-group">' +
  383. '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  384. '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  385. '</div>';
  386. }
  387. item.in_use = '<div class="progress">' +
  388. '<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" ' +
  389. 'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
  390. item.username = escapeHtml(item.username);
  391. if (Array.isArray(item.tags)){
  392. var tags = '';
  393. for (var i = 0; i < item.tags.length; i++)
  394. tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
  395. item.tags = tags;
  396. } else {
  397. item.tags = '';
  398. }
  399. });
  400. return json;
  401. }
  402. },
  403. columns: [
  404. {
  405. // placeholder, so checkbox will not block child row toggle
  406. title: '',
  407. data: null,
  408. searchable: false,
  409. orderable: false,
  410. defaultContent: '',
  411. responsivePriority: 1
  412. },
  413. {
  414. title: '',
  415. data: 'chkbox',
  416. searchable: false,
  417. orderable: false,
  418. defaultContent: '',
  419. responsivePriority: 2
  420. },
  421. {
  422. title: lang.username,
  423. data: 'username',
  424. responsivePriority: 3,
  425. defaultContent: ''
  426. },
  427. {
  428. title: lang.domain_quota,
  429. data: 'quota',
  430. responsivePriority: 8,
  431. defaultContent: '',
  432. render: function (data, type) {
  433. data = data.split("/");
  434. var of_q = (data[1] == 0 ? "∞" : humanFileSize(data[1]));
  435. return humanFileSize(data[0]) + " / " + of_q;
  436. }
  437. },
  438. {
  439. title: lang.last_mail_login,
  440. data: 'last_mail_login',
  441. defaultContent: '',
  442. responsivePriority: 7,
  443. render: function (data, type) {
  444. res = data.split("/");
  445. return '<div class="badge bg-info mb-2">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' +
  446. '<div class="badge bg-info mb-2">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
  447. '<div class="badge bg-info">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>';
  448. }
  449. },
  450. {
  451. title: lang.last_pw_change,
  452. data: 'last_pw_change',
  453. defaultContent: ''
  454. },
  455. {
  456. title: lang.in_use,
  457. data: 'in_use',
  458. defaultContent: '',
  459. responsivePriority: 9,
  460. className: 'dt-data-w100'
  461. },
  462. {
  463. title: lang.fname,
  464. data: 'name',
  465. defaultContent: '',
  466. className: 'none'
  467. },
  468. {
  469. title: lang.domain,
  470. data: 'domain',
  471. defaultContent: '',
  472. className: 'none'
  473. },
  474. {
  475. title: lang.tls_enforce_in,
  476. data: 'tls_enforce_in',
  477. defaultContent: '',
  478. className: 'none'
  479. },
  480. {
  481. title: lang.tls_enforce_out,
  482. data: 'tls_enforce_out',
  483. defaultContent: '',
  484. className: 'none'
  485. },
  486. {
  487. title: 'SMTP',
  488. data: 'smtp_access',
  489. defaultContent: '',
  490. className: 'none'
  491. },
  492. {
  493. title: 'IMAP',
  494. data: 'imap_access',
  495. defaultContent: '',
  496. className: 'none'
  497. },
  498. {
  499. title: 'POP3',
  500. data: 'pop3_access',
  501. defaultContent: '',
  502. className: 'none'
  503. },
  504. {
  505. title: 'SIEVE',
  506. data: 'sieve_access',
  507. defaultContent: '',
  508. className: 'none'
  509. },
  510. {
  511. title: lang.quarantine_notification,
  512. data: 'quarantine_notification',
  513. defaultContent: '',
  514. className: 'none'
  515. },
  516. {
  517. title: lang.quarantine_category,
  518. data: 'quarantine_category',
  519. defaultContent: '',
  520. className: 'none'
  521. },
  522. {
  523. title: lang.msg_num,
  524. data: 'messages',
  525. defaultContent: '',
  526. responsivePriority: 5
  527. },
  528. {
  529. title: 'Tags',
  530. data: 'tags',
  531. defaultContent: '',
  532. className: 'none'
  533. },
  534. {
  535. title: lang.active,
  536. data: 'active',
  537. defaultContent: '',
  538. responsivePriority: 4,
  539. render: function (data, type) {
  540. return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'&#8212;');
  541. }
  542. },
  543. {
  544. title: lang.action,
  545. data: 'action',
  546. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
  547. responsivePriority: 6,
  548. defaultContent: ''
  549. },
  550. ]
  551. });
  552. }
  553. function draw_resource_table() {
  554. // just recalc width if instance already exists
  555. if ($.fn.DataTable.isDataTable('#resource_table') ) {
  556. $('#resource_table').DataTable().columns.adjust().responsive.recalc();
  557. return;
  558. }
  559. $('#resource_table').DataTable({
  560. processing: true,
  561. serverSide: false,
  562. language: lang_datatables,
  563. ajax: {
  564. type: "GET",
  565. url: "/api/v1/get/resource/all",
  566. dataSrc: function(json){
  567. $.each(json, function (i, item) {
  568. if (item.multiple_bookings == '0') {
  569. item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-success">' + lang.booking_0_short + '</span>';
  570. } else if (item.multiple_bookings == '-1') {
  571. item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-warning">' + lang.booking_lt0_short + '</span>';
  572. } else {
  573. item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
  574. }
  575. item.action = '<div class="btn-group">' +
  576. '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  577. '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  578. '</div>';
  579. item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
  580. item.name = escapeHtml(item.name);
  581. item.description = escapeHtml(item.description);
  582. });
  583. return json;
  584. }
  585. },
  586. columns: [
  587. {
  588. // placeholder, so checkbox will not block child row toggle
  589. title: '',
  590. data: null,
  591. searchable: false,
  592. orderable: false,
  593. defaultContent: '',
  594. responsivePriority: 1
  595. },
  596. {
  597. title: '',
  598. data: 'chkbox',
  599. searchable: false,
  600. orderable: false,
  601. defaultContent: '',
  602. responsivePriority: 2
  603. },
  604. {
  605. title: lang.description,
  606. data: 'description',
  607. responsivePriority: 3,
  608. defaultContent: ''
  609. },
  610. {
  611. title: lang.alias,
  612. data: 'name',
  613. defaultContent: ''
  614. },
  615. {
  616. title: lang.kind,
  617. data: 'kind',
  618. defaultContent: ''
  619. },
  620. {
  621. title: lang.domain,
  622. data: 'domain',
  623. responsivePriority: 4,
  624. defaultContent: ''
  625. },
  626. {
  627. title: lang.multiple_bookings,
  628. data: 'multiple_bookings',
  629. defaultContent: ''
  630. },
  631. {
  632. title: lang.active,
  633. data: 'active',
  634. defaultContent: '',
  635. render: function (data, type) {
  636. return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'&#8212;');
  637. }
  638. },
  639. {
  640. title: lang.action,
  641. data: 'action',
  642. responsivePriority: 5,
  643. defaultContent: '',
  644. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right'
  645. },
  646. ]
  647. });
  648. }
  649. function draw_bcc_table() {
  650. $.get("/api/v1/get/bcc-destination-options", function(data){
  651. // Domains
  652. var optgroup = "<optgroup label='" + lang.domains + "'>";
  653. $.each(data.domains, function(index, domain){
  654. optgroup += "<option value='" + domain + "'>" + domain + "</option>"
  655. });
  656. optgroup += "</optgroup>"
  657. $('#bcc-local-dest').append(optgroup);
  658. // Alias domains
  659. var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
  660. $.each(data.alias_domains, function(index, alias_domain){
  661. optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
  662. });
  663. optgroup += "</optgroup>"
  664. $('#bcc-local-dest').append(optgroup);
  665. // Mailboxes and aliases
  666. $.each(data.mailboxes, function(mailbox, aliases){
  667. var optgroup = "<optgroup label='" + mailbox + "'>";
  668. $.each(aliases, function(index, alias){
  669. optgroup += "<option value='" + alias + "'>" + alias + "</option>"
  670. });
  671. optgroup += "</optgroup>"
  672. $('#bcc-local-dest').append(optgroup);
  673. });
  674. // Finish
  675. $('#bcc-local-dest').selectpicker('refresh');
  676. });
  677. // just recalc width if instance already exists
  678. if ($.fn.DataTable.isDataTable('#bcc_table') ) {
  679. $('#bcc_table').DataTable().columns.adjust().responsive.recalc();
  680. return;
  681. }
  682. $('#bcc_table').DataTable({
  683. processing: true,
  684. serverSide: false,
  685. language: lang_datatables,
  686. ajax: {
  687. type: "GET",
  688. url: "/api/v1/get/bcc/all",
  689. dataSrc: function(json){
  690. $.each(json, function (i, item) {
  691. item.action = '<div class="btn-group">' +
  692. '<a href="/edit/bcc/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  693. '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  694. '</div>';
  695. item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
  696. item.local_dest = escapeHtml(item.local_dest);
  697. item.bcc_dest = escapeHtml(item.bcc_dest);
  698. if (item.type == 'sender') {
  699. item.type = '<span id="active-script" class="badge fs-6 bg-success">' + lang.bcc_sender_map + '</span>';
  700. } else {
  701. item.type = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.bcc_rcpt_map + '</span>';
  702. }
  703. });
  704. return json;
  705. }
  706. },
  707. columns: [
  708. {
  709. // placeholder, so checkbox will not block child row toggle
  710. title: '',
  711. data: null,
  712. searchable: false,
  713. orderable: false,
  714. defaultContent: '',
  715. responsivePriority: 1
  716. },
  717. {
  718. title: '',
  719. data: 'chkbox',
  720. searchable: false,
  721. orderable: false,
  722. defaultContent: '',
  723. responsivePriority: 2
  724. },
  725. {
  726. title: 'ID',
  727. data: 'id',
  728. responsivePriority: 3,
  729. defaultContent: ''
  730. },
  731. {
  732. title: lang.bcc_type,
  733. data: 'type',
  734. defaultContent: ''
  735. },
  736. {
  737. title: lang.bcc_local_dest,
  738. data: 'local_dest',
  739. defaultContent: ''
  740. },
  741. {
  742. title: lang.bcc_destinations,
  743. data: 'bcc_dest',
  744. defaultContent: ''
  745. },
  746. {
  747. title: lang.domain,
  748. data: 'domain',
  749. responsivePriority: 4,
  750. defaultContent: ''
  751. },
  752. {
  753. title: lang.active,
  754. data: 'active',
  755. defaultContent: '',
  756. render: function (data, type) {
  757. return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'&#8212;');
  758. }
  759. },
  760. {
  761. title: lang.action,
  762. data: 'action',
  763. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  764. responsivePriority: 5,
  765. defaultContent: ''
  766. },
  767. ]
  768. });
  769. }
  770. function draw_recipient_map_table() {
  771. // just recalc width if instance already exists
  772. if ($.fn.DataTable.isDataTable('#recipient_map_table') ) {
  773. $('#recipient_map_table').DataTable().columns.adjust().responsive.recalc();
  774. return;
  775. }
  776. $('#recipient_map_table').DataTable({
  777. processing: true,
  778. serverSide: false,
  779. language: lang_datatables,
  780. ajax: {
  781. type: "GET",
  782. url: "/api/v1/get/recipient_map/all",
  783. dataSrc: function(json){
  784. if (role !== "admin") return null;
  785. $.each(json, function (i, item) {
  786. item.recipient_map_old = escapeHtml(item.recipient_map_old);
  787. item.recipient_map_new = escapeHtml(item.recipient_map_new);
  788. item.action = '<div class="btn-group">' +
  789. '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  790. '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  791. '</div>';
  792. item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
  793. });
  794. return json;
  795. }
  796. },
  797. columns: [
  798. {
  799. // placeholder, so checkbox will not block child row toggle
  800. title: '',
  801. data: null,
  802. searchable: false,
  803. orderable: false,
  804. defaultContent: '',
  805. responsivePriority: 1
  806. },
  807. {
  808. title: '',
  809. data: 'chkbox',
  810. searchable: false,
  811. orderable: false,
  812. defaultContent: '',
  813. responsivePriority: 2
  814. },
  815. {
  816. title: 'ID',
  817. data: 'id',
  818. responsivePriority: 3,
  819. defaultContent: ''
  820. },
  821. {
  822. title: lang.recipient_map_old,
  823. data: 'recipient_map_old',
  824. defaultContent: ''
  825. },
  826. {
  827. title: lang.recipient_map_new,
  828. data: 'recipient_map_new',
  829. defaultContent: '',
  830. responsivePriority: 4
  831. },
  832. {
  833. title: lang.active,
  834. data: 'active',
  835. defaultContent: '',
  836. render: function (data, type) {
  837. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  838. }
  839. },
  840. {
  841. title: lang.action,
  842. data: 'action',
  843. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  844. responsivePriority: 5,
  845. defaultContent: ''
  846. },
  847. ]
  848. });
  849. }
  850. function draw_tls_policy_table() {
  851. // just recalc width if instance already exists
  852. if ($.fn.DataTable.isDataTable('#tls_policy_table') ) {
  853. $('#tls_policy_table').DataTable().columns.adjust().responsive.recalc();
  854. return;
  855. }
  856. $('#tls_policy_table').DataTable({
  857. processing: true,
  858. serverSide: false,
  859. language: lang_datatables,
  860. ajax: {
  861. type: "GET",
  862. url: "/api/v1/get/tls-policy-map/all",
  863. dataSrc: function(json){
  864. console.log(json);
  865. if (role !== "admin") return null;
  866. $.each(json, function (i, item) {
  867. item.dest = escapeHtml(item.dest);
  868. item.policy = '<b>' + escapeHtml(item.policy) + '</b>';
  869. if (item.parameters == '') {
  870. item.parameters = '<code>-</code>';
  871. } else {
  872. item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
  873. }
  874. item.action = '<div class="btn-group">' +
  875. '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  876. '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  877. '</div>';
  878. item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
  879. });
  880. return json;
  881. }
  882. },
  883. columns: [
  884. {
  885. // placeholder, so checkbox will not block child row toggle
  886. title: '',
  887. data: null,
  888. searchable: false,
  889. orderable: false,
  890. defaultContent: '',
  891. responsivePriority: 1
  892. },
  893. {
  894. title: '',
  895. data: 'chkbox',
  896. searchable: false,
  897. orderable: false,
  898. defaultContent: '',
  899. responsivePriority: 2
  900. },
  901. {
  902. title: 'ID',
  903. data: 'id',
  904. responsivePriority: 3,
  905. defaultContent: ''
  906. },
  907. {
  908. title: lang.tls_map_dest,
  909. data: 'dest',
  910. defaultContent: '',
  911. responsivePriority: 4
  912. },
  913. {
  914. title: lang.tls_map_policy,
  915. data: 'policy',
  916. defaultContent: ''
  917. },
  918. {
  919. title: lang.tls_map_parameters,
  920. data: 'parameters',
  921. defaultContent: ''
  922. },
  923. {
  924. title: lang.active,
  925. data: 'active',
  926. defaultContent: '',
  927. render: function (data, type) {
  928. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  929. }
  930. },
  931. {
  932. title: lang.action,
  933. data: 'action',
  934. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  935. responsivePriority: 5,
  936. defaultContent: ''
  937. },
  938. ]
  939. });
  940. }
  941. function draw_alias_table() {
  942. // just recalc width if instance already exists
  943. if ($.fn.DataTable.isDataTable('#alias_table') ) {
  944. $('#alias_table').DataTable().columns.adjust().responsive.recalc();
  945. return;
  946. }
  947. $('#alias_table').DataTable({
  948. processing: true,
  949. serverSide: false,
  950. language: lang_datatables,
  951. ajax: {
  952. type: "GET",
  953. url: "/api/v1/get/alias/all",
  954. dataSrc: function(json){
  955. $.each(json, function (i, item) {
  956. item.action = '<div class="btn-group">' +
  957. '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  958. '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  959. '</div>';
  960. item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
  961. item.goto = escapeHtml(item.goto.replace(/,/g, " "));
  962. if (item.public_comment !== null) {
  963. item.public_comment = escapeHtml(item.public_comment);
  964. }
  965. else {
  966. item.public_comment = '-';
  967. }
  968. if (item.private_comment !== null) {
  969. item.private_comment = escapeHtml(item.private_comment);
  970. }
  971. else {
  972. item.private_comment = '-';
  973. }
  974. if (item.is_catch_all == 1) {
  975. item.address = '<div class="badge fs-6 bg-secondary">' + lang.catch_all + '</div> ' + escapeHtml(item.address);
  976. }
  977. else {
  978. item.address = escapeHtml(item.address);
  979. }
  980. if (item.goto == "null@localhost") {
  981. item.goto = '⤷ <i class="bi bi-trash" style="font-size:12px"></i>';
  982. }
  983. else if (item.goto == "spam@localhost") {
  984. item.goto = '<span class="badge fs-6 bg-danger">' + lang.goto_spam + '</span>';
  985. }
  986. else if (item.goto == "ham@localhost") {
  987. item.goto = '<span class="badge fs-6 bg-success">' + lang.goto_ham + '</span>';
  988. }
  989. if (item.in_primary_domain !== "") {
  990. item.domain = '<i data-domainname="' + item.domain + '" class="bi bi-info-circle-fill alias-domain-info text-info" data-bs-toggle="tooltip" title="' + lang.target_domain + ': ' + item.in_primary_domain + '"></i> ' + item.domain;
  991. }
  992. });
  993. return json;
  994. }
  995. },
  996. columns: [
  997. {
  998. // placeholder, so checkbox will not block child row toggle
  999. title: '',
  1000. data: null,
  1001. searchable: false,
  1002. orderable: false,
  1003. defaultContent: '',
  1004. responsivePriority: 1
  1005. },
  1006. {
  1007. title: '',
  1008. data: 'chkbox',
  1009. searchable: false,
  1010. orderable: false,
  1011. defaultContent: '',
  1012. responsivePriority: 2
  1013. },
  1014. {
  1015. title: 'ID',
  1016. data: 'id',
  1017. responsivePriority: 3,
  1018. defaultContent: ''
  1019. },
  1020. {
  1021. title: lang.alias,
  1022. data: 'address',
  1023. responsivePriority: 4,
  1024. defaultContent: ''
  1025. },
  1026. {
  1027. title: lang.target_address,
  1028. data: 'goto',
  1029. defaultContent: ''
  1030. },
  1031. {
  1032. title: lang.domain,
  1033. data: 'domain',
  1034. defaultContent: '',
  1035. responsivePriority: 5,
  1036. },
  1037. {
  1038. title: lang.bcc_destinations,
  1039. data: 'bcc_dest',
  1040. defaultContent: ''
  1041. },
  1042. {
  1043. title: lang.sogo_visible,
  1044. data: 'sogo_visible',
  1045. defaultContent: '',
  1046. render: function(data, type){
  1047. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  1048. }
  1049. },
  1050. {
  1051. title: lang.public_comment,
  1052. data: 'public_comment',
  1053. defaultContent: ''
  1054. },
  1055. {
  1056. title: lang.private_comment,
  1057. data: 'private_comment',
  1058. defaultContent: ''
  1059. },
  1060. {
  1061. title: lang.active,
  1062. data: 'active',
  1063. defaultContent: '',
  1064. responsivePriority: 6,
  1065. render: function (data, type) {
  1066. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  1067. }
  1068. },
  1069. {
  1070. title: lang.action,
  1071. data: 'action',
  1072. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  1073. responsivePriority: 5,
  1074. defaultContent: ''
  1075. },
  1076. ]
  1077. });
  1078. }
  1079. function draw_aliasdomain_table() {
  1080. // just recalc width if instance already exists
  1081. if ($.fn.DataTable.isDataTable('#aliasdomain_table') ) {
  1082. $('#aliasdomain_table').DataTable().columns.adjust().responsive.recalc();
  1083. return;
  1084. }
  1085. $('#aliasdomain_table').DataTable({
  1086. processing: true,
  1087. serverSide: false,
  1088. language: lang_datatables,
  1089. ajax: {
  1090. type: "GET",
  1091. url: "/api/v1/get/alias-domain/all",
  1092. dataSrc: function(json){
  1093. $.each(json, function (i, item) {
  1094. item.action = '<div class="btn-group">' +
  1095. '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  1096. '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  1097. '<a href="#dnsInfoModal" class="btn btn-sm btn-xs-third btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
  1098. '</div>';
  1099. item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
  1100. if(item.parent_is_backupmx == '1') {
  1101. item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a> <div class="badge fs-6 bg-warning">' + lang.alias_domain_backupmx + '</div></span>';
  1102. } else {
  1103. item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a></span>';
  1104. }
  1105. });
  1106. return json;
  1107. }
  1108. },
  1109. columns: [
  1110. {
  1111. // placeholder, so checkbox will not block child row toggle
  1112. title: '',
  1113. data: null,
  1114. searchable: false,
  1115. orderable: false,
  1116. defaultContent: '',
  1117. responsivePriority: 1
  1118. },
  1119. {
  1120. title: '',
  1121. data: 'chkbox',
  1122. searchable: false,
  1123. orderable: false,
  1124. defaultContent: '',
  1125. responsivePriority: 2
  1126. },
  1127. {
  1128. title: lang.alias,
  1129. data: 'alias_domain',
  1130. responsivePriority: 3,
  1131. defaultContent: ''
  1132. },
  1133. {
  1134. title: lang.target_domain,
  1135. data: 'target_domain',
  1136. responsivePriority: 4,
  1137. defaultContent: ''
  1138. },
  1139. {
  1140. title: lang.active,
  1141. data: 'active',
  1142. defaultContent: '',
  1143. render: function (data, type) {
  1144. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  1145. }
  1146. },
  1147. {
  1148. title: lang.action,
  1149. data: 'action',
  1150. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  1151. responsivePriority: 5,
  1152. defaultContent: ''
  1153. },
  1154. ]
  1155. });
  1156. }
  1157. function draw_sync_job_table() {
  1158. // just recalc width if instance already exists
  1159. if ($.fn.DataTable.isDataTable('#sync_job_table') ) {
  1160. $('#sync_job_table').DataTable().columns.adjust().responsive.recalc();
  1161. return;
  1162. }
  1163. $('#sync_job_table').DataTable({
  1164. processing: true,
  1165. serverSide: false,
  1166. language: lang_datatables,
  1167. ajax: {
  1168. type: "GET",
  1169. url: "/api/v1/get/syncjobs/all/no_log",
  1170. dataSrc: function(json){
  1171. $.each(json, function (i, item) {
  1172. item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + encodeURIComponent(item.id) + '">' + lang.open_logs + '</a>'
  1173. item.user2 = escapeHtml(item.user2);
  1174. if (!item.exclude > 0) {
  1175. item.exclude = '-';
  1176. } else {
  1177. item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>';
  1178. }
  1179. item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
  1180. item.action = '<div class="btn-group">' +
  1181. '<a href="/edit/syncjob/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  1182. '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  1183. '</div>';
  1184. item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
  1185. if (item.is_running == 1) {
  1186. item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
  1187. } else {
  1188. item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>';
  1189. }
  1190. if (!item.last_run > 0) {
  1191. item.last_run = lang.waiting;
  1192. }
  1193. if (item.success == null) {
  1194. item.success = '-';
  1195. item.exit_status = '';
  1196. } else {
  1197. item.success = '<i class="text-' + (item.success == 1 ? 'success' : 'danger') + ' bi bi-' + (item.success == 1 ? 'check-lg' : 'x-lg') + '"></i>';
  1198. }
  1199. if (lang['syncjob_'+item.exit_status]) {
  1200. item.exit_status = lang['syncjob_'+item.exit_status];
  1201. } else if (item.success != '-') {
  1202. item.exit_status = lang.syncjob_check_log;
  1203. }
  1204. item.exit_status = item.success + ' ' + item.exit_status;
  1205. });
  1206. return json;
  1207. }
  1208. },
  1209. columns: [
  1210. {
  1211. // placeholder, so checkbox will not block child row toggle
  1212. title: '',
  1213. data: null,
  1214. searchable: false,
  1215. orderable: false,
  1216. defaultContent: '',
  1217. responsivePriority: 1
  1218. },
  1219. {
  1220. title: '',
  1221. data: 'chkbox',
  1222. searchable: false,
  1223. orderable: false,
  1224. defaultContent: '',
  1225. responsivePriority: 2
  1226. },
  1227. {
  1228. title: 'ID',
  1229. data: 'id',
  1230. responsivePriority: 3,
  1231. defaultContent: ''
  1232. },
  1233. {
  1234. title: lang.owner,
  1235. data: 'user2',
  1236. responsivePriority: 4,
  1237. defaultContent: ''
  1238. },
  1239. {
  1240. title: 'Server',
  1241. data: 'server_w_port',
  1242. defaultContent: ''
  1243. },
  1244. {
  1245. title: lang.last_run,
  1246. data: 'last_run',
  1247. defaultContent: ''
  1248. },
  1249. {
  1250. title: lang.syncjob_last_run_result,
  1251. data: 'exit_status',
  1252. defaultContent: ''
  1253. },
  1254. {
  1255. title: 'Log',
  1256. data: 'log',
  1257. defaultContent: ''
  1258. },
  1259. {
  1260. title: lang.active,
  1261. data: 'active',
  1262. defaultContent: '',
  1263. render: function (data, type) {
  1264. return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
  1265. }
  1266. },
  1267. {
  1268. title: lang.status,
  1269. data: 'is_running',
  1270. defaultContent: ''
  1271. },
  1272. {
  1273. title: lang.excludes,
  1274. data: 'exclude',
  1275. defaultContent: '',
  1276. className: 'none'
  1277. },
  1278. {
  1279. title: lang.mins_interval,
  1280. data: 'mins_interval',
  1281. defaultContent: '',
  1282. className: 'none'
  1283. },
  1284. {
  1285. title: lang.action,
  1286. data: 'action',
  1287. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  1288. responsivePriority: 5,
  1289. defaultContent: ''
  1290. },
  1291. ]
  1292. });
  1293. }
  1294. function draw_filter_table() {
  1295. // just recalc width if instance already exists
  1296. if ($.fn.DataTable.isDataTable('#filter_table') ) {
  1297. $('#filter_table').DataTable().columns.adjust().responsive.recalc();
  1298. return;
  1299. }
  1300. var table = $('#filter_table').DataTable({
  1301. autoWidth: false,
  1302. processing: true,
  1303. serverSide: false,
  1304. language: lang_datatables,
  1305. ajax: {
  1306. type: "GET",
  1307. url: "/api/v1/get/filters/all",
  1308. dataSrc: function(json){
  1309. $.each(json, function (i, item) {
  1310. if (item.active == 1) {
  1311. item.active = '<span id="active-script" class="badge fs-6 bg-success">' + lang.active + '</span>';
  1312. } else {
  1313. item.active = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.inactive + '</span>';
  1314. }
  1315. item.script_data = '<pre class="text-break" style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
  1316. item.filter_type = '<div class="badge fs-6 bg-secondary">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
  1317. item.action = '<div class="btn-group">' +
  1318. '<a href="/edit/filter/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
  1319. '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
  1320. '</div>';
  1321. item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
  1322. });
  1323. return json;
  1324. }
  1325. },
  1326. columns: [
  1327. {
  1328. // placeholder, so checkbox will not block child row toggle
  1329. title: '',
  1330. data: null,
  1331. searchable: false,
  1332. orderable: false,
  1333. defaultContent: '',
  1334. responsivePriority: 1
  1335. },
  1336. {
  1337. title: '',
  1338. data: 'chkbox',
  1339. searchable: false,
  1340. orderable: false,
  1341. defaultContent: '',
  1342. responsivePriority: 2
  1343. },
  1344. {
  1345. title: 'ID',
  1346. data: 'id',
  1347. responsivePriority: 2,
  1348. defaultContent: ''
  1349. },
  1350. {
  1351. title: lang.active,
  1352. data: 'active',
  1353. responsivePriority: 3,
  1354. defaultContent: ''
  1355. },
  1356. {
  1357. title: 'Type',
  1358. data: 'filter_type',
  1359. responsivePriority: 4,
  1360. defaultContent: ''
  1361. },
  1362. {
  1363. title: lang.owner,
  1364. data: 'username',
  1365. defaultContent: ''
  1366. },
  1367. {
  1368. title: lang.description,
  1369. data: 'script_desc',
  1370. defaultContent: ''
  1371. },
  1372. {
  1373. title: 'Script',
  1374. data: 'script_data',
  1375. defaultContent: '',
  1376. className: 'none'
  1377. },
  1378. {
  1379. title: lang.action,
  1380. data: 'action',
  1381. className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
  1382. responsivePriority: 5,
  1383. defaultContent: ''
  1384. },
  1385. ]
  1386. });
  1387. };
  1388. // detect element visibility changes
  1389. function onVisible(element, callback) {
  1390. $(document).ready(function() {
  1391. element_object = document.querySelector(element);
  1392. if (element_object === null) return;
  1393. new IntersectionObserver((entries, observer) => {
  1394. entries.forEach(entry => {
  1395. if(entry.intersectionRatio > 0) {
  1396. callback(element_object);
  1397. }
  1398. });
  1399. }).observe(element_object);
  1400. });
  1401. }
  1402. // Load only if the tab is visible
  1403. onVisible("[id^=domain_table]", () => draw_domain_table());
  1404. onVisible("[id^=mailbox_table]", () => draw_mailbox_table());
  1405. onVisible("[id^=resource_table]", () => draw_resource_table());
  1406. onVisible("[id^=alias_table]", () => draw_alias_table());
  1407. onVisible("[id^=aliasdomain_table]", () => draw_aliasdomain_table());
  1408. onVisible("[id^=sync_job_table]", () => draw_sync_job_table());
  1409. onVisible("[id^=filter_table]", () => draw_filter_table());
  1410. onVisible("[id^=bcc_table]", () => draw_bcc_table());
  1411. onVisible("[id^=recipient_map_table]", () => draw_recipient_map_table());
  1412. onVisible("[id^=tls_policy_table]", () => draw_tls_policy_table());
  1413. });