Add Run Now button to schedules page

Adds a "Run Now" button in each schedule's Actions column that
triggers the backup in the background, logging to the same cron
log file. Forks the process and redirects immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shuki
2026-03-04 04:30:42 +02:00
parent afe8c856e2
commit 425085f018

View File

@@ -22,6 +22,7 @@ if ($action eq 'add') { handle_add() }
elsif ($action eq 'edit') { handle_edit() }
elsif ($action eq 'delete') { handle_delete() }
elsif ($action eq 'toggle_cron') { handle_toggle_cron() }
elsif ($action eq 'run_now') { handle_run_now() }
else { handle_list() }
exit;
@@ -66,6 +67,13 @@ sub handle_list {
print qq{<input type="checkbox" class="toggle toggle-sm toggle-success" data-schedule="$esc_name" onchange="gnizaToggleCron(this)"$checked>};
print qq{</td>};
print qq{<td>};
print qq{<div class="flex items-center gap-2">};
print qq{<form method="POST" action="schedules.cgi" style="display:inline">};
print qq{<input type="hidden" name="action" value="run_now">};
print qq{<input type="hidden" name="name" value="$esc_name">};
print GnizaWHM::UI::csrf_hidden_field();
print qq{<button type="submit" class="btn btn-secondary btn-sm" onclick="return confirm('Run backup for schedule $esc_name now?')">Run Now</button>};
print qq{</form>};
print qq{<a href="schedules.cgi?action=edit&amp;name=$esc_name" class="btn btn-ghost btn-sm">Edit</a>};
print qq{<form method="POST" action="schedules.cgi" style="display:inline">};
print qq{<input type="hidden" name="action" value="delete">};
@@ -73,6 +81,7 @@ sub handle_list {
print GnizaWHM::UI::csrf_hidden_field();
print qq{<button type="submit" class="btn btn-error btn-sm" onclick="return confirm('Delete schedule $esc_name?')">Delete</button>};
print qq{</form>};
print qq{</div>};
print qq{</td>};
print qq{</tr>\n};
}
@@ -322,6 +331,78 @@ sub handle_delete {
exit;
}
# ── Run Now ──────────────────────────────────────────────────
sub handle_run_now {
if ($method ne 'POST') {
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
unless (GnizaWHM::UI::verify_csrf_token($form->{'gniza_csrf'})) {
GnizaWHM::UI::set_flash('error', 'Invalid or expired form token.');
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
my $name = $form->{'name'} // '';
my $name_err = GnizaWHM::Validator::validate_schedule_name($name);
if ($name_err) {
GnizaWHM::UI::set_flash('error', 'Invalid schedule name.');
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
my $conf_path = GnizaWHM::UI::schedule_conf_path($name);
unless (-f $conf_path) {
GnizaWHM::UI::set_flash('error', "Schedule '$name' not found.");
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
my $conf = GnizaWHM::Config::parse($conf_path, 'schedule');
my $remotes = $conf->{REMOTES} // '';
$remotes =~ s/^\s+|\s+$//g;
# Build command
my @cmd = ('/usr/local/bin/gniza', 'backup');
if ($remotes ne '') {
push @cmd, "--remote=$remotes";
}
my $log_file = "/var/log/gniza/cron-${name}.log";
# Fork to background
my $pid = fork();
if (!defined $pid) {
GnizaWHM::UI::set_flash('error', "Failed to fork backup process: $!");
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
if ($pid == 0) {
# Child: detach and exec
close STDIN;
close STDOUT;
close STDERR;
open STDOUT, '>>', $log_file;
open STDERR, '>&', \*STDOUT;
exec @cmd;
exit 1;
}
# Parent: don't wait, redirect immediately
GnizaWHM::UI::set_flash('success', "Backup started for schedule '$name'. Check Logs for progress.");
print "Status: 302 Found\r\n";
print "Location: schedules.cgi\r\n\r\n";
exit;
}
# ── Toggle Cron ──────────────────────────────────────────────
sub handle_toggle_cron {