Place the SVG icon next to the tab bar in a flex row instead of
rendering it as a separate centered block above the navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uncheck and disable the toggle when switching to Selective so
the value cannot carry through to the confirmation step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use hidden class toggle instead of inline style.display, since
Tailwind CSS is built with the important flag.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Scans each log file for [ERROR] and [WARN] markers and displays
a color-coded badge in the logs table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /scripts/removeacct script was failing with "You do not have
permission to remove that account" even when running as root. Switch
to whmapi1 removeacct which uses the WHM API with proper root
authentication context. Also check the whmapi1 result field since
whmapi1 returns exit code 0 even on logical failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cPanel's removeacct expects username before flags. Also capture and
log the command output to aid debugging if termination still fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The /scripts/removeacct command only accepts --force and --keepdns.
The --skipbw flag is not a valid option and was causing account
termination to fail during full account restore with terminate enabled.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the 8-card category grid with a unified restore workflow:
- index.live.cgi: now serves as Step 1 (remote + snapshot selection)
- restore.live.cgi: Step 2 (Full Account/Selective mode toggle with
type checkboxes, exclude paths, file browser), Step 3 (multi-type
confirmation), Step 4 (multi-type execution via AdminBin)
Also update cPanel plugin icon from gniza.svg source.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AdminBin modules run as root, so $ENV{'REMOTE_USER'} is not set.
The correct way to get the authenticated cPanel user is via the
parent class method get_caller_username().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Perl's qq{} delimiter matches balanced braces, which conflicted with
JavaScript curly braces, producing empty function bodies. Converted
_print_step1_js and _print_step2_js to heredoc blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use $cpanel->header() and $cpanel->footer() from LiveAPI to wrap
plugin content in cPanel's standard layout with sidebar navigation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cPanel's live engine provides the HTTP headers and page chrome
(sidebar, topbar). CGI should not output its own Content-Type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
__PACKAGE__->run() was called before my variables were declared,
so $MAIN_CONFIG and $REMOTES_DIR were undef when action methods ran.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cPanel's live engine requires .live.cgi files to create a
Cpanel::LiveAPI connection. Without it, the engine cannot
establish communication with the CGI subprocess.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cPanel's adminbin framework requires the module to be directly
executable with a shebang line, and Script::Call modules need
__PACKAGE__->run() to bootstrap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Variables declared with 'my' inside open3() were scoped to that call,
causing 'Global symbol requires explicit package name' errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SVG had negative coordinates that rendered off-screen in cPanel's
sprite sheet. Export to clean 48x48 PNG (2.8KB) instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server box with data rows (navy) and circular restore arrow (copper)
matching gniza brand colors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 378KB VTracer-traced logo with a clean 1KB 48x48 SVG icon
for cPanel's icon system. Update install.json, install.sh, and
uninstall.sh to reference the new icon. Also update README with
skip-suspended flag and schedule config fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Old versions stored CSRF/flash as plain files at the directory path.
New code expects directories. _ensure_dir now removes conflicting
plain files left by older versions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add fallback write when O_EXCL _safe_write fails for CSRF tokens
(ensures token is always persisted to disk)
- Update SMTP test JS to sync new CSRF token into main form hidden field
(prevents stale token after SMTP test consumes the original)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
install_plugin requires a tar.gz archive, not a raw JSON file. Also copies
install.json to the plugin directory so uninstall_plugin can reference it.
Includes CLAUDE.md documentation updates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Terminate First" toggle to restore page (UI, Runner, CLI, lib)
- When enabled, removes existing cPanel account before restoring
- Add GNIZA Backup SVG logo to WHM plugin header (inline base64)
- Copy uninstall.sh to /usr/local/gniza/ during installation
- Update CLAUDE.md with new restore params and Runner options
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Restores now always merge into existing accounts (--force). The
terminate-and-recreate option is removed from CLI, restore library,
Runner allowlist, and WHM UI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Always defaults to merge (overwrite) strategy. The terminate & re-create
option is removed from the UI to simplify the restore workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fall back to default '30' when RETENTION_COUNT is set to empty string,
not just when the key is missing from the config.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Widen label to w-52 with whitespace-nowrap to prevent the info icon
from wrapping to a new line. Change tooltip position from right to top.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --exclude flag to restore account/files commands to skip specific
paths during homedir restoration (rsync --exclude / rclone --exclude)
- Add exclude paths UI in WHM restore form (step 2 tag input + modal,
step 3 summary, step 4 command building)
- Add rclone_from_remote_filtered() for passing extra args to rclone copy
- Add _build_exclude_args() helper in restore.sh
- Add exclude pattern to Runner.pm allowlist
- Add skip-suspended flag and schedule configuration enhancements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds SKIP_SUSPENDED config key and --skip-suspended CLI flag that
excludes suspended accounts (detected via /var/cpanel/suspended/)
from backups. Follows the same pattern as the existing SYSBACKUP
toggle across all layers: config, schedule loader, cron builder,
CLI flag parsing, and WHM UI (table toggle, AJAX handler, form card).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Runner.pm: extract _validate()/_build_cmd_line(), add run_async() that
forks a detached child via setsid() to run commands in background
- restore.cgi: handle_step4() builds commands array and uses run_async()
instead of blocking synchronous execution, redirects to logs.cgi
- logs.cgi: add auto-refresh JS (10s list view, 5s file view with
auto-scroll) that polls index.cgi?action=status while gniza is running
- index.cgi: add live status card with AJAX polling and JSON endpoint
- Cron/schedule: redirect cron output to /dev/null (gniza has own logs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses DaisyUI collapse component so the SSH guidance is hidden
by default and expandable on click.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>