diff --git a/cpanel/gniza/assets/gniza-cpanel-icon.png b/cpanel/gniza/assets/gniza-cpanel-icon.png index 27b1905..855df06 100644 Binary files a/cpanel/gniza/assets/gniza-cpanel-icon.png and b/cpanel/gniza/assets/gniza-cpanel-icon.png differ diff --git a/cpanel/gniza/assets/gniza-cpanel-icon.svg b/cpanel/gniza/assets/gniza-cpanel-icon.svg index fe5b81d..426b8e6 100644 --- a/cpanel/gniza/assets/gniza-cpanel-icon.svg +++ b/cpanel/gniza/assets/gniza-cpanel-icon.svg @@ -1,16 +1,11 @@ - - - - - - - - - - - - + + + + + + + diff --git a/cpanel/gniza/index.live.cgi b/cpanel/gniza/index.live.cgi index cbfc817..5f80e24 100644 --- a/cpanel/gniza/index.live.cgi +++ b/cpanel/gniza/index.live.cgi @@ -1,5 +1,5 @@ #!/usr/local/cpanel/3rdparty/bin/perl -# gniza cPanel Plugin — Restore Category Grid +# gniza cPanel Plugin — Step 1: Select Remote + Snapshot use strict; use warnings; @@ -27,6 +27,7 @@ my $remotes_raw = eval { Cpanel::AdminBin::Call::call('Gniza', 'Restore', 'LIST_ my @remotes = grep { $_ ne '' } split /\n/, $remotes_raw; print GnizaCPanel::UI::page_header('GNIZA Backups'); +print GnizaCPanel::UI::render_flash(); if (!@remotes) { print qq{
No backup remotes are available for restore. Please contact your server administrator.
\n}; @@ -36,76 +37,111 @@ if (!@remotes) { exit; } -# Category cards -my @categories = ( - { - type => 'account', - label => 'Full Backup', - desc => 'Restore entire account from backup', - icon => '', - }, - { - type => 'files', - label => 'Home Directory', - desc => 'Restore files and folders', - icon => '', - }, - { - type => 'database', - label => 'Databases', - desc => 'Restore MySQL databases', - icon => '', - }, - { - type => 'dbusers', - label => 'Database Users', - desc => 'Restore database users and grants', - icon => '', - }, - { - type => 'cron', - label => 'Cron Jobs', - desc => 'Restore scheduled tasks', - icon => '', - }, - { - type => 'domains', - label => 'Domains', - desc => 'Restore domain and DNS configuration', - icon => '', - }, - { - type => 'ssl', - label => 'SSL Certificates', - desc => 'Restore SSL certificates', - icon => '', - }, - { - type => 'mailbox', - label => 'Email Accounts', - desc => 'Restore mailboxes and email', - icon => '', - }, -); +print qq{
\n
\n}; +print qq{

Select Backup Source

\n}; -print qq{
\n}; +# Remote dropdown +print qq{
\n}; +print qq{ \n}; +print qq{ \n}; +print qq{
\n}; -for my $cat (@categories) { - my $type = GnizaCPanel::UI::esc($cat->{type}); - my $label = GnizaCPanel::UI::esc($cat->{label}); - my $desc = GnizaCPanel::UI::esc($cat->{desc}); - my $icon = $cat->{icon}; # Already safe SVG +# Snapshot dropdown (populated via AJAX) +print qq{
\n}; +print qq{ \n}; +print qq{ \n}; +print qq{
\n}; - print qq{\n}; - print qq{
\n}; - print qq{
$icon
\n}; - print qq{

$label

\n}; - print qq{

$desc

\n}; - print qq{
\n}; - print qq{
\n}; +print qq{
\n
\n}; + +print qq{
\n}; +print qq{ \n}; +print qq{
\n}; + +# JavaScript for snapshot loading and navigation +print <<"END_JS"; + +END_JS print GnizaCPanel::UI::page_footer(); print $cpanel->footer(); diff --git a/cpanel/gniza/restore.live.cgi b/cpanel/gniza/restore.live.cgi index ad9ab9a..9edb1c3 100644 --- a/cpanel/gniza/restore.live.cgi +++ b/cpanel/gniza/restore.live.cgi @@ -23,7 +23,7 @@ my $cpanel = Cpanel::LiveAPI->new(); END { $cpanel->end() if $cpanel } my $form = Cpanel::Form::parseform(); my $method = $ENV{'REQUEST_METHOD'} // 'GET'; -my $step = $form->{'step'} // '1'; +my $step = $form->{'step'} // ''; my %TYPE_LABELS = ( account => 'Full Backup', @@ -36,15 +36,17 @@ my %TYPE_LABELS = ( ssl => 'SSL Certificates', ); -my %SIMPLE_TYPES = map { $_ => 1 } qw(account cron); - # JSON endpoints if ($step eq 'fetch_snapshots') { handle_fetch_snapshots() } elsif ($step eq 'fetch_options') { handle_fetch_options() } elsif ($step eq '2') { handle_step2() } elsif ($step eq '3') { handle_step3() } elsif ($step eq '4') { handle_step4() } -else { handle_step1() } +else { + # Default: redirect to index + print "Status: 302 Found\r\n"; + print "Location: index.live.cgi\r\n\r\n"; +} exit; @@ -75,6 +77,12 @@ sub _adminbin_call { return (1, $result, ''); } +sub _uri_escape { + my $str = shift // ''; + $str =~ s/([^A-Za-z0-9\-._~])/sprintf("%%%02X", ord($1))/ge; + return $str; +} + # ── JSON: fetch snapshots ───────────────────────────────────── sub handle_fetch_snapshots { @@ -161,234 +169,215 @@ sub handle_fetch_options { print qq({"options":[$json_arr]}); } -# ── Step 1: Select Remote + Snapshot ────────────────────────── - -sub handle_step1 { - my $type = $form->{'type'} // 'account'; - unless (exists $TYPE_LABELS{$type}) { - $type = 'account'; - } - - print "Content-Type: text/html\r\n\r\n"; - print $cpanel->header('GNIZA Backups'); - print GnizaCPanel::UI::page_header('Restore: ' . ($TYPE_LABELS{$type} // $type)); - print GnizaCPanel::UI::render_flash(); - - # Get allowed remotes - my $remotes_raw = eval { Cpanel::AdminBin::Call::call('Gniza', 'Restore', 'LIST_ALLOWED_REMOTES') } // ''; - my @remotes = grep { $_ ne '' } split /\n/, $remotes_raw; - - unless (@remotes) { - print qq{
No backup remotes are available. Please contact your server administrator.
\n}; - print qq{Back\n}; - print GnizaCPanel::UI::page_footer(); - print $cpanel->footer(); - return; - } - - my $esc_type = GnizaCPanel::UI::esc($type); - my $type_label = GnizaCPanel::UI::esc($TYPE_LABELS{$type} // $type); - - print qq{
\n
\n}; - print qq{

Step 1: Select Source

\n}; - print qq{

Restore type: $type_label

\n}; - - # Remote dropdown - print qq{
\n}; - print qq{ \n}; - print qq{ \n}; - print qq{
\n}; - - # Snapshot dropdown (populated via AJAX) - print qq{
\n}; - print qq{ \n}; - print qq{ \n}; - print qq{
\n}; - - print qq{
\n
\n}; - - # For simple types, go directly to step 3 (confirm); others go to step 2 - my $next_step = $SIMPLE_TYPES{$type} ? '3' : '2'; - - print qq{
\n}; - print qq{ \n}; - print qq{ Back\n}; - print qq{
\n}; - - # JavaScript for snapshot loading and navigation - _print_step1_js($esc_type, $next_step); - - print GnizaCPanel::UI::page_footer(); - print $cpanel->footer(); -} - -sub _print_step1_js { - my ($esc_type, $next_step) = @_; - print <<"END_JS"; - -END_JS -} - -# ── Step 2: Select specific item ───────────────────────────── +# ── Step 2: Choose Restore Options ─────────────────────────── sub handle_step2 { - my $type = $form->{'type'} // 'account'; my $remote = $form->{'remote'} // ''; my $timestamp = $form->{'timestamp'} // ''; - $type = 'account' unless exists $TYPE_LABELS{$type}; - if ($remote eq '' || $timestamp eq '') { GnizaCPanel::UI::set_flash('error', 'Remote and snapshot are required.'); print "Status: 302 Found\r\n"; - print "Location: restore.live.cgi?type=$type\r\n\r\n"; + print "Location: index.live.cgi\r\n\r\n"; exit; } + # Fetch snapshots server-side via AdminBin + my ($ok, $stdout, $err) = _adminbin_call('LIST_SNAPSHOTS', $remote); + + my @snapshots; + if ($ok) { + for my $line (split /\n/, $stdout) { + if ($line =~ /^\s+(\d{4}-\d{2}-\d{2}T\d{6})/) { + push @snapshots, $1; + } + } + } + print "Content-Type: text/html\r\n\r\n"; print $cpanel->header('GNIZA Backups'); - print GnizaCPanel::UI::page_header('Restore: ' . ($TYPE_LABELS{$type} // $type)); + print GnizaCPanel::UI::page_header('Restore Options'); print GnizaCPanel::UI::render_flash(); - my $esc_type = GnizaCPanel::UI::esc($type); my $esc_remote = GnizaCPanel::UI::esc($remote); my $esc_timestamp = GnizaCPanel::UI::esc($timestamp); + print qq{
\n}; + print qq{\n}; + print qq{\n}; + print qq{
\n
\n}; - print qq{

Step 2: Select Items

\n}; - print qq{

Remote: $esc_remote · Snapshot: $esc_timestamp

\n}; + print qq{

Step 2: Choose Restore Options

\n}; + print qq{

Remote: $esc_remote

\n}; - if ($type eq 'files') { - _render_file_picker(); + # Snapshot dropdown + print qq{
\n}; + print qq{ \n}; + if (@snapshots) { + print qq{ \n}; + } else { + print qq{ No snapshots found\n}; } - elsif ($type eq 'database' || $type eq 'dbusers' || $type eq 'mailbox' || $type eq 'domains' || $type eq 'ssl') { - my $item_label = { - database => 'Databases', - dbusers => 'Database Users', - mailbox => 'Mailboxes', - domains => 'Domains', - ssl => 'SSL Certificates', - }->{$type}; - - print qq{

$item_label

\n}; - print qq{\n}; - print qq{
\n}; - print qq{ Loading...\n}; - print qq{
\n}; - } - elsif ($type eq 'cron') { - print qq{

Cron Jobs Preview

\n}; - print qq{
\n}; - print qq{ Loading...\n}; - print qq{
\n}; - } - - print qq{
\n
\n}; - - print qq{
\n}; - print qq{ \n}; - print qq{ Back\n}; print qq{
\n}; - _print_step2_js($esc_type, $esc_remote, $esc_timestamp); - - print GnizaCPanel::UI::page_footer(); - print $cpanel->footer(); -} - -sub _render_file_picker { + # Restore mode toggle print qq{
\n}; - print qq{ \n}; - print qq{
\n}; - print qq{ \n}; - print qq{ \n}; + print qq{ \n}; + print qq{
\n}; + print qq{ \n}; + print qq{ \n}; print qq{
\n}; print qq{
\n}; - print qq{

Leave empty to restore all files.

\n}; + + # Exclude paths section + print qq{
\n}; + print qq{
\n}; + print qq{

Directories and Files to Exclude

\n}; + print qq{
\n}; + print qq{ \n}; + print qq{ \n}; + print qq{ \n}; + print qq{
\n}; + print qq{

Exclude files and directories from restoration

\n}; + print qq{
\n}; + print qq{ \n}; + print qq{
\n}; + print qq{
\n}; + + # Exclude modal + print qq{\n}; + print qq{\n}; + print qq{\n}; + print qq{\n}; + + # Hidden field for account type in full mode + print qq{\n}; + + # Selective type buttons (hidden by default) + my @selective_types = ( + ['files', 'Files'], + ['database', 'Database'], + ['dbusers', 'Database Users'], + ['mailbox', 'Mailbox'], + ['cron', 'Cron'], + ['domains', 'Domains'], + ['ssl', 'SSL'], + ); + + print qq{\n}; # File browser modal print qq{\n}; @@ -405,47 +394,119 @@ sub _render_file_picker { print qq{ \n}; print qq{
\n}; print qq{
\n}; - print qq{\n}; + print qq{\n}; print qq{\n}; + + print qq{
\n\n}; + + if (@snapshots) { + print qq{
\n}; + print qq{ \n}; + print qq{ Back\n}; + print qq{
\n}; + } else { + print qq{Back\n}; + } + + print qq{\n}; + + # JavaScript for dynamic dropdowns and interactive elements + _print_step2_js($esc_remote); + + print GnizaCPanel::UI::page_footer(); + print $cpanel->footer(); } sub _print_step2_js { - my ($esc_type, $esc_remote, $esc_timestamp) = @_; + my ($esc_remote) = @_; print <<"END_JS"; END_JS } @@ -692,18 +869,34 @@ END_JS # ── Step 3: Confirmation ───────────────────────────────────── sub handle_step3 { - my $type = $form->{'type'} // 'account'; - my $remote = $form->{'remote'} // ''; - my $timestamp = $form->{'timestamp'} // ''; - my $path = $form->{'path'} // ''; - my $items = $form->{'items'} // ''; + my $remote = $form->{'remote'} // ''; + my $timestamp = $form->{'timestamp'} // ''; + my $path = $form->{'path'} // ''; + my $dbnames = $form->{'dbnames'} // ''; + my $dbuser_names = $form->{'dbuser_names'} // ''; + my $emails = $form->{'emails'} // ''; + my $domain_names = $form->{'domain_names'} // ''; + my $ssl_names = $form->{'ssl_names'} // ''; + my $exclude_paths = $form->{'exclude_paths'} // ''; - $type = 'account' unless exists $TYPE_LABELS{$type}; + # Collect selected types from type_* checkboxes + my @all_type_keys = qw(account files database mailbox cron dbusers domains ssl); + my @selected_types; + for my $t (@all_type_keys) { + push @selected_types, $t if ($form->{"type_$t"} // '') eq '1'; + } if ($remote eq '' || $timestamp eq '') { GnizaCPanel::UI::set_flash('error', 'Remote and snapshot are required.'); print "Status: 302 Found\r\n"; - print "Location: restore.live.cgi?type=$type\r\n\r\n"; + print "Location: index.live.cgi\r\n\r\n"; + exit; + } + + unless (@selected_types) { + GnizaCPanel::UI::set_flash('error', 'Please select at least one restore type.'); + print "Status: 302 Found\r\n"; + print "Location: restore.live.cgi?step=2&remote=" . _uri_escape($remote) . "×tamp=" . _uri_escape($timestamp) . "\r\n\r\n"; exit; } @@ -712,27 +905,55 @@ sub handle_step3 { print GnizaCPanel::UI::page_header('Restore: Confirm'); print GnizaCPanel::UI::render_flash(); - my $esc_type = GnizaCPanel::UI::esc($type); my $esc_remote = GnizaCPanel::UI::esc($remote); my $esc_timestamp = GnizaCPanel::UI::esc($timestamp); - my $type_label = GnizaCPanel::UI::esc($TYPE_LABELS{$type} // $type); my $user = GnizaCPanel::UI::esc(GnizaCPanel::UI::get_current_user()); + my $types_display = join(', ', map { GnizaCPanel::UI::esc($TYPE_LABELS{$_} // $_) } @selected_types); + print qq{
\n
\n}; print qq{

Step 3: Confirm Restore

\n}; print qq{
\n}; print qq{\n}; print qq{\n}; print qq{\n}; - print qq{\n}; + print qq{\n}; - if ($type eq 'files') { + # Show sub-field details for applicable types + if (grep { $_ eq 'files' } @selected_types) { my $path_display = $path ne '' ? GnizaCPanel::UI::esc($path) : 'All files'; print qq{\n}; - } elsif ($type ne 'account' && $type ne 'cron' && $items ne '') { - my $items_display = $items eq '__ALL__' ? 'All' : GnizaCPanel::UI::esc($items); - $items_display =~ s/,/, /g; - print qq{\n}; + } + if (grep { $_ eq 'database' } @selected_types) { + my $db_display = ($dbnames eq '' || $dbnames eq '__ALL__') ? 'All databases' : GnizaCPanel::UI::esc($dbnames); + $db_display =~ s/,/, /g; + print qq{\n}; + } + if (grep { $_ eq 'dbusers' } @selected_types) { + my $dbu_display = ($dbuser_names eq '' || $dbuser_names eq '__ALL__') ? 'All database users' : GnizaCPanel::UI::esc($dbuser_names); + $dbu_display =~ s/,/, /g; + print qq{\n}; + } + if (grep { $_ eq 'mailbox' } @selected_types) { + my $mb_display = ($emails eq '' || $emails eq '__ALL__') ? 'All mailboxes' : GnizaCPanel::UI::esc($emails); + $mb_display =~ s/,/, /g; + print qq{\n}; + } + if (grep { $_ eq 'domains' } @selected_types) { + my $dom_display = ($domain_names eq '' || $domain_names eq '__ALL__') ? 'All domains' : GnizaCPanel::UI::esc($domain_names); + $dom_display =~ s/,/, /g; + print qq{\n}; + } + if (grep { $_ eq 'ssl' } @selected_types) { + my $ssl_display = ($ssl_names eq '' || $ssl_names eq '__ALL__') ? 'All certificates' : GnizaCPanel::UI::esc($ssl_names); + $ssl_display =~ s/,/, /g; + print qq{\n}; + } + + if ($exclude_paths ne '') { + my $exclude_display = GnizaCPanel::UI::esc($exclude_paths); + $exclude_display =~ s/,/, /g; + print qq{\n}; } print qq{
Account$user
Remote$esc_remote
Snapshot$esc_timestamp
Restore Type$type_label
Restore Types$types_display
Path$path_display
Items$items_display
Database$db_display
Database Users$dbu_display
Mailbox$mb_display
Domains$dom_display
SSL$ssl_display
Exclude$exclude_display
\n}; @@ -740,11 +961,18 @@ sub handle_step3 { print qq{
\n}; print qq{\n}; - print qq{\n}; print qq{\n}; print qq{\n}; + for my $t (@selected_types) { + print qq{\n}; + } print qq{\n}; - print qq{\n}; + print qq{\n}; + print qq{\n}; + print qq{\n}; + print qq{\n}; + print qq{\n}; + print qq{\n}; print GnizaCPanel::UI::csrf_hidden_field(); print qq{
\n}; @@ -767,68 +995,112 @@ sub handle_step4 { exit; } - my $type = $form->{'type'} // 'account'; - my $remote = $form->{'remote'} // ''; - my $timestamp = $form->{'timestamp'} // ''; - my $path = $form->{'path'} // ''; - my $items = $form->{'items'} // ''; + my $remote = $form->{'remote'} // ''; + my $timestamp = $form->{'timestamp'} // ''; + my $path = $form->{'path'} // ''; + my $dbnames = $form->{'dbnames'} // ''; + my $dbuser_names = $form->{'dbuser_names'} // ''; + my $emails = $form->{'emails'} // ''; + my $domain_names = $form->{'domain_names'} // ''; + my $ssl_names = $form->{'ssl_names'} // ''; + my $exclude_paths = $form->{'exclude_paths'} // ''; - $type = 'account' unless exists $TYPE_LABELS{$type}; + # Collect selected types + my @all_type_keys = qw(account files database mailbox cron dbusers domains ssl); + my @selected_types; + for my $t (@all_type_keys) { + push @selected_types, $t if ($form->{"type_$t"} // '') eq '1'; + } + + unless (@selected_types) { + GnizaCPanel::UI::set_flash('error', 'No restore types selected.'); + print "Status: 302 Found\r\n"; + print "Location: index.live.cgi\r\n\r\n"; + exit; + } print "Content-Type: text/html\r\n\r\n"; print $cpanel->header('GNIZA Backups'); - print GnizaCPanel::UI::page_header('Restore: Results'); - - my $type_label = GnizaCPanel::UI::esc($TYPE_LABELS{$type}); + print GnizaCPanel::UI::page_header('Restore Results'); print qq{
\n
\n}; - print qq{

Restore Results: $type_label

\n}; + print qq{

Restore Results

\n}; my @results; - my %action_map = ( - account => 'RESTORE_ACCOUNT', - files => 'RESTORE_FILES', - database => 'RESTORE_DATABASE', - mailbox => 'RESTORE_MAILBOX', - cron => 'RESTORE_CRON', - dbusers => 'RESTORE_DBUSERS', - domains => 'RESTORE_DOMAINS', - ssl => 'RESTORE_SSL', - ); + for my $type (@selected_types) { + my $type_label = $TYPE_LABELS{$type} // $type; - my $action = $action_map{$type}; - unless ($action) { - push @results, { ok => 0, label => $type, msg => 'Unknown restore type' }; - _render_results(\@results); - print qq{
\n
\n}; - print qq{Back to Categories\n}; - print GnizaCPanel::UI::page_footer(); - print $cpanel->footer(); - return; - } - - if ($type eq 'account') { - my ($ok, $stdout, $err) = _adminbin_call($action, $remote, $timestamp, ''); - push @results, { ok => $ok, label => 'Full Account', msg => $ok ? $stdout : $err }; - } - elsif ($type eq 'cron') { - my ($ok, $stdout, $err) = _adminbin_call($action, $remote, $timestamp); - push @results, { ok => $ok, label => 'Cron Jobs', msg => $ok ? $stdout : $err }; - } - elsif ($type eq 'files') { - my ($ok, $stdout, $err) = _adminbin_call($action, $remote, $timestamp, $path, ''); - push @results, { ok => $ok, label => 'Files', msg => $ok ? $stdout : $err }; - } - elsif ($type eq 'database' || $type eq 'dbusers' || $type eq 'mailbox' || $type eq 'domains' || $type eq 'ssl') { - if ($items eq '' || $items eq '__ALL__') { - my ($ok, $stdout, $err) = _adminbin_call($action, $remote, $timestamp, ''); + if ($type eq 'account') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_ACCOUNT', $remote, $timestamp, $exclude_paths); push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; - } else { - for my $item (split /,/, $items) { - next if $item eq ''; - my ($ok, $stdout, $err) = _adminbin_call($action, $remote, $timestamp, $item); - push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } + elsif ($type eq 'files') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_FILES', $remote, $timestamp, $path, $exclude_paths); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } + elsif ($type eq 'cron') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_CRON', $remote, $timestamp); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } + elsif ($type eq 'database') { + if ($dbnames eq '' || $dbnames eq '__ALL__') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DATABASE', $remote, $timestamp, ''); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } else { + for my $item (split /,/, $dbnames) { + next if $item eq ''; + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DATABASE', $remote, $timestamp, $item); + push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } + } + } + elsif ($type eq 'dbusers') { + if ($dbuser_names eq '' || $dbuser_names eq '__ALL__') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DBUSERS', $remote, $timestamp, ''); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } else { + for my $item (split /,/, $dbuser_names) { + next if $item eq ''; + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DBUSERS', $remote, $timestamp, $item); + push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } + } + } + elsif ($type eq 'mailbox') { + if ($emails eq '' || $emails eq '__ALL__') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_MAILBOX', $remote, $timestamp, ''); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } else { + for my $item (split /,/, $emails) { + next if $item eq ''; + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_MAILBOX', $remote, $timestamp, $item); + push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } + } + } + elsif ($type eq 'domains') { + if ($domain_names eq '' || $domain_names eq '__ALL__') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DOMAINS', $remote, $timestamp, ''); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } else { + for my $item (split /,/, $domain_names) { + next if $item eq ''; + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_DOMAINS', $remote, $timestamp, $item); + push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } + } + } + elsif ($type eq 'ssl') { + if ($ssl_names eq '' || $ssl_names eq '__ALL__') { + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_SSL', $remote, $timestamp, ''); + push @results, { ok => $ok, label => $type_label, msg => $ok ? $stdout : $err }; + } else { + for my $item (split /,/, $ssl_names) { + next if $item eq ''; + my ($ok, $stdout, $err) = _adminbin_call('RESTORE_SSL', $remote, $timestamp, $item); + push @results, { ok => $ok, label => $item, msg => $ok ? $stdout : $err }; + } } } } @@ -837,7 +1109,7 @@ sub handle_step4 { print qq{
\n
\n}; - print qq{Back to Categories\n}; + print qq{Back to Home\n}; print GnizaCPanel::UI::page_footer(); print $cpanel->footer();