Full WooCommerce plugin for aaPanel hosting management: - aaPanel API client (all website + database endpoints) - Admin: server management, site/DB assignments, full site/DB management panels - Customer My Account: web hosting tab with sites and databases - WooDomains PowerDNS integration for DNS management - WooCommerce order auto-provisioning (product → server linking) - Permission model: admin has all actions, customers have scoped access Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
390 lines
19 KiB
JavaScript
390 lines
19 KiB
JavaScript
/**
|
|
* WooAApanel Account JS
|
|
*
|
|
* Customer My Account "Web Hosting" tab.
|
|
* Handles site and database panels.
|
|
* Integrates WooDomains PowerDNS for DNS management if active.
|
|
*/
|
|
(function ($) {
|
|
'use strict';
|
|
|
|
var cfg = wooaapanelAcct;
|
|
var ajaxUrl = cfg.ajax_url;
|
|
var nonce = cfg.nonce;
|
|
var pdnsActive = parseInt(cfg.pdns_active, 10) === 1;
|
|
var pdnsNonce = cfg.pdns_nonce;
|
|
|
|
/* ── Utility ──────────────────────────────────────────────── */
|
|
|
|
function post(action, data, cb) {
|
|
data = $.extend({ action: action, nonce: nonce }, data);
|
|
$.post(ajaxUrl, data, cb).fail(function () {
|
|
setNotice('#wap-acct-notices', 'Request failed. Please reload and try again.', 'error');
|
|
});
|
|
}
|
|
|
|
function pdnsPost(action, data, cb) {
|
|
data = $.extend({ action: action, nonce: pdnsNonce }, data);
|
|
$.post(ajaxUrl, data, cb);
|
|
}
|
|
|
|
function setNotice(selector, msg, type) {
|
|
var $el = $(selector);
|
|
$el.attr('class', 'woocommerce-' + (type === 'error' ? 'error' : 'message') + ' woocommerce-info')
|
|
.text(msg).show();
|
|
setTimeout(function () { $el.fadeOut(); }, 5000);
|
|
}
|
|
|
|
function inlineNotice($el, msg, type) {
|
|
$el.text(msg).attr('class', 'wap-notice-inline ' + (type === 'error' ? 'error' : 'ok'));
|
|
setTimeout(function () { $el.text('').removeClass('ok error'); }, 4000);
|
|
}
|
|
|
|
function escHtml(s) {
|
|
return String(s)
|
|
.replace(/&/g,'&').replace(/</g,'<')
|
|
.replace(/>/g,'>').replace(/"/g,'"');
|
|
}
|
|
|
|
function siteOpts($panel) {
|
|
return {
|
|
server_id: $panel.data('server-id'),
|
|
site_name: $panel.data('site-name')
|
|
};
|
|
}
|
|
|
|
function dbOpts($panel) {
|
|
return {
|
|
server_id: $panel.data('server-id'),
|
|
db_name: $panel.data('db-name')
|
|
};
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════
|
|
SITE PANELS
|
|
══════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Domains ──────────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-domains', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-domains-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible')) {
|
|
loadDomains($panel);
|
|
}
|
|
});
|
|
|
|
function loadDomains($panel) {
|
|
var opts = siteOpts($panel);
|
|
var $list = $panel.find('.wap-domains-list').html('<em>Loading…</em>');
|
|
post('wooaapanel_acct_site_domains', opts, function (res) {
|
|
var domains = res.data && res.data.data ? res.data.data : [];
|
|
if (!domains.length) { $list.html('<p>No extra domains.</p>'); return; }
|
|
var html = '<table class="woocommerce-table"><thead><tr><th>Domain</th><th>Port</th><th></th></tr></thead><tbody>';
|
|
$.each(domains, function (i, d) {
|
|
html += '<tr><td>' + escHtml(d.name || d.domain || '') + '</td><td>' + (d.port || '') + '</td>'
|
|
+ '<td><button class="button wap-del-domain wap-btn-sm" data-domain="' + escHtml(d.name || d.domain || '') + '" data-id="' + (d.id || 0) + '">Remove</button></td></tr>';
|
|
});
|
|
html += '</tbody></table>';
|
|
$list.html(html);
|
|
|
|
$list.find('.wap-del-domain').on('click', function () {
|
|
if (!confirm('Remove this domain?')) return;
|
|
post('wooaapanel_acct_site_del_domain', $.extend({}, opts, {
|
|
domain: $(this).data('domain'),
|
|
site_id: $(this).data('id')
|
|
}), function () { loadDomains($panel); });
|
|
});
|
|
});
|
|
}
|
|
|
|
$(document).on('click', '.wap-add-domain-btn', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var domain = $panel.find('.wap-new-domain').val();
|
|
var $notice = $panel.find('.wap-domain-notice');
|
|
if (!domain) { inlineNotice($notice, 'Enter a domain name.', 'error'); return; }
|
|
post('wooaapanel_acct_site_add_domain', $.extend({}, siteOpts($panel), { domain: domain }), function (res) {
|
|
inlineNotice($notice, res.success ? 'Domain added!' : (res.data || 'Error.'), res.success ? 'ok' : 'error');
|
|
if (res.success) { $panel.find('.wap-new-domain').val(''); loadDomains($panel); }
|
|
});
|
|
});
|
|
|
|
/* ── PHP Version ──────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-php', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-php-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible') && !$sec.data('loaded')) {
|
|
$sec.data('loaded', 1);
|
|
loadPhpSection($panel, $sec);
|
|
}
|
|
});
|
|
|
|
function loadPhpSection($panel, $sec) {
|
|
var opts = siteOpts($panel);
|
|
$sec.find('.wap-php-current').text('Loading…');
|
|
post('wooaapanel_acct_site_php_get', opts, function (res) {
|
|
var current = res.data && res.data.version ? res.data.version : '?';
|
|
$sec.find('.wap-php-current').html('Current PHP version: <strong>' + escHtml(current) + '</strong>');
|
|
post('wooaapanel_acct_site_php_versions', opts, function (res2) {
|
|
var versions = res2.data && res2.data.version ? res2.data.version : [];
|
|
var opts2 = '';
|
|
$.each(versions, function (i, v) {
|
|
var ver = v.version || v;
|
|
opts2 += '<option value="' + escHtml(ver) + '"' + (ver == current ? ' selected' : '') + '>' + escHtml(ver) + '</option>';
|
|
});
|
|
$sec.find('.wap-php-select').html(opts2);
|
|
});
|
|
});
|
|
}
|
|
|
|
$(document).on('click', '.wap-php-set-btn', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-php-section');
|
|
var $notice = $sec.find('.wap-php-notice');
|
|
var version = $sec.find('.wap-php-select').val();
|
|
post('wooaapanel_acct_site_php_set', $.extend({}, siteOpts($panel), { version: version }), function (res) {
|
|
inlineNotice($notice, res.success ? 'PHP version updated!' : (res.data || 'Error.'), res.success ? 'ok' : 'error');
|
|
if (res.success) {
|
|
$sec.data('loaded', 0);
|
|
loadPhpSection($panel, $sec);
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ── URL Rewrite ──────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-rewrite', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-rewrite-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible') && !$sec.data('loaded')) {
|
|
$sec.data('loaded', 1);
|
|
post('wooaapanel_acct_site_rewrite_get', siteOpts($panel), function (res) {
|
|
var content = res.data && res.data.data ? res.data.data : (res.data || '');
|
|
$sec.find('.wap-rewrite-content').val(content);
|
|
});
|
|
}
|
|
});
|
|
|
|
$(document).on('click', '.wap-rewrite-save-btn', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-rewrite-section');
|
|
var $notice = $sec.find('.wap-rewrite-notice');
|
|
var content = $sec.find('.wap-rewrite-content').val();
|
|
post('wooaapanel_acct_site_rewrite_set', $.extend({}, siteOpts($panel), { content: content }), function (res) {
|
|
inlineNotice($notice, res.success ? 'Saved!' : (res.data || 'Error.'), res.success ? 'ok' : 'error');
|
|
});
|
|
});
|
|
|
|
/* ── SSL ──────────────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-ssl', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-ssl-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible') && !$sec.data('loaded')) {
|
|
$sec.data('loaded', 1);
|
|
post('wooaapanel_acct_site_ssl_get', siteOpts($panel), function (res) {
|
|
var d = res.data || {};
|
|
var html = '';
|
|
if (d.status !== undefined) {
|
|
var valid = d.status == 1 || d.status === true;
|
|
html += '<p>Status: <span class="' + (valid ? 'wap-ssl-valid' : 'wap-ssl-invalid') + '">' + (valid ? 'Active' : 'Inactive') + '</span></p>';
|
|
}
|
|
if (d.notAfter) html += '<p>Expires: ' + escHtml(d.notAfter) + '</p>';
|
|
if (d.issuer) html += '<p>Issuer: ' + escHtml(d.issuer) + '</p>';
|
|
if (d.subject) html += '<p>Domain: ' + escHtml(d.subject) + '</p>';
|
|
if (!html) html = '<pre>' + escHtml(JSON.stringify(d, null, 2)) + '</pre>';
|
|
$sec.find('.wap-ssl-info').html(html);
|
|
});
|
|
}
|
|
});
|
|
|
|
/* ── Server Info ──────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-server-info', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-server-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible') && !$sec.data('loaded')) {
|
|
$sec.data('loaded', 1);
|
|
post('wooaapanel_acct_server_info', siteOpts($panel), function (res) {
|
|
if (!res.success) { $sec.find('.wap-server-info').text(res.data || 'Error.'); return; }
|
|
var d = res.data;
|
|
var html = '<table class="woocommerce-table">'
|
|
+ '<tr><th>Server Name</th><td>' + escHtml(d.server_name || '') + '</td></tr>'
|
|
+ '<tr><th>Server Host / IP</th><td>' + escHtml(d.server_host || '') + '</td></tr>'
|
|
+ '<tr><th>Panel URL</th><td>' + escHtml(d.panel_url || '') + '</td></tr>';
|
|
if (d.panel_status) {
|
|
html += '<tr><th>Panel Status</th><td><pre style="margin:0;font-size:11px">' + escHtml(JSON.stringify(d.panel_status, null, 2)) + '</pre></td></tr>';
|
|
}
|
|
html += '</table>';
|
|
$sec.find('.wap-server-info').html(html);
|
|
});
|
|
}
|
|
});
|
|
|
|
/* ── DNS (WooDomains PowerDNS integration) ────────────────── */
|
|
|
|
if (pdnsActive) {
|
|
$(document).on('click', '.wap-load-dns', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var zone = $(this).data('zone');
|
|
var $sec = $panel.find('.wap-dns-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible')) {
|
|
loadDnsRecords($sec, zone);
|
|
}
|
|
});
|
|
|
|
function loadDnsRecords($sec, zone) {
|
|
$sec.find('.wap-dns-records-list').html('<em>Loading DNS records…</em>');
|
|
pdnsPost('woodomains_dns_get', { zone: zone }, function (res) {
|
|
if (!res.success) {
|
|
$sec.find('.wap-dns-records-list').html('<p>' + escHtml(res.data && res.data.message ? res.data.message : 'Error.') + '</p>');
|
|
return;
|
|
}
|
|
var records = res.data.records || [];
|
|
var html = '<table class="woocommerce-table shop_table"><thead><tr>'
|
|
+ '<th>Name</th><th>Type</th><th>TTL</th><th>Content</th><th></th>'
|
|
+ '</tr></thead><tbody>';
|
|
$.each(records, function (i, rr) {
|
|
var contents = $.map(rr.records, function (r) { return escHtml(r.content); }).join('<br>');
|
|
html += '<tr><td>' + escHtml(rr.name) + '</td><td>' + escHtml(rr.type) + '</td>'
|
|
+ '<td>' + rr.ttl + '</td><td>' + contents + '</td>'
|
|
+ '<td><button class="button wap-btn-sm wap-dns-del" data-name="' + escHtml(rr.name) + '" data-type="' + escHtml(rr.type) + '" data-zone="' + escHtml(zone) + '">Del</button></td></tr>';
|
|
});
|
|
html += '</tbody></table>';
|
|
$sec.find('.wap-dns-records-list').html(html);
|
|
|
|
$sec.find('.wap-dns-del').on('click', function () {
|
|
if (!confirm('Delete this DNS record?')) return;
|
|
pdnsPost('woodomains_dns_delete', {
|
|
zone: $(this).data('zone'),
|
|
name: $(this).data('name'),
|
|
type: $(this).data('type')
|
|
}, function () { loadDnsRecords($sec, zone); });
|
|
});
|
|
});
|
|
}
|
|
|
|
$(document).on('click', '.wap-dns-save-btn', function () {
|
|
var $panel = $(this).closest('.wap-site-panel');
|
|
var $sec = $panel.find('.wap-dns-section');
|
|
var zone = $sec.data('zone');
|
|
var $notice = $sec.find('.wap-dns-notice');
|
|
var contents = $sec.find('.wap-dns-content').val()
|
|
.split('\n').filter(function (s) { return s.trim(); });
|
|
|
|
pdnsPost('woodomains_dns_upsert', {
|
|
zone: zone,
|
|
name: $sec.find('.wap-dns-name').val(),
|
|
type: $sec.find('.wap-dns-type').val(),
|
|
ttl: parseInt($sec.find('.wap-dns-ttl').val(), 10) || 3600,
|
|
contents: contents
|
|
}, function (res) {
|
|
inlineNotice($notice, res.success ? 'Saved!' : (res.data && res.data.message ? res.data.message : 'Error.'), res.success ? 'ok' : 'error');
|
|
if (res.success) loadDnsRecords($sec, zone);
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════
|
|
DATABASE PANELS
|
|
══════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Backup ───────────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-db-backup-btn', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
var $notice = $panel.find('.wap-db-action-notice');
|
|
post('wooaapanel_acct_db_backup', dbOpts($panel), function (res) {
|
|
$notice.attr('class', 'wap-db-action-notice ' + (res.success ? 'ok' : 'error'))
|
|
.text(res.success ? 'Backup started!' : (res.data || 'Error.'));
|
|
});
|
|
});
|
|
|
|
/* ── Backup list ──────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-load-db-backups', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
var $sec = $panel.find('.wap-db-backups-section');
|
|
$sec.toggle();
|
|
if ($sec.is(':visible')) {
|
|
loadDbBackups($panel, $sec);
|
|
}
|
|
});
|
|
|
|
function loadDbBackups($panel, $sec) {
|
|
$sec.find('.wap-db-backups-list').html('<em>Loading…</em>');
|
|
post('wooaapanel_acct_db_backups', dbOpts($panel), function (res) {
|
|
var backups = res.data && res.data.data ? res.data.data : [];
|
|
if (!backups.length) { $sec.find('.wap-db-backups-list').html('<p>No backups found.</p>'); return; }
|
|
var html = '<table class="woocommerce-table"><thead><tr><th>File</th><th>Size</th><th>Date</th><th></th></tr></thead><tbody>';
|
|
$.each(backups, function (i, b) {
|
|
html += '<tr><td>' + escHtml(b.name || '') + '</td><td>' + escHtml(b.size || '') + '</td><td>' + escHtml(b.addtime || '') + '</td>'
|
|
+ '<td><button class="button wap-btn-sm wap-del-db-backup" data-id="' + (b.id || '') + '">Del</button></td></tr>';
|
|
});
|
|
html += '</tbody></table>';
|
|
$sec.find('.wap-db-backups-list').html(html);
|
|
|
|
$sec.find('.wap-del-db-backup').on('click', function () {
|
|
if (!confirm('Delete this backup?')) return;
|
|
post('wooaapanel_acct_db_backup_delete', $.extend({}, dbOpts($panel), { backup_id: $(this).data('id') }), function () {
|
|
loadDbBackups($panel, $sec);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ── Optimize ─────────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-db-optimize-btn', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
var $notice = $panel.find('.wap-db-action-notice');
|
|
post('wooaapanel_acct_db_optimize', dbOpts($panel), function (res) {
|
|
$notice.attr('class', 'wap-db-action-notice ' + (res.success ? 'ok' : 'error'))
|
|
.text(res.success ? 'Database optimized!' : (res.data || 'Error.'));
|
|
});
|
|
});
|
|
|
|
/* ── Repair ───────────────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-db-repair-btn', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
var $notice = $panel.find('.wap-db-action-notice');
|
|
post('wooaapanel_acct_db_repair', dbOpts($panel), function (res) {
|
|
$notice.attr('class', 'wap-db-action-notice ' + (res.success ? 'ok' : 'error'))
|
|
.text(res.success ? 'Database repaired!' : (res.data || 'Error.'));
|
|
});
|
|
});
|
|
|
|
/* ── Change Password ──────────────────────────────────────── */
|
|
|
|
$(document).on('click', '.wap-db-password-btn', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
$panel.find('.wap-db-password-section').toggle();
|
|
});
|
|
|
|
$(document).on('click', '.wap-db-pass-save-btn', function () {
|
|
var $panel = $(this).closest('.wap-db-panel');
|
|
var $sec = $panel.find('.wap-db-password-section');
|
|
var $notice = $sec.find('.wap-db-pass-notice');
|
|
var db_user = $sec.find('.wap-db-user').val();
|
|
var password = $sec.find('.wap-db-new-pass').val();
|
|
|
|
if (!db_user || !password) {
|
|
inlineNotice($notice, 'Database user and password are required.', 'error'); return;
|
|
}
|
|
|
|
post('wooaapanel_acct_db_password', $.extend({}, dbOpts($panel), { db_user: db_user, password: password }), function (res) {
|
|
inlineNotice($notice, res.success ? 'Password updated!' : (res.data || 'Error.'), res.success ? 'ok' : 'error');
|
|
if (res.success) { $sec.find('.wap-db-user, .wap-db-new-pass').val(''); }
|
|
});
|
|
});
|
|
|
|
})(jQuery);
|