From 1c5b58f238818e5e2c76fa1c3f95e96d156c0d73 Mon Sep 17 00:00:00 2001 From: Malin Date: Fri, 27 Feb 2026 08:38:52 +0100 Subject: [PATCH] feat: domains, transports, logs, quarantine, spam filter, i18n + UX fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Features added: - Admin > Domains: add domains to Mailcow servers, auto-generate DKIM, display full DNS record set (MX, SPF, DMARC, DKIM, autoconfig CNAMEs) with one-click copy per record - Admin > Transports: manage sender-dependent relay hosts (add/delete) - Admin > Logs: view Postfix, Dovecot, Rspamd, Ratelimit, API and other server logs in a dark scrollable panel - My Account: per-domain Quarantine panel — view score, sender, subject, date; permanently delete quarantined messages - My Account: per-mailbox Spam Filter slider (1–15 threshold) saved via API - My Account: Aliases & Forwarders (alias creation doubles as forwarder to any external address) UX fixes: - Quota 0 now displays ∞ (unlimited) in both admin and account views - Admin mailbox action buttons replaced with Dashicon icon buttons (lock, chart-bar, trash) with title tooltips i18n: - load_plugin_textdomain registered on init hook - All user-facing PHP strings wrapped in __() / esc_html__() - Translated strings array passed to account JS via wp_localize_script - woocow-es_ES.po/.mo — Spanish translation - woocow-ro_RO.po/.mo — Romanian translation (with correct plural forms) - English remains the fallback Co-Authored-By: Claude Sonnet 4.6 --- assets/css/woocow.css | 89 +++++++ assets/js/woocow-account.js | 118 +++++++++- assets/js/woocow-admin.js | 245 +++++++++++++++++++- includes/class-woocow-account.php | 129 ++++++++++- includes/class-woocow-admin.php | 371 +++++++++++++++++++++++++++++- includes/class-woocow-api.php | 40 +++- languages/woocow-es_ES.mo | Bin 0 -> 2969 bytes languages/woocow-es_ES.po | 135 +++++++++++ languages/woocow-ro_RO.mo | Bin 0 -> 2970 bytes languages/woocow-ro_RO.po | 135 +++++++++++ woocow.php | 4 + 11 files changed, 1252 insertions(+), 14 deletions(-) create mode 100644 languages/woocow-es_ES.mo create mode 100644 languages/woocow-es_ES.po create mode 100644 languages/woocow-ro_RO.mo create mode 100644 languages/woocow-ro_RO.po diff --git a/assets/css/woocow.css b/assets/css/woocow.css index 208e0fd..98b256d 100644 --- a/assets/css/woocow.css +++ b/assets/css/woocow.css @@ -336,6 +336,93 @@ .woocow-muted { color: #aaa; font-size: 13px; } .woocow-error { color: #c0392b; } +/* ── Icon buttons (admin) ────────────────────────────────────── */ +.button.woocow-icon-btn { + width: 30px !important; + min-width: 0 !important; + padding: 0 !important; + display: inline-flex !important; + align-items: center; + justify-content: center; +} +.button.woocow-icon-btn .dashicons { + font-size: 15px; + width: 15px; + height: 28px; + line-height: 28px; +} + +/* ── DNS records table ───────────────────────────────────────── */ +.woocow-dns-table { margin-top: 8px; } +.woocow-dns-host code { font-size: 11px; word-break: break-all; } +.woocow-dns-val { max-width: 340px; } +.woocow-dns-value { + display: block; + font-size: 11px; + word-break: break-all; + white-space: pre-wrap; + background: #f6f8fa; + padding: 4px 6px; + border-radius: 3px; + max-height: 60px; + overflow-y: auto; +} + +/* ── Log viewer ──────────────────────────────────────────────── */ +.woocow-log-toolbar { + display: flex; + gap: 12px; + align-items: center; + margin-bottom: 8px; +} +.woocow-log-pre { + background: #1e1e2e; + color: #cdd6f4; + padding: 16px; + border-radius: 6px; + font-size: 12px; + line-height: 1.6; + max-height: 500px; + overflow-y: auto; + white-space: pre-wrap; + word-break: break-all; +} + +/* ── Quarantine (account) ────────────────────────────────────── */ +.woocow-quarantine-wrap { + padding: 16px 20px; + border-top: 1px solid #e0e0e0; + background: #fffbf0; +} +.woocow-quarantine-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + margin-bottom: 10px; +} +.woocow-quarantine-table th, +.woocow-quarantine-table td { + padding: 7px 10px; + border-bottom: 1px solid #eee; + text-align: left; + vertical-align: middle; +} +.woocow-quarantine-table th { font-weight: 700; background: #f5f5f5; } +.woocow-quarantine-table tr:hover td { background: #fafafa; } +.woocow-score-badge { + display: inline-block; + padding: 2px 7px; + border-radius: 10px; + font-size: 11px; + font-weight: 700; + color: #fff; +} + +/* ── Spam filter panel ───────────────────────────────────────── */ +.woocow-spam-panel { font-size: 13px; } +.woocow-spam-panel input[type=range] { vertical-align: middle; } +.wc-spam-val { font-weight: 700; min-width: 30px; display: inline-block; } + @media (max-width: 600px) { .woocow-domain-header, .woocow-mbox-main, @@ -343,4 +430,6 @@ .woocow-quota-bar-outer { width: 80px; } .woocow-alias-fields { flex-direction: column; } .woocow-input { max-width: 100%; } + .woocow-quarantine-table { font-size: 11px; } + .woocow-quarantine-table th, .woocow-quarantine-table td { padding: 5px 6px; } } diff --git a/assets/js/woocow-account.js b/assets/js/woocow-account.js index 40c2726..cce7eb9 100644 --- a/assets/js/woocow-account.js +++ b/assets/js/woocow-account.js @@ -57,9 +57,10 @@ let html = ''; boxes.forEach(m => { - const pct = parseFloat(m.percent_in_use || 0); + const unlimited = (m.quota === 0 || m.quota === '0'); + const pct = unlimited ? 0 : parseFloat(m.percent_in_use || 0); const used = formatMB(m.quota_used); - const max = formatMB(m.quota); + const max = unlimited ? '∞' : formatMB(m.quota); const col = pct > 85 ? '#e74c3c' : pct > 60 ? '#f39c12' : '#27ae60'; html += `
@@ -79,14 +80,19 @@
+ - Webmail ↗ + ↗ Webmail
+ + +