mailbox.js 53 KB

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