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

O Operator
Diff

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

added on local at 2026-07-10 22:19:06

Added
+108
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 359054848baa
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;
3use warnings;
4use CGI ();
5use MODS::Config;
6use MODS::DBConnect;
7use MODS::Template;
8use MODS::PageWrapper;
9use MODS::Charts;
10use POSIX ();
11
12my $cgi = CGI->new;
13my $db = MODS::DBConnect->new;
14my $tpl = MODS::Template->new;
15
16$|=1; print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
17
18my $dbh = $db->db_connect or die "DB connect failed\n";
19
20my $days = int($cgi->param('days') || 7); $days = 1 if $days < 1; $days = 365 if $days > 365;
21my $q = $cgi->param('q') || '';
22my $server_filter = int($cgi->param('server') || 0);
23
24my $where = "date_time >= DATE_SUB(NOW(), INTERVAL $days DAY)";
25$where .= " AND file_name LIKE " . $dbh->quote('%' . $q . '%') if length $q;
26$where .= " AND server_id = $server_filter" if $server_filter;
27
28my @rows = $db->db_readwrite_multiple($dbh, qq~
29 SELECT fc.file_changes_id AS id, fc.file_name, fc.status, fc.date_time,
30 fc.blob_sha, fc.diff_blob_sha, fc.is_ts_only, fc.uid, fc.gid, fc.permissions,
31 s.server_name
32 FROM FILE_CHANGES fc
33 LEFT JOIN SERVERS s ON s.server_id = fc.server_id
34 WHERE $where
35 ORDER BY fc.date_time DESC
36 LIMIT 200
37~, __FILE__, __LINE__);
38# --- Per-file 30-day sparkline data. One query, then bucket in Perl. ---
39my %spark; # file_name => arrayref [30 daily counts, oldest -> newest]
40{
41 my @dedupe_files;
42 my %seen;
43 foreach my $r (@rows) {
44 next unless defined $r->{file_name};
45 next if $seen{$r->{file_name}}++;
46 push @dedupe_files, $r->{file_name};
47 }
48 if (@dedupe_files) {
49 my @quoted = map { $dbh->quote($_) } @dedupe_files;
50 my $in_list = join(',', @quoted);
51 my @day_rows = $db->db_readwrite_multiple($dbh, qq~
52 SELECT file_name,
53 DATE_FORMAT(date_time, '%Y-%m-%d') AS d,
54 COUNT(*) AS n
55 FROM FILE_CHANGES
56 WHERE file_name IN ($in_list)
57 AND date_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
58 GROUP BY file_name, d
59 ~, __FILE__, __LINE__);
60 my %by_file;
61 foreach my $dr (@day_rows) {
62 $by_file{$dr->{file_name}}{$dr->{d}} = $dr->{n};
63 }
64 my $now = time;
65 my @day_keys;
66 for (my $i = 29; $i >= 0; $i--) {
67 push @day_keys, POSIX::strftime('%Y-%m-%d', localtime($now - $i * 86400));
68 }
69 foreach my $fname (@dedupe_files) {
70 my @series;
71 for my $k (@day_keys) {
72 push @series, ($by_file{$fname}{$k} || 0);
73 }
74 $spark{$fname} = \@series;
75 }
76 }
77}
78
79foreach my $r (@rows) {
80 $r->{status_pill} = $r->{status} && $r->{status} eq 'added' ? 'pill-ok'
81 : $r->{status} && $r->{status} eq 'modified' ? 'pill-warn'
82 : $r->{status} && $r->{status} eq 'deleted' ? 'pill-bad'
83 : 'pill-mute';
84 $r->{status} //= 'unknown';
85 $r->{file_name_h} = $r->{file_name} // '';
86 $r->{file_name_h} = length($r->{file_name_h}) > 90 ? '...' . substr($r->{file_name_h}, -87) : $r->{file_name_h};
87 $r->{blob_short} = $r->{blob_sha} ? substr($r->{blob_sha}, 0, 8) : '-';
88 $r->{diff_url} = "/diff.cgi?kind=file&id=$r->{id}";
89 my $series = $spark{$r->{file_name} // ''};
90 $r->{sparkline_svg} = $series
91 ? MODS::Charts::sparkline(values => $series, width => 88, height => 20, color => '#14b8a6')
92 : '';
93}
94my $total = scalar @rows;
95
96$db->db_disconnect($dbh);
97
98my $tvars = {
99 rows => \@rows, has_rows => $total ? 1 : 0, total => $total,
100 days => $days, q => $q,
101};
102my @body = $tpl->template('file_changes.html', $tvars);
103
104MODS::PageWrapper->new->wrapper(
105 page_title => 'File changes', page_key => 'file_changes',
106 body_html => join('', @body),
107 userinfo => { display_name => 'Operator' },
108);