From 6ecba2ae4360f66bc99ce4eec7cf38eeb2db8180 Mon Sep 17 00:00:00 2001 From: shuki Date: Thu, 5 Mar 2026 03:43:00 +0200 Subject: [PATCH] Load restore account dropdown from remote backups via AJAX The WHM restore page now populates the account dropdown dynamically from the selected remote, making terminated/removed accounts visible and restorable. Accounts not on the local server show "(terminated)". Co-Authored-By: Claude Opus 4.6 --- bin/gniza | 16 +++ whm/gniza-whm/lib/GnizaWHM/Runner.pm | 1 + whm/gniza-whm/restore.cgi | 149 ++++++++++++++++++++++++--- 3 files changed, 150 insertions(+), 16 deletions(-) diff --git a/bin/gniza b/bin/gniza index 7950047..0a1a598 100755 --- a/bin/gniza +++ b/bin/gniza @@ -702,6 +702,22 @@ cmd_list() { validate_config || die "Invalid configuration" init_logging + # list accounts subcommand + if [[ "${1:-}" == "accounts" ]]; then + shift + local remote_flag="" + remote_flag=$(get_opt remote "$@" 2>/dev/null) || true + [[ -z "$remote_flag" ]] && die "Usage: gniza list accounts --remote=NAME" + local remotes; remotes=$(get_target_remotes "$remote_flag") || die "Invalid remote" + local rname; rname=$(head -1 <<< "$remotes") + _save_remote_globals + load_remote "$rname" || die "Failed to load remote: $rname" + _test_connection || die "Connection failed to remote: $rname" + list_remote_accounts + _restore_remote_globals + return 0 + fi + local single_account="" single_account=$(get_opt account "$@" 2>/dev/null) || true diff --git a/whm/gniza-whm/lib/GnizaWHM/Runner.pm b/whm/gniza-whm/lib/GnizaWHM/Runner.pm index a3cffa2..8217dcb 100644 --- a/whm/gniza-whm/lib/GnizaWHM/Runner.pm +++ b/whm/gniza-whm/lib/GnizaWHM/Runner.pm @@ -39,6 +39,7 @@ my @ALLOWED = ( { cmd => 'restore', subcmd => 'list-ssl', args => [qr/^[a-z][a-z0-9_-]*$/] }, # list { cmd => 'list', subcmd => undef, args => [] }, + { cmd => 'list', subcmd => 'accounts', args => [] }, ); # Named option patterns (--key=value). diff --git a/whm/gniza-whm/restore.cgi b/whm/gniza-whm/restore.cgi index cf96f24..b48d3e7 100644 --- a/whm/gniza-whm/restore.cgi +++ b/whm/gniza-whm/restore.cgi @@ -31,6 +31,7 @@ my %TYPE_LABELS = ( my %SIMPLE_TYPES = map { $_ => 1 } qw(account cron cpconfig); if ($step eq 'fetch_options') { handle_fetch_options() } +elsif ($step eq 'fetch_accounts') { handle_fetch_accounts() } elsif ($step eq '2') { handle_step2() } elsif ($step eq '3') { handle_step3() } elsif ($step eq '4') { handle_step4() } @@ -106,6 +107,48 @@ sub handle_fetch_options { print qq({"options":[$json_arr]}); } +# ── JSON endpoint: fetch accounts from remote ────────────────── + +sub handle_fetch_accounts { + my $remote = $form->{'remote'} // ''; + + print "Content-Type: application/json\r\n\r\n"; + + if ($remote eq '') { + print qq({"error":"Remote is required"}); + return; + } + + my ($ok, $stdout, $stderr) = GnizaWHM::Runner::run( + 'list', 'accounts', [], { remote => $remote } + ); + + unless ($ok) { + my $msg = $stderr // 'Failed to list accounts'; + $msg =~ s/\\/\\\\/g; + $msg =~ s/"/\\"/g; + $msg =~ s/\n/\\n/g; + $msg =~ s/\r/\\r/g; + print qq({"error":"$msg"}); + return; + } + + # Get local cPanel accounts for terminated detection + my %local_accounts = map { $_ => 1 } GnizaWHM::UI::get_cpanel_accounts(); + + my @accounts; + for my $line (split /\n/, $stdout) { + $line =~ s/^\s+|\s+$//g; + next unless $line =~ /^[a-z][a-z0-9_-]*$/; + my $terminated = $local_accounts{$line} ? 0 : 1; + $line =~ s/\\/\\\\/g; + $line =~ s/"/\\"/g; + push @accounts, qq({"name":"$line","terminated":$terminated}); + } + + print '{"accounts":[' . join(',', @accounts) . ']}'; +} + # ── Step 1: Select Account + Remote ───────────────────────── sub handle_step1 { @@ -125,7 +168,7 @@ sub handle_step1 { return; } - print qq{
\n}; + print qq{\n}; print qq{\n}; print qq{
\n
\n}; @@ -134,7 +177,10 @@ sub handle_step1 { # Remote dropdown print qq{
\n}; print qq{ \n}; - print qq{ \n}; + if (@remotes > 1) { + print qq{ \n}; + } for my $r (@remotes) { my $esc = GnizaWHM::UI::esc($r); print qq{ \n}; @@ -142,31 +188,102 @@ sub handle_step1 { print qq{ \n}; print qq{
\n}; - # Account input - my @accounts = GnizaWHM::UI::get_cpanel_accounts(); + # Account dropdown (populated via AJAX) print qq{
\n}; print qq{ \n}; - if (@accounts) { - print qq{ \n}; - } else { - print qq{ \n}; - } + print qq{ \n}; + print qq{ \n}; print qq{
\n}; print qq{
\n
\n}; print qq{
\n}; - print qq{ \n}; + print qq{ \n}; print qq{
\n}; print qq{
\n}; + # JavaScript for dynamic account loading + my $single_remote = (@remotes == 1) ? 'true' : 'false'; + print <<'JSEOF'; +\n"; + print GnizaWHM::UI::page_footer(); Whostmgr::HTMLInterface::footer(); }