Files
gniza4cp/whm/gniza-whm/settings.cgi
shuki 1459bd1b8b Initial commit: gniza backup & disaster recovery CLI + WHM plugin
Full-featured cPanel backup tool with SSH, S3, and Google Drive support.
Includes WHM plugin with Tailwind/DaisyUI UI, multi-remote management,
decoupled schedules, and account restore workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:39:39 +02:00

172 lines
7.0 KiB
Perl

#!/usr/local/cpanel/3rdparty/bin/perl
# gniza WHM Plugin — Main Config Editor
use strict;
use warnings;
use lib '/usr/local/cpanel/whostmgr/docroot/cgi/gniza-whm/lib';
use Whostmgr::HTMLInterface ();
use Cpanel::Form ();
use GnizaWHM::Config;
use GnizaWHM::Validator;
use GnizaWHM::UI;
my $CONFIG_FILE = '/etc/gniza/gniza.conf';
my $form = Cpanel::Form::parseform();
my $method = $ENV{'REQUEST_METHOD'} // 'GET';
# ── Handle POST ──────────────────────────────────────────────
my @errors;
my $saved = 0;
if ($method eq 'POST') {
unless (GnizaWHM::UI::verify_csrf_token($form->{'gniza_csrf'})) {
push @errors, 'Invalid or expired form token. Please try again.';
}
if (!@errors) {
my %data;
for my $key (@GnizaWHM::Config::MAIN_KEYS) {
$data{$key} = $form->{$key} // '';
}
my $validation_errors = GnizaWHM::Validator::validate_main_config(\%data);
if (@$validation_errors) {
@errors = @$validation_errors;
} else {
my ($ok, $err) = GnizaWHM::Config::write($CONFIG_FILE, \%data, \@GnizaWHM::Config::MAIN_KEYS);
if ($ok) {
GnizaWHM::UI::set_flash('success', 'Configuration saved successfully.');
print "Status: 302 Found\r\n";
print "Location: settings.cgi\r\n\r\n";
exit;
} else {
push @errors, "Failed to save config: $err";
}
}
}
}
# ── Render Page ──────────────────────────────────────────────
print "Content-Type: text/html\r\n\r\n";
Whostmgr::HTMLInterface::defheader('gniza Backup Manager — Settings', '', '/cgi/gniza-whm/settings.cgi');
print GnizaWHM::UI::page_header('Settings');
print GnizaWHM::UI::render_nav('settings.cgi');
print GnizaWHM::UI::render_flash();
if (@errors) {
print GnizaWHM::UI::render_errors(\@errors);
}
# Load current config (or use POST data if validation failed)
my $conf;
if (@errors && $method eq 'POST') {
$conf = {};
for my $key (@GnizaWHM::Config::MAIN_KEYS) {
$conf->{$key} = $form->{$key} // '';
}
} else {
$conf = GnizaWHM::Config::parse($CONFIG_FILE, 'main');
}
# Helper to output a text field row
sub field_text {
my ($key, $label, $hint, $extra) = @_;
$extra //= '';
my $val = GnizaWHM::UI::esc($conf->{$key} // '');
my $hint_html = $hint ? qq{ <span class="text-xs text-base-content/60 ml-2">$hint</span>} : '';
print qq{<div class="flex items-center gap-3 mb-2.5">\n};
print qq{ <label class="w-44 font-medium text-sm" for="$key">$label</label>\n};
print qq{ <input type="text" class="input input-bordered input-sm w-full max-w-xs" id="$key" name="$key" value="$val" $extra>\n};
print qq{ $hint_html\n} if $hint;
print qq{</div>\n};
}
# Helper to output a select field row
sub field_select {
my ($key, $label, $options_ref) = @_;
my $current = $conf->{$key} // '';
print qq{<div class="flex items-center gap-3 mb-2.5">\n};
print qq{ <label class="w-44 font-medium text-sm" for="$key">$label</label>\n};
print qq{ <select class="select select-bordered select-sm w-full max-w-xs" id="$key" name="$key">\n};
for my $opt (@$options_ref) {
my $sel = ($current eq $opt) ? ' selected' : '';
my $esc_opt = GnizaWHM::UI::esc($opt);
print qq{ <option value="$esc_opt"$sel>$esc_opt</option>\n};
}
print qq{ </select>\n};
print qq{</div>\n};
}
# ── Form ─────────────────────────────────────────────────────
print qq{<form method="POST" action="settings.cgi">\n};
print GnizaWHM::UI::csrf_hidden_field();
# Section: Local Settings
print qq{<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Local Settings</h2>\n};
field_text('TEMP_DIR', 'Working Directory', 'Default: /usr/local/gniza/workdir');
print qq{</div>\n</div>\n};
# Section: Account Filtering
print qq{<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Account Filtering</h2>\n};
my $inc_val = GnizaWHM::UI::esc($conf->{INCLUDE_ACCOUNTS} // '');
my $exc_val = GnizaWHM::UI::esc($conf->{EXCLUDE_ACCOUNTS} // '');
print qq{<div class="flex items-center gap-3 mb-2.5">\n};
print qq{ <label class="w-44 font-medium text-sm" for="INCLUDE_ACCOUNTS">Include Accounts</label>\n};
print qq{ <textarea class="textarea textarea-bordered textarea-sm w-full max-w-xs" id="INCLUDE_ACCOUNTS" name="INCLUDE_ACCOUNTS" placeholder="Comma-separated, empty = all">$inc_val</textarea>\n};
print qq{</div>\n};
print qq{<div class="flex items-center gap-3 mb-2.5">\n};
print qq{ <label class="w-44 font-medium text-sm" for="EXCLUDE_ACCOUNTS">Exclude Accounts</label>\n};
print qq{ <textarea class="textarea textarea-bordered textarea-sm w-full max-w-xs" id="EXCLUDE_ACCOUNTS" name="EXCLUDE_ACCOUNTS" placeholder="Comma-separated">$exc_val</textarea>\n};
print qq{</div>\n};
my @accounts = GnizaWHM::UI::get_cpanel_accounts();
if (@accounts) {
print qq{<div class="text-xs text-base-content/60 mt-2">};
print qq{Available accounts: } . GnizaWHM::UI::esc(join(', ', @accounts));
print qq{</div>\n};
}
print qq{</div>\n</div>\n};
# Section: Logging
print qq{<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Logging</h2>\n};
field_text('LOG_DIR', 'Log Directory', 'Default: /var/log/gniza');
field_select('LOG_LEVEL', 'Log Level', ['debug', 'info', 'warn', 'error']);
field_text('LOG_RETAIN', 'Log Retention (days)', 'Default: 90');
print qq{</div>\n</div>\n};
# Section: Notifications
print qq{<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Notifications</h2>\n};
field_text('NOTIFY_EMAIL', 'Email Address', 'Empty = disabled');
field_select('NOTIFY_ON', 'Notify On', ['always', 'failure', 'never']);
print qq{</div>\n</div>\n};
# Section: Advanced
print qq{<div class="card bg-base-100 shadow-sm border border-base-300 mb-6">\n<div class="card-body">\n};
print qq{<h2 class="card-title text-sm">Advanced</h2>\n};
field_text('LOCK_FILE', 'Lock File', 'Default: /var/run/gniza.lock');
field_text('SSH_TIMEOUT', 'SSH Timeout (seconds)', 'Default: 30');
field_text('SSH_RETRIES', 'SSH Retries', 'Default: 3');
field_text('RSYNC_EXTRA_OPTS', 'Extra rsync Options', 'Additional flags for rsync');
print qq{</div>\n</div>\n};
# Submit
print qq{<div class="flex gap-2 mt-4">\n};
print qq{ <button type="submit" class="btn btn-primary btn-sm">Save Settings</button>\n};
print qq{</div>\n};
print qq{</form>\n};
print GnizaWHM::UI::page_footer();
Whostmgr::HTMLInterface::footer();