Diff -- /var/www/vhosts/3dshawn.com/site1/file_monitors.cgi
Diff

/var/www/vhosts/3dshawn.com/site1/file_monitors.cgi

added on local at 2026-07-13 16:38:18

Added
+123
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 81f101226a6f
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1#!/usr/bin/perl
2use strict; use warnings; use CGI ();
3use MODS::Config; use MODS::DBConnect; use MODS::Template; use MODS::PageWrapper;
4my $cgi = CGI->new; my $db = MODS::DBConnect->new; my $tpl = MODS::Template->new;
5$|=1;
6my $dbh = $db->db_connect or die "DB connect failed\n";
7
8if (($ENV{REQUEST_METHOD} || '') eq 'POST' && $cgi->param('save')) {
9 my $q_name = $dbh->quote($cgi->param('scan_name') || '');
10 my $q_path = $dbh->quote($cgi->param('scan_path') || '');
11 my $q_ig = $dbh->quote($cgi->param('ignore_list') || '.git/,node_modules/,*.log,*.tmp,.DS_Store');
12 my $q_ft = $dbh->quote($cgi->param('file_type_filter') || '');
13 my $status = $cgi->param('status') ? 1 : 0;
14 my $srv = int($cgi->param('server_id') || 1);
15 my $ret = int($cgi->param('retention_days') || 0);
16 my $ret_expr = $ret > 0 ? $ret : 'NULL';
17 $db->db_readwrite($dbh, qq~
18 INSERT INTO FILE_MONITOR_SETTINGS
19 (scan_name, scan_path, ignore_list, file_type_filter, status, server_id, retention_days)
20 VALUES ($q_name, $q_path, $q_ig, $q_ft, $status, $srv, $ret_expr)
21 ~, __FILE__, __LINE__);
22 my $new_row = $db->db_readwrite($dbh, "SELECT LAST_INSERT_ID() AS id", __FILE__, __LINE__);
23 my $new_mid = $new_row && $new_row->{id};
24
25 # Kick an immediate baseline scan for JUST this monitor so the operator
26 # doesn't wait 2-5 minutes for the next cron tick. Picks the right
27 # scanner based on the target server's kind. Forks + double-forks so
28 # the browser gets the redirect immediately; scanner runs detached.
29 if ($status && $new_mid) {
30 my $srv_row = $db->db_readwrite($dbh, qq~
31 SELECT kind FROM SERVERS WHERE server_id = $srv LIMIT 1
32 ~, __FILE__, __LINE__);
33 my $scanner = ($srv_row && ($srv_row->{kind} // '') eq 'ssh_agent')
34 ? '_agent_scan.pl'
35 : '_file_scan.pl';
36 _spawn_baseline_scan($scanner, $new_mid);
37 }
38 print "Status: 302 Found\nLocation: /file_monitors.cgi?saved=1&mid=$new_mid\n\n"; exit;
39}
40
41sub _spawn_baseline_scan {
42 my ($scanner, $mid) = @_;
43 my $dir = '/var/www/vhosts/3dshawn.com/site1';
44 return unless -f "$dir/$scanner";
45 $mid = int($mid || 0);
46 return unless $mid;
47 # Detach via shell: `setsid nohup ... &`. Under Apache's cgid handler
48 # a plain fork() gets reaped when the CGI process exits, so we hand
49 # the child off to init explicitly via setsid + nohup.
50 my $cmd = "setsid /usr/bin/nohup /usr/bin/perl -I$dir $dir/$scanner --mid=$mid "
51 . "</dev/null >/dev/null 2>&1 &";
52 system($cmd);
53}
54
55# POST-update: change per-monitor retention_days
56if (($ENV{REQUEST_METHOD} || '') eq 'POST' && $cgi->param('update_retention')) {
57 my $mid = int($cgi->param('mid') || 0);
58 my $ret = int($cgi->param('retention_days') || 0);
59 my $ret_expr = $ret > 0 ? $ret : 'NULL';
60 $db->db_readwrite($dbh,
61 "UPDATE FILE_MONITOR_SETTINGS SET retention_days = $ret_expr WHERE file_monitor_list_id = $mid",
62 __FILE__, __LINE__);
63 print "Status: 302 Found\nLocation: /file_monitors.cgi?updated=1\n\n"; exit;
64}
65
66# POST-update: quiet hours
67if (($ENV{REQUEST_METHOD} || '') eq 'POST' && $cgi->param('update_quiet_hours')) {
68 my $mid = int($cgi->param('mid') || 0);
69 my $qs = $cgi->param('quiet_hours_start') // '';
70 my $qe = $cgi->param('quiet_hours_end') // '';
71 # Empty string = clear the quiet hours (both must be empty together)
72 my $qs_expr = (length $qs && $qs =~ /^\d{2}:\d{2}(:\d{2})?$/) ? $dbh->quote($qs) : 'NULL';
73 my $qe_expr = (length $qe && $qe =~ /^\d{2}:\d{2}(:\d{2})?$/) ? $dbh->quote($qe) : 'NULL';
74 $db->db_readwrite($dbh, qq~
75 UPDATE FILE_MONITOR_SETTINGS
76 SET quiet_hours_start = $qs_expr, quiet_hours_end = $qe_expr
77 WHERE file_monitor_list_id = $mid
78 ~, __FILE__, __LINE__);
79 print "Status: 302 Found\nLocation: /file_monitors.cgi?updated=1\n\n"; exit;
80}
81
82print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
83# Probe quiet_hours columns so pre-wave7 schemas still render this page
84my $has_qh = $db->db_readwrite($dbh, q~
85 SELECT 1 AS ok FROM INFORMATION_SCHEMA.COLUMNS
86 WHERE TABLE_SCHEMA=DATABASE()
87 AND TABLE_NAME='FILE_MONITOR_SETTINGS'
88 AND COLUMN_NAME='quiet_hours_start'
89~, __FILE__, __LINE__);
90my $qh_sel = ($has_qh && $has_qh->{ok})
91 ? ', TIME_FORMAT(quiet_hours_start, "%H:%i") AS quiet_hours_start,
92 TIME_FORMAT(quiet_hours_end, "%H:%i") AS quiet_hours_end'
93 : ', NULL AS quiet_hours_start, NULL AS quiet_hours_end';
94
95my @rows = $db->db_readwrite_multiple($dbh, qq~
96 SELECT file_monitor_list_id AS id, scan_name, scan_path, ignore_list, file_type_filter,
97 status, retention_days,
98 DATE_FORMAT(last_scanned, '%b %d %H:%i') AS last_h
99 $qh_sel
100 FROM FILE_MONITOR_SETTINGS ORDER BY file_monitor_list_id ASC
101~, __FILE__, __LINE__);
102foreach my $r (@rows) {
103 $r->{status_pill} = $r->{status} ? 'pill-ok' : 'pill-mute';
104 $r->{status_lbl} = $r->{status} ? 'ACTIVE' : 'DISABLED';
105 $r->{ignore_preview} = $r->{ignore_list} ? substr($r->{ignore_list}, 0, 50) . (length($r->{ignore_list}) > 50 ? '...' : '') : '';
106 $r->{retention_h} = defined($r->{retention_days}) && $r->{retention_days} > 0
107 ? "$r->{retention_days} d" : '(global)';
108 $r->{retention_days} //= 0;
109 $r->{quiet_hours_start} //= '';
110 $r->{quiet_hours_end} //= '';
111 $r->{has_quiet_hours} = (length($r->{quiet_hours_start}) && length($r->{quiet_hours_end})) ? 1 : 0;
112 $r->{quiet_h} = $r->{has_quiet_hours}
113 ? "$r->{quiet_hours_start} - $r->{quiet_hours_end}"
114 : '(none)';
115}
116$db->db_disconnect($dbh);
117
118my @body = $tpl->template('file_monitors.html',
119 { rows => \@rows, has_rows => scalar(@rows) ? 1 : 0, total => scalar @rows });
120MODS::PageWrapper->new->wrapper(
121 page_title => 'File monitors', page_key => 'file_monitors',
122 body_html => join('', @body), userinfo => { display_name => 'Operator' },
123);
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help