mailbox.js 53 KB

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