/** * WooCow – Admin JavaScript */ (function ($) { 'use strict'; const ajax = (action, data) => $.post(woocow.ajax_url, { action, nonce: woocow.nonce, ...data }); const notice = ($el, type, msg, autohide = true) => { $el.html(`

${msg}

`); if (autohide) setTimeout(() => $el.find('.notice').fadeOut(), 4000); }; // ── Servers Page ────────────────────────────────────────────────────────── if ($('#wc-servers-table-wrap').length) { let editId = 0; const loadServers = () => { ajax('woocow_servers_list').done(res => { if (!res.success) return; const rows = res.data; if (!rows.length) { $('#wc-servers-table-wrap').html('

No servers yet. Add one above.

'); return; } let html = ``; rows.forEach(s => { const badge = s.active == 1 ? 'Active' : 'Inactive'; html += ``; }); html += '
NameURLStatusAddedActions
${esc(s.name)} ${esc(s.url)} ${badge} ${s.created_at.split(' ')[0]}
'; $('#wc-servers-table-wrap').html(html); $('#wc-servers-loading').hide(); }); }; loadServers(); // Show add form $('#wc-add-server').on('click', () => { editId = 0; $('#wc-server-id').val(''); $('#wc-server-name, #wc-server-url, #wc-server-key').val(''); $('#wc-server-active').prop('checked', true); $('#wc-server-form-title').text('Add Server'); $('#wc-server-form').slideDown(); }); // Edit row $(document).on('click', '.wc-srv-edit', function () { editId = $(this).data('id'); const $row = $(this).closest('tr'); $('#wc-server-id').val(editId); $('#wc-server-name').val($row.data('name')); $('#wc-server-url').val($row.data('url')); $('#wc-server-key').val(''); $('#wc-server-active').prop('checked', true); $('#wc-server-form-title').text('Edit Server'); $('#wc-server-form').slideDown(); $('html, body').animate({ scrollTop: 0 }, 300); }); // Save $('#wc-server-save').on('click', () => { const data = { id: $('#wc-server-id').val(), name: $('#wc-server-name').val().trim(), url: $('#wc-server-url').val().trim(), api_key: $('#wc-server-key').val().trim(), active: $('#wc-server-active').is(':checked') ? 1 : 0, }; if (!data.name || !data.url || (!data.api_key && !editId)) { notice($('#wc-notices'), 'error', 'Please fill in all required fields.'); return; } ajax('woocow_server_save', data).done(res => { if (res.success) { notice($('#wc-notices'), 'success', 'Server saved.'); $('#wc-server-form').slideUp(); loadServers(); } else { notice($('#wc-notices'), 'error', res.data || 'Save failed.'); } }); }); // Test connection $('#wc-server-test').on('click', () => { const $result = $('#wc-server-test-result').text('Testing…'); ajax('woocow_server_test', { id: $('#wc-server-id').val(), url: $('#wc-server-url').val().trim(), api_key: $('#wc-server-key').val().trim(), }).done(res => { if (res.success) { $result.html(`✓ Connected – Mailcow ${esc(res.data.version)}`); } else { $result.html(`✗ ${esc(res.data)}`); } }); }); // Test from row $(document).on('click', '.wc-srv-test', function () { const id = $(this).data('id'); const $td = $(this).closest('td'); $td.append(' Testing…'); ajax('woocow_server_test', { id }).done(res => { $td.find('.wc-inline-test').html( res.success ? ` ✓ v${esc(res.data.version)}` : ` ✗ ${esc(res.data)}` ); }); }); // Delete $(document).on('click', '.wc-srv-del', function () { if (!confirm('Delete this server? All domain assignments for it will also be removed.')) return; ajax('woocow_server_delete', { id: $(this).data('id') }).done(res => { if (res.success) loadServers(); else notice($('#wc-notices'), 'error', res.data); }); }); $('#wc-server-cancel').on('click', () => $('#wc-server-form').slideUp()); } // ── Assignments Page ────────────────────────────────────────────────────── if ($('#wc-assignments-table-wrap').length) { const loadAssignments = () => { ajax('woocow_assignments_list').done(res => { if (!res.success) return; const rows = res.data; if (!rows.length) { $('#wc-assignments-table-wrap').html('

No assignments yet.

'); $('#wc-assignments-loading').hide(); return; } let html = ``; rows.forEach(r => { html += ``; }); html += '
CustomerEmailDomainServerAssignedActions
${esc(r.display_name)} ${esc(r.user_email)} ${esc(r.domain)} ${esc(r.server_name)} ${r.created_at.split(' ')[0]}
'; $('#wc-assignments-table-wrap').html(html); $('#wc-assignments-loading').hide(); }); }; // Load servers into select ajax('woocow_servers_list').done(res => { if (!res.success) return; res.data.filter(s => s.active == 1).forEach(s => { $('#wc-assign-server').append(``); }); }); // Server → load domains $('#wc-assign-server').on('change', function () { const sid = $(this).val(); $('#wc-assign-domain').html(''); if (!sid) { $('#wc-domain-row').hide(); return; } ajax('woocow_server_domains', { server_id: sid }).done(res => { if (!res.success) { alert('Could not load domains: ' + res.data); return; } $('#wc-assign-domain').html(''); res.data.forEach(d => { $('#wc-assign-domain').append(``); }); $('#wc-domain-row').show(); }); }); // Customer autocomplete let searchTimer; $('#wc-cust-search').on('input', function () { clearTimeout(searchTimer); const term = $(this).val().trim(); if (term.length < 2) { $('#wc-cust-results').hide(); return; } searchTimer = setTimeout(() => { ajax('woocow_customers_search', { term }).done(res => { if (!res.success || !res.data.length) { $('#wc-cust-results').hide(); return; } let html = ''; res.data.forEach(c => { html += `
${esc(c.label)}
`; }); $('#wc-cust-results').html(html).show(); }); }, 250); }); $(document).on('click', '.woocow-ac-item', function () { $('#wc-cust-id').val($(this).data('id')); $('#wc-cust-search').val(''); $('#wc-cust-selected').text($(this).data('label')); $('#wc-cust-results').hide(); }); $(document).on('click', function (e) { if (!$(e.target).closest('#wc-cust-results, #wc-cust-search').length) { $('#wc-cust-results').hide(); } }); // Save assignment $('#wc-assign-save').on('click', () => { const customer_id = $('#wc-cust-id').val(); const server_id = $('#wc-assign-server').val(); const domain = $('#wc-assign-domain').val(); if (!customer_id || !server_id || !domain) { notice($('#wc-assign-notice'), 'error', 'Please select a customer, server, and domain.'); return; } ajax('woocow_assignment_save', { customer_id, server_id, domain }).done(res => { if (res.success) { notice($('#wc-assign-notice'), 'success', `Domain ${esc(domain)} assigned.`); $('#wc-cust-id').val(''); $('#wc-cust-selected').text(''); loadAssignments(); } else { notice($('#wc-assign-notice'), 'error', res.data); } }); }); // Delete assignment $(document).on('click', '.wc-assign-del', function () { if (!confirm('Remove this domain assignment?')) return; ajax('woocow_assignment_delete', { id: $(this).data('id') }).done(res => { if (res.success) loadAssignments(); }); }); loadAssignments(); } // ── Mailboxes Page ──────────────────────────────────────────────────────── if ($('#wc-mb-table-wrap').length) { let currentServerId = null; let currentDomain = null; // Server → load domains $('#wc-mb-server').on('change', function () { const sid = $(this).val(); $('#wc-mb-domain').hide().html(''); $('#wc-mb-load').prop('disabled', true); if (!sid) return; ajax('woocow_server_domains', { server_id: sid }).done(res => { if (!res.success) return; res.data.forEach(d => { $('#wc-mb-domain').append(``); }); $('#wc-mb-domain').show(); }); }); $('#wc-mb-domain').on('change', function () { $('#wc-mb-load').prop('disabled', !$(this).val()); }); const loadMailboxes = () => { currentServerId = $('#wc-mb-server').val(); currentDomain = $('#wc-mb-domain').val(); if (!currentServerId || !currentDomain) return; $('#wc-mb-table-wrap').html('

Loading…

'); ajax('woocow_admin_mailboxes', { server_id: currentServerId, domain: currentDomain }).done(res => { if (!res.success) { $('#wc-mb-table-wrap').html(`

${esc(res.data)}

`); return; } const boxes = res.data.mailboxes || []; const webmail = res.data.webmail_url; if (!boxes.length) { $('#wc-mb-table-wrap').html('

No mailboxes found for this domain.

'); } else { let html = ``; boxes.forEach(m => { const pct = m.percent_in_use || 0; const used = formatMB(m.quota_used); const max = formatMB(m.quota); const bar = `
`; const quotaMB = Math.round((m.quota || 0) / 1024 / 1024); html += ``; }); html += '
EmailNameQuota UsedQuota MaxActiveActions
${esc(m.username)} ${esc(m.name)} ${used} ${bar} ${max} ${m.active == 1 ? '✓' : '–'}
'; $('#wc-mb-table-wrap').html(html); } $('#wc-mb-domain-label').text(currentDomain); $('#wc-mb-create').show(); }); }; $('#wc-mb-load').on('click', loadMailboxes); // Create mailbox modal $('#wc-mb-create').on('click', () => { $('#wc-mb-local, #wc-mb-fullname, #wc-mb-pass, #wc-mb-pass2').val(''); $('#wc-mb-quota').val(1024); $('#wc-mb-modal-notice').text(''); $('#wc-mb-modal').show(); }); $('#wc-mb-modal-cancel').on('click', () => $('#wc-mb-modal').hide()); $(document).on('keydown', e => { if (e.key === 'Escape') $('#wc-mb-modal').hide(); }); $('#wc-mb-modal-save').on('click', () => { const data = { server_id: currentServerId, domain: currentDomain, local_part: $('#wc-mb-local').val().trim(), name: $('#wc-mb-fullname').val().trim(), password: $('#wc-mb-pass').val(), password2: $('#wc-mb-pass2').val(), quota: $('#wc-mb-quota').val(), }; $('#wc-mb-modal-notice').text('Creating…'); ajax('woocow_admin_mailbox_create', data).done(res => { if (res.success) { $('#wc-mb-modal').hide(); notice($('#wc-mb-notices'), 'success', `Mailbox ${esc(res.data.email)} created.`); loadMailboxes(); } else { $('#wc-mb-modal-notice').html(`${esc(res.data)}`); } }); }); // Delete mailbox $(document).on('click', '.wc-mb-del', function () { const email = $(this).data('email'); if (!confirm(`Delete mailbox ${email}? This cannot be undone.`)) return; ajax('woocow_admin_mailbox_delete', { server_id: currentServerId, email }).done(res => { if (res.success) loadMailboxes(); else notice($('#wc-mb-notices'), 'error', res.data); }); }); // ── Edit modal: Reset PW ────────────────────────────────────────────── let editEmail = ''; let editType = ''; const openEditModal = (email, type, currentQuota) => { editEmail = email; editType = type; $('#wc-mb-edit-subtitle').text(email); $('#wc-mb-edit-notice').text(''); $('#wc-mb-edit-pw-section, #wc-mb-edit-quota-section').hide(); if (type === 'password') { $('#wc-mb-edit-title').text('Reset Password'); $('#wc-mb-edit-pass, #wc-mb-edit-pass2').val(''); $('#wc-mb-edit-pw-section').show(); setTimeout(() => $('#wc-mb-edit-pass').trigger('focus'), 100); } else { $('#wc-mb-edit-title').text('Set Quota'); $('#wc-mb-edit-quota').val(currentQuota || 1024); $('#wc-mb-edit-quota-section').show(); setTimeout(() => $('#wc-mb-edit-quota').trigger('focus'), 100); } $('#wc-mb-edit-modal').show(); }; $(document).on('click', '.wc-mb-reset-pw', function () { openEditModal($(this).data('email'), 'password', null); }); $(document).on('click', '.wc-mb-set-quota', function () { openEditModal($(this).data('email'), 'quota', $(this).data('quota')); }); $('#wc-mb-edit-cancel').on('click', () => $('#wc-mb-edit-modal').hide()); $(document).on('keydown', e => { if (e.key === 'Escape') $('#wc-mb-edit-modal').hide(); }); $('#wc-mb-edit-save').on('click', () => { const $note = $('#wc-mb-edit-notice').text('Saving…'); const data = { server_id: currentServerId, email: editEmail, type: editType }; if (editType === 'password') { data.password = $('#wc-mb-edit-pass').val(); data.password2 = $('#wc-mb-edit-pass2').val(); if (!data.password) { $note.html('Password cannot be empty.'); return; } if (data.password !== data.password2) { $note.html('Passwords do not match.'); return; } } else { data.quota = $('#wc-mb-edit-quota').val(); if (!data.quota || data.quota < 1) { $note.html('Enter a valid quota.'); return; } } ajax('woocow_admin_mailbox_edit', data).done(res => { if (res.success) { $('#wc-mb-edit-modal').hide(); const msg = editType === 'password' ? 'Password updated.' : 'Quota updated.'; notice($('#wc-mb-notices'), 'success', `${esc(editEmail)} — ${msg}`); if (editType === 'quota') loadMailboxes(); // refresh to show new quota } else { $note.html(`${esc(res.data)}`); } }); }); } // ── Utilities ───────────────────────────────────────────────────────────── function esc(str) { return String(str).replace(/[&<>"']/g, m => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[m]); } function formatMB(bytes) { if (bytes === 0 || bytes === '0') return '∞'; if (!bytes) return '0 MB'; const mb = bytes / 1024 / 1024; return mb >= 1024 ? (mb / 1024).toFixed(1) + ' GB' : mb.toFixed(0) + ' MB'; } // ── Domains Page ────────────────────────────────────────────────────────── if ($('#wc-dom-server').length) { let domServerId = null; let domServerUrl = null; let domainsData = {}; // domain name → full data object $('#wc-dom-server').on('change', function () { domServerId = $(this).val(); domServerUrl = $(this).find('option:selected').data('url'); $('#wc-dom-load').prop('disabled', !domServerId); $('#wc-dom-add-btn, #wc-dom-table-wrap').hide(); domainsData = {}; }); const loadDomains = () => { ajax('woocow_server_domains', { server_id: domServerId }).done(res => { if (!res.success) { notice($('#wc-dom-notices'), 'error', res.data); return; } const domains = res.data; domainsData = {}; domains.forEach(d => { domainsData[d.domain] = d; }); if (!domains.length) { $('#wc-dom-table-wrap').html('

No domains on this server yet.

').show(); } else { let html = ``; domains.forEach(d => { const mboxes = `${d.mboxes_in}/${d.mailboxes || '∞'}`; const qUsed = formatMB(d.quota_used * 1024 * 1024); const qTotal = d.quota ? formatMB(d.quota * 1024 * 1024) : '∞'; const active = d.active == 1 ? 'Active' : 'Inactive'; html += ``; }); html += '
Domain Mailboxes Quota Used Active Actions
${esc(d.domain)}${d.description ? `
${esc(d.description)}` : ''}
${mboxes} ${qUsed} / ${qTotal} ${active}
'; $('#wc-dom-table-wrap').html(html).show(); } $('#wc-dom-add-btn').show(); }); }; $('#wc-dom-load').on('click', loadDomains); $('#wc-dom-add-btn').on('click', () => { $('#wc-dom-name, #wc-dom-desc').val(''); $('#wc-dom-form-notice').text(''); $('#wc-dom-form').slideDown(); }); $('#wc-dom-cancel').on('click', () => $('#wc-dom-form').slideUp()); $('#wc-dom-save').on('click', () => { const $note = $('#wc-dom-form-notice').text('Adding domain…'); const data = { server_id: domServerId, domain: $('#wc-dom-name').val().trim(), description: $('#wc-dom-desc').val().trim(), mailboxes: $('#wc-dom-mailboxes').val(), aliases: $('#wc-dom-aliases').val(), quota: $('#wc-dom-quota').val(), defquota: $('#wc-dom-defquota').val(), dkim_size: $('#wc-dom-dkim-size').val(), }; if (!data.domain) { $note.html('Domain name required.'); return; } ajax('woocow_admin_domain_add', data).done(res => { if (res.success) { $note.html('✓ Domain added with DKIM generated!'); $('#wc-dom-form').slideUp(); loadDomains(); } else { $note.html(`${esc(res.data)}`); } }); }); // ── Edit Domain modal ───────────────────────────────────────────────── $(document).on('click', '.wc-dom-edit', function () { const domain = $(this).data('domain'); const d = domainsData[domain]; if (!d) return; $('#wc-dom-edit-domain').val(domain); $('#wc-dom-edit-name').text(domain); $('#wc-dom-edit-desc').val(d.description || ''); $('#wc-dom-edit-mboxes').val(d.mailboxes || 10); $('#wc-dom-edit-aliases').val(d.aliases || 400); $('#wc-dom-edit-quota').val(d.quota || 10240); $('#wc-dom-edit-defquota').val(d.defquota || 3072); $('#wc-dom-edit-rl-value').val(d.rl_value || 0); $('#wc-dom-edit-rl-frame').val(d.rl_frame || 's'); $('#wc-dom-edit-active').prop('checked', d.active == 1); $('#wc-dom-edit-notice').text(''); // Load relayhosts into transport dropdown const $sel = $('#wc-dom-edit-relayhost').html(''); ajax('woocow_admin_relayhosts_list', { server_id: domServerId }).done(rh => { if (rh.success && Array.isArray(rh.data)) { rh.data.forEach(r => { $sel.append(``); }); $sel.val(d.relayhost || '0'); } }); $('#wc-dom-edit-modal').show(); }); $('#wc-dom-edit-cancel').on('click', () => $('#wc-dom-edit-modal').hide()); $('#wc-dom-edit-save').on('click', () => { const $note = $('#wc-dom-edit-notice').text('Saving…'); const domain = $('#wc-dom-edit-domain').val(); ajax('woocow_admin_domain_edit', { server_id: domServerId, domain, description: $('#wc-dom-edit-desc').val(), mailboxes: $('#wc-dom-edit-mboxes').val(), aliases: $('#wc-dom-edit-aliases').val(), quota: $('#wc-dom-edit-quota').val(), defquota: $('#wc-dom-edit-defquota').val(), rl_value: $('#wc-dom-edit-rl-value').val(), rl_frame: $('#wc-dom-edit-rl-frame').val(), relayhost: $('#wc-dom-edit-relayhost').val(), active: $('#wc-dom-edit-active').is(':checked') ? 1 : 0, }).done(res => { if (res.success) { $('#wc-dom-edit-modal').hide(); notice($('#wc-dom-notices'), 'success', `Domain ${esc(domain)} updated.`); loadDomains(); } else { $note.html(`${esc(res.data)}`); } }); }); // ── Delete Domain ───────────────────────────────────────────────────── $(document).on('click', '.wc-dom-del', function () { const domain = $(this).data('domain'); if (!confirm(`Delete domain ${domain}? This will also delete all mailboxes, aliases, and data on the Mailcow server. This cannot be undone!`)) return; ajax('woocow_admin_domain_delete', { server_id: domServerId, domain }).done(res => { if (res.success) { notice($('#wc-dom-notices'), 'success', `Domain ${esc(domain)} deleted.`); loadDomains(); } else { notice($('#wc-dom-notices'), 'error', res.data); } }); }); // DNS Records panel $(document).on('click', '.wc-dom-dns', function () { const domain = $(this).data('domain'); $('#wc-dom-dns-domain').text(domain); $('#wc-dom-dns-content').html('

Loading…

'); $('#wc-dom-dns-panel').show(); $('html,body').animate({ scrollTop: $('#wc-dom-dns-panel').offset().top - 40 }, 300); ajax('woocow_admin_domain_dns', { server_id: domServerId, domain }).done(res => { if (!res.success) { $('#wc-dom-dns-content').html(`

${esc(res.data)}

`); return; } const d = res.data; let html = ``; d.records.forEach(r => { html += ``; }); html += '
TypeHost / NameValuePriorityTTLNote
${esc(r.type)} ${esc(r.host)} ${esc(r.value)} ${esc(r.prio)} ${esc(r.ttl)} ${esc(r.note || '')}
'; if (!d.dkim_txt) { html += `

⚠ DKIM key not yet generated for this domain. Add the domain first, then view DNS records again.

`; } $('#wc-dom-dns-content').html(html); }); }); $(document).on('click', '.wc-copy-dns', function () { const val = $(this).data('val'); navigator.clipboard.writeText(val).then(() => { $(this).text('Copied!'); setTimeout(() => $(this).text('Copy'), 1500); }); }); $('#wc-dom-dns-close').on('click', () => $('#wc-dom-dns-panel').hide()); } // ── Transports Page ─────────────────────────────────────────────────────── if ($('#wc-tr-server').length) { let trServerId = null; $('#wc-tr-server').on('change', function () { trServerId = $(this).val(); $('#wc-tr-load').prop('disabled', !trServerId); }); const loadTransports = () => { ajax('woocow_admin_relayhosts_list', { server_id: trServerId }).done(res => { if (!res.success) { notice($('#wc-tr-notices'), 'error', res.data); return; } const rows = res.data; if (!Array.isArray(rows) || !rows.length) { $('#wc-tr-table-wrap').html('

No transports configured on this server.

'); } else { let html = ``; rows.forEach(r => { html += ``; }); html += '
Hostname:PortUsernameUsed by DomainsActiveActions
${esc(r.hostname)} ${esc(r.username)} ${esc(r.used_by_domains || '—')} ${r.active == 1 ? '✓' : '–'}
'; $('#wc-tr-table-wrap').html(html); } $('#wc-tr-add-btn').show(); }); }; $('#wc-tr-load').on('click', loadTransports); $('#wc-tr-add-btn').on('click', () => { $('#wc-tr-hostname,#wc-tr-user,#wc-tr-pass').val(''); $('#wc-tr-form').slideDown(); }); $('#wc-tr-cancel').on('click', () => $('#wc-tr-form').slideUp()); $('#wc-tr-save').on('click', () => { const $note = $('#wc-tr-form-notice').text('Saving…'); ajax('woocow_admin_relayhost_save', { server_id: trServerId, hostname: $('#wc-tr-hostname').val().trim(), username: $('#wc-tr-user').val().trim(), password: $('#wc-tr-pass').val(), active: $('#wc-tr-active').is(':checked') ? 1 : 0, }).done(res => { if (res.success) { $note.html('✓ Transport added.'); $('#wc-tr-form').slideUp(); loadTransports(); } else $note.html(`${esc(res.data)}`); }); }); $(document).on('click', '.wc-tr-del', function () { if (!confirm('Delete this transport?')) return; ajax('woocow_admin_relayhost_delete', { server_id: trServerId, id: $(this).data('id') }).done(res => { if (res.success) loadTransports(); else notice($('#wc-tr-notices'), 'error', res.data); }); }); } // ── Logs Page ───────────────────────────────────────────────────────────── if ($('#wc-log-server').length) { $('#wc-log-server').on('change', function () { $('#wc-log-load').prop('disabled', !$(this).val()); }); $('#wc-log-load').on('click', () => { const sid = $('#wc-log-server').val(); const type = $('#wc-log-type').val(); $('#wc-log-wrap').html('

Loading…

'); ajax('woocow_admin_logs', { server_id: sid, log_type: type }).done(res => { if (!res.success) { $('#wc-log-wrap').html(`

${esc(res.data)}

`); return; } const entries = Array.isArray(res.data) ? res.data : Object.values(res.data); if (!entries.length) { $('#wc-log-wrap').html('

No log entries.

'); return; } // Render as a scrollable pre block const text = entries.map(e => { if (typeof e === 'string') return e; if (e.time && e.message) return `[${e.time}] ${e.message}`; return JSON.stringify(e); }).join('\n'); $('#wc-log-wrap').html(`
${esc(type.charAt(0).toUpperCase() + type.slice(1))} log ${entries.length} entries
${esc(text)}
`); }); }); } // ── Admin Quarantine Page ───────────────────────────────────────────────── if ($('#wc-quar-server').length) { let quarServerId = null; $('#wc-quar-server').on('change', function () { quarServerId = $(this).val(); $('#wc-quar-load').prop('disabled', !quarServerId); }); const loadQuarantine = () => { $('#wc-quar-wrap').html('

Loading…

'); ajax('woocow_admin_quarantine', { server_id: quarServerId }).done(res => { if (!res.success) { $('#wc-quar-wrap').html(`

${esc(res.data)}

`); return; } const msgs = Array.isArray(res.data) ? res.data : []; if (!msgs.length) { $('#wc-quar-wrap').html('

No quarantined messages.

'); return; } let html = ``; msgs.forEach(m => { const date = m.created ? new Date(m.created * 1000).toLocaleString() : '—'; const domain = (m.rcpt || '').split('@')[1] || ''; html += ``; }); html += '
DateSenderRecipientSubjectScoreActions
${esc(date)} ${esc(m.sender)} ${esc(m.rcpt)} ${esc(m.subject)} ${esc(m.score)}
'; html += `

${msgs.length} quarantined message(s). Note: To release a message to inbox, use the link in the quarantine notification email or Webmail.

`; $('#wc-quar-wrap').html(html); }); }; $('#wc-quar-load').on('click', loadQuarantine); $(document).on('click', '.wc-quar-del', function () { if (!confirm('Permanently delete this quarantined message?')) return; const qid = $(this).data('qid'); ajax('woocow_admin_quarantine_delete', { server_id: quarServerId, qid }).done(res => { if (res.success) loadQuarantine(); else notice($('#wc-quar-notices'), 'error', res.data); }); }); $(document).on('click', '.wc-quar-block', function () { const sender = $(this).data('sender'); const domain = $(this).data('domain'); if (!domain) { notice($('#wc-quar-notices'), 'error', 'Could not determine recipient domain.'); return; } if (!confirm(`Add ${sender} to the blacklist for domain ${domain}?`)) return; ajax('woocow_admin_quarantine_block', { server_id: quarServerId, domain, object_from: sender, }).done(res => { if (res.success) notice($('#wc-quar-notices'), 'success', `Sender ${esc(sender)} blacklisted for ${esc(domain)}.`); else notice($('#wc-quar-notices'), 'error', res.data); }); }); } })(jQuery);