Files
WooCow/assets/js/woocow-account.js
Malin 8644282ecb fix: correct mailbox endpoint path and quota field name
- get_domain_mailboxes: was POST /api/v1/get/mailboxes/{domain},
  correct path is GET /api/v1/get/mailbox/all/{domain}
- Quota percentage field is percent_in_use, not quota_used_in_percent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 08:18:08 +01:00

282 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* WooCow My Account frontend JavaScript
*/
(function ($) {
'use strict';
if (!$('#woocow-account').length) return;
const ajax = (action, data) =>
$.post(woocowAcct.ajax_url, { action, nonce: woocowAcct.nonce, ...data });
const notice = (msg, type = 'success') => {
const $n = $('#woocow-acct-notices');
$n.html(`<div class="woocommerce-${type === 'success' ? 'message' : 'error'}">${msg}</div>`);
setTimeout(() => $n.find('> div').fadeOut(400, function () { $(this).remove(); }), 5000);
};
function esc(str) {
return String(str).replace(/[&<>"']/g, m => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;'
})[m]);
}
function formatMB(bytes) {
if (!bytes) return '0 MB';
const mb = bytes / 1024 / 1024;
return mb >= 1024 ? (mb / 1024).toFixed(1) + ' GB' : mb.toFixed(0) + ' MB';
}
// ── Load Mailboxes ────────────────────────────────────────────────────────
$(document).on('click', '.woocow-load-mailboxes', function () {
const $panel = $(this).closest('.woocow-domain-panel');
const sid = $panel.data('server-id');
const domain = $panel.data('domain');
const $wrap = $panel.find('.woocow-mailboxes-wrap');
const $list = $panel.find('.woocow-mailboxes-list');
$(this).prop('disabled', true).text('Loading…');
$wrap.show();
$list.html('<p class="woocow-loading">Fetching mailboxes…</p>');
ajax('woocow_acct_mailboxes', { server_id: sid, domain }).done(res => {
$(this).prop('disabled', false).text('Refresh');
if (!res.success) {
$list.html(`<p class="woocow-error">${esc(res.data)}</p>`);
return;
}
const boxes = res.data.mailboxes || [];
const webmail = res.data.webmail_url;
if (!boxes.length) {
$list.html('<p class="woocow-muted">No mailboxes yet. Create one below.</p>');
return;
}
let html = '';
boxes.forEach(m => {
const pct = parseFloat(m.percent_in_use || 0);
const used = formatMB(m.quota_used);
const max = formatMB(m.quota);
const col = pct > 85 ? '#e74c3c' : pct > 60 ? '#f39c12' : '#27ae60';
html += `<div class="woocow-mailbox-row" data-email="${esc(m.username)}">
<div class="woocow-mbox-main">
<div class="woocow-mbox-address">
<span class="woocow-mbox-icon">✉</span>
<strong>${esc(m.username)}</strong>
${m.name ? `<span class="woocow-mbox-name">(${esc(m.name)})</span>` : ''}
</div>
<div class="woocow-quota-wrap">
<div class="woocow-quota-bar-outer">
<div class="woocow-quota-bar-inner" style="width:${pct}%;background:${col}"></div>
</div>
<span class="woocow-quota-text">${used} / ${max} (${pct}%)</span>
</div>
</div>
<div class="woocow-mbox-actions">
<button class="woocow-btn woocow-btn-sm wc-change-pw"
data-server="${esc(sid)}" data-domain="${esc(domain)}" data-email="${esc(m.username)}">
Change Password
</button>
<button class="woocow-btn woocow-btn-sm woocow-btn-outline wc-toggle-aliases"
data-server="${esc(sid)}" data-domain="${esc(domain)}">
Aliases
</button>
<a href="${esc(webmail)}" target="_blank" rel="noopener" class="woocow-btn woocow-btn-sm woocow-btn-ghost">
Webmail ↗
</a>
</div>
<div class="woocow-aliases-wrap" style="display:none">
<div class="woocow-aliases-list"></div>
<div class="woocow-alias-create-form" style="display:none">
<div class="woocow-alias-fields">
<input type="email" class="wc-alias-addr woocow-input" placeholder="alias@${esc(domain)}">
<span class="woocow-arrow">→</span>
<input type="email" class="wc-alias-goto woocow-input" placeholder="destination@example.com" value="${esc(m.username)}">
<button class="woocow-btn woocow-btn-primary woocow-btn-sm wc-alias-save"
data-server="${esc(sid)}" data-domain="${esc(domain)}">Add</button>
<button class="woocow-btn woocow-btn-sm wc-alias-cancel">✕</button>
</div>
</div>
<button class="woocow-btn woocow-btn-sm woocow-btn-outline wc-alias-add-btn">+ Add Alias</button>
</div>
</div>`;
});
$list.html(html);
});
});
// ── Aliases ───────────────────────────────────────────────────────────────
$(document).on('click', '.wc-toggle-aliases', function () {
const $row = $(this).closest('.woocow-mailbox-row');
const $wrap = $row.find('.woocow-aliases-wrap');
const sid = $(this).data('server');
const domain = $(this).data('domain');
if ($wrap.is(':visible')) {
$wrap.slideUp();
return;
}
const $list = $row.find('.woocow-aliases-list').html('<p class="woocow-muted">Loading aliases…</p>');
$wrap.slideDown();
ajax('woocow_acct_aliases', { server_id: sid, domain }).done(res => {
if (!res.success) {
$list.html(`<p class="woocow-error">${esc(res.data)}</p>`);
return;
}
const aliases = res.data;
if (!aliases.length) {
$list.html('<p class="woocow-muted">No aliases for this domain yet.</p>');
return;
}
let html = '<ul class="woocow-alias-list">';
aliases.forEach(a => {
html += `<li>
<span class="woocow-alias-addr">${esc(a.address)}</span>
<span class="woocow-arrow">→</span>
<span class="woocow-alias-goto">${esc(a.goto)}</span>
<button class="woocow-btn woocow-btn-danger woocow-btn-xs wc-alias-del"
data-id="${esc(a.id)}" data-server="${esc(sid)}" data-domain="${esc(domain)}">✕</button>
</li>`;
});
html += '</ul>';
$list.html(html);
});
});
$(document).on('click', '.wc-alias-add-btn', function () {
$(this).closest('.woocow-aliases-wrap').find('.woocow-alias-create-form').slideToggle();
});
$(document).on('click', '.wc-alias-cancel', function () {
$(this).closest('.woocow-alias-create-form').slideUp();
});
$(document).on('click', '.wc-alias-save', function () {
const $form = $(this).closest('.woocow-alias-create-form');
const sid = $(this).data('server');
const domain = $(this).data('domain');
const addr = $form.find('.wc-alias-addr').val().trim();
const goto_ = $form.find('.wc-alias-goto').val().trim();
if (!addr || !goto_) { alert('Both alias and destination are required.'); return; }
ajax('woocow_acct_alias_create', { server_id: sid, domain, address: addr, goto: goto_ }).done(res => {
if (res.success) {
// Refresh alias list
$(this).closest('.woocow-mailbox-row').find('.wc-toggle-aliases').trigger('click');
setTimeout(() => { $(this).closest('.woocow-mailbox-row').find('.wc-toggle-aliases').trigger('click'); }, 300);
$form.slideUp();
} else {
alert('Error: ' + res.data);
}
});
});
$(document).on('click', '.wc-alias-del', function () {
if (!confirm('Delete this alias?')) return;
const $li = $(this).closest('li');
const sid = $(this).data('server');
const domain = $(this).data('domain');
const id = $(this).data('id');
ajax('woocow_acct_alias_delete', { server_id: sid, domain, alias_id: id }).done(res => {
if (res.success) $li.fadeOut(300, function () { $(this).remove(); });
else alert('Delete failed: ' + res.data);
});
});
// ── Create Mailbox ────────────────────────────────────────────────────────
$(document).on('click', '.woocow-create-mbox-btn', function () {
const $panel = $(this).closest('.woocow-domain-panel');
$panel.find('.woocow-create-mbox-form').slideToggle();
});
$(document).on('click', '.wc-mbox-cancel', function () {
$(this).closest('.woocow-create-mbox-form').slideUp();
});
$(document).on('click', '.wc-mbox-submit', function () {
const $panel = $(this).closest('.woocow-domain-panel');
const sid = $panel.data('server-id');
const domain = $panel.data('domain');
const $form = $(this).closest('.woocow-create-mbox-form');
const $note = $form.find('.wc-mbox-notice');
const local = $form.find('.wc-mbox-local').val().trim();
const name = $form.find('.wc-mbox-name').val().trim();
const pass = $form.find('.wc-mbox-pass').val();
const pass2 = $form.find('.wc-mbox-pass2').val();
const quota = $form.find('.wc-mbox-quota').val();
if (!local || !pass) { $note.html('<span class="woocow-error">Username and password required.</span>'); return; }
if (pass !== pass2) { $note.html('<span class="woocow-error">Passwords do not match.</span>'); return; }
$note.text('Creating…');
ajax('woocow_acct_mailbox_create', { server_id: sid, domain, local_part: local, name, password: pass, password2: pass2, quota }).done(res => {
if (res.success) {
$note.html('<span style="color:green">✓ Mailbox created!</span>');
$form.slideUp();
// Refresh mailbox list
$panel.find('.woocow-load-mailboxes').trigger('click');
} else {
$note.html(`<span class="woocow-error">${esc(res.data)}</span>`);
}
});
});
// ── Change Password Modal ─────────────────────────────────────────────────
$(document).on('click', '.wc-change-pw', function () {
const sid = $(this).data('server');
const domain = $(this).data('domain');
const email = $(this).data('email');
$('#woocow-pw-server-id').val(sid);
$('#woocow-pw-mailbox').val(email);
$('#woocow-pw-email').text(email);
$('#woocow-pw-new, #woocow-pw-new2').val('');
$('#woocow-pw-notice').text('');
$('#woocow-pw-modal').fadeIn(200);
// Store domain on modal for verification
$('#woocow-pw-modal').data('domain', domain);
});
$('#woocow-pw-cancel').on('click', () => $('#woocow-pw-modal').fadeOut(200));
$(document).on('click', '#woocow-pw-modal', function (e) {
if ($(e.target).is('#woocow-pw-modal')) $(this).fadeOut(200);
});
$('#woocow-pw-save').on('click', function () {
const sid = $('#woocow-pw-server-id').val();
const email = $('#woocow-pw-mailbox').val();
const domain = $('#woocow-pw-modal').data('domain');
const pass = $('#woocow-pw-new').val();
const pass2 = $('#woocow-pw-new2').val();
const $note = $('#woocow-pw-notice');
if (!pass || pass !== pass2) {
$note.html('<span class="woocow-error">Passwords do not match or are empty.</span>');
return;
}
$note.text('Updating…');
ajax('woocow_acct_mailbox_password', { server_id: sid, domain, email, password: pass, password2: pass2 }).done(res => {
if (res.success) {
$note.html('<span style="color:green">✓ Password updated!</span>');
setTimeout(() => $('#woocow-pw-modal').fadeOut(200), 1500);
} else {
$note.html(`<span class="woocow-error">${esc(res.data)}</span>`);
}
});
});
})(jQuery);