diff --git a/CLAUDE.md b/CLAUDE.md index 2c1c9a4..fdd3461 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -52,6 +52,7 @@ whm/ ├── restore.cgi # Restore workflow — 4-step form (account → snapshot → confirm → execute) ├── assets/ │ ├── gniza-whm.css # Built Tailwind/DaisyUI CSS (committed, ~58KB) + │ ├── gniza-logo.svg # SVG logo (embedded as data URI in page header) │ └── src/ │ ├── input.css # Tailwind v4 entry point with DaisyUI plugin │ ├── safelist.html # Class safelist for Tailwind content scanner @@ -384,7 +385,7 @@ All restore functions dispatch by `_is_rclone_mode` — using `rclone_from_remot | Function | Description | |----------|-------------| -| `restore_full_account(user, ts)` | Full account restore from snapshot | +| `restore_full_account(user, ts, terminate, exclude)` | Full account restore from snapshot. If `terminate=true`, removes existing account via `/scripts/removeacct` before restoring. Otherwise merges with `--force`. | | `restore_files(user, ts, path)` | Restore specific files/directories | | `restore_database(user, ts, dbname)` | Restore a MySQL database from snapshot | | `restore_mailbox(user, email, ts)` | Restore a mailbox (parses email → mail/domain/user path) | @@ -442,7 +443,7 @@ Pattern-based command runner for safe CLI execution from the WHM UI. Each allowe | `run($cmd, $subcmd, \@args, \%opts)` | Validate against allowlist and execute gniza CLI | Allowed commands: `restore account/files/database/mailbox/list-databases/list-mailboxes`, `list`. -Named option patterns: `--remote`, `--timestamp`, `--path`, `--account`. +Named option patterns: `--remote`, `--timestamp`, `--path`, `--account`, `--terminate`, `--exclude`. ### GnizaWHM::Config @@ -525,6 +526,31 @@ _restore_remote_globals **NEVER write custom CSS.** Always use Tailwind utility classes and DaisyUI components exclusively. All styling must be done through class attributes in HTML — no custom CSS rules, no `\n} - . qq{
\n}; + . qq{
\n} + . $logo_html; } sub _unwrap_layers { diff --git a/whm/gniza-whm/restore.cgi b/whm/gniza-whm/restore.cgi index c3d4217..cf96f24 100644 --- a/whm/gniza-whm/restore.cgi +++ b/whm/gniza-whm/restore.cgi @@ -247,6 +247,12 @@ sub handle_step2 { print qq{
\n}; print qq{
\n}; + # Terminate toggle (only visible in Full Account mode) + print qq{
\n}; + print qq{ \n}; + print qq{ \n}; + print qq{
\n}; + # Exclude paths (visible in both Full Account and Selective modes) print qq{
\n}; print qq{
\n}; @@ -443,6 +449,7 @@ function gnizaModeChanged() { var mode = document.querySelector('input[name="restore_mode"]:checked').value; var selective = mode === 'selective'; document.getElementById('selective-panel').hidden = !selective; + document.getElementById('terminate-panel').hidden = selective; document.getElementById('type_account_hidden').disabled = selective; if (selective) { gnizaTypesChanged(); @@ -851,6 +858,7 @@ sub handle_step3 { my $domain_names = $form->{'domain_names'} // ''; my $ssl_names = $form->{'ssl_names'} // ''; my $exclude_paths = $form->{'exclude_paths'} // ''; + my $terminate = $form->{'terminate'} // ''; # Collect selected types from type_* checkboxes my @all_type_keys = qw(account files database mailbox cron dbusers cpconfig domains ssl); @@ -912,6 +920,10 @@ sub handle_step3 { print qq{SSL$ssl_display\n}; } + if ($terminate eq '1' && grep { $_ eq 'account' } @selected_types) { + print qq{Terminate FirstYes — account will be removed before restore\n}; + } + if ($exclude_paths ne '') { my $exclude_display = GnizaWHM::UI::esc($exclude_paths); $exclude_display =~ s/,/, /g; @@ -936,6 +948,7 @@ sub handle_step3 { print qq{\n}; print qq{\n}; print qq{\n}; + print qq{\n}; print GnizaWHM::UI::csrf_hidden_field(); print qq{
\n}; @@ -968,6 +981,7 @@ sub handle_step4 { my $domain_names = $form->{'domain_names'} // ''; my $ssl_names = $form->{'ssl_names'} // ''; my $exclude_paths = $form->{'exclude_paths'} // ''; + my $terminate = $form->{'terminate'} // ''; # Collect selected types my @all_type_keys = qw(account files database mailbox cron dbusers cpconfig domains ssl); @@ -990,7 +1004,10 @@ sub handle_step4 { $opts{timestamp} = $timestamp if $timestamp ne ''; if ($SIMPLE_TYPES{$type}) { - $opts{exclude} = $exclude_paths if $exclude_paths ne '' && $type eq 'account'; + if ($type eq 'account') { + $opts{exclude} = $exclude_paths if $exclude_paths ne ''; + $opts{terminate} = '1' if $terminate eq '1'; + } push @commands, ['restore', $type, [$account], {%opts}]; } elsif ($type eq 'files') { $opts{path} = $path if $path ne '';