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

O Operator
Diff

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

modified on local at 2026-07-11 23:34:33

Added
+2
lines
Removed
-0
lines
Context
127
unchanged
Blobs
from 00ab93cbfdf2
to 5cd91f273405
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
11#!/usr/bin/perl
22use strict;
33use warnings;
44use CGI ();
55use MODS::Config;
66use MODS::DBConnect;
77use MODS::Template;
88use MODS::PageWrapper;
99use MODS::Charts;
1010use MODS::RangePicker;
1111use POSIX ();
1212
1313my $cgi = CGI->new;
1414my $db = MODS::DBConnect->new;
1515my $tpl = MODS::Template->new;
1616
1717$|=1; print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
1818
1919my $dbh = $db->db_connect or die "DB connect failed\n";
2020
2121my $r = MODS::RangePicker::parse($cgi);
2222my $q = $cgi->param('q') || '';
2323my $server_filter = int($cgi->param('server') || 0);
2424
2525my $where = $r->{sql_where}->('fc.date_time');
2626$where .= " AND fc.file_name LIKE " . $dbh->quote('%' . $q . '%') if length $q;
2727$where .= " AND fc.server_id = $server_filter" if $server_filter;
2828
2929my @rows = $db->db_readwrite_multiple($dbh, qq~
3030 SELECT fc.file_changes_id AS id, fc.file_name, fc.status,
3131 UNIX_TIMESTAMP(fc.date_time) AS ts_epoch,
3232 fc.date_time,
3333 fc.blob_sha, fc.diff_blob_sha, fc.is_ts_only, fc.uid, fc.gid, fc.permissions,
3434 s.server_name
3535 FROM FILE_CHANGES fc
3636 LEFT JOIN SERVERS s ON s.server_id = fc.server_id
3737 WHERE $where
3838 ORDER BY fc.date_time DESC
3939 LIMIT 200
4040~, __FILE__, __LINE__);
4141
4242# --- Per-file 30-day sparkline data. One query, then bucket in Perl. ---
4343my %spark;
4444{
4545 my @dedupe_files;
4646 my %seen;
4747 foreach my $r_row (@rows) {
4848 next unless defined $r_row->{file_name};
4949 next if $seen{$r_row->{file_name}}++;
5050 push @dedupe_files, $r_row->{file_name};
5151 }
5252 if (@dedupe_files) {
5353 my @quoted = map { $dbh->quote($_) } @dedupe_files;
5454 my $in_list = join(',', @quoted);
5555 my @day_rows = $db->db_readwrite_multiple($dbh, qq~
5656 SELECT file_name,
5757 DATE_FORMAT(date_time, '%Y-%m-%d') AS d,
5858 COUNT(*) AS n
5959 FROM FILE_CHANGES
6060 WHERE file_name IN ($in_list)
6161 AND date_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
6262 GROUP BY file_name, d
6363 ~, __FILE__, __LINE__);
6464 my %by_file;
6565 foreach my $dr (@day_rows) {
6666 $by_file{$dr->{file_name}}{$dr->{d}} = $dr->{n};
6767 }
6868 my $now = time;
6969 my @day_keys;
7070 for (my $i = 29; $i >= 0; $i--) {
7171 push @day_keys, POSIX::strftime('%Y-%m-%d', localtime($now - $i * 86400));
7272 }
7373 foreach my $fname (@dedupe_files) {
7474 my @series;
7575 for my $k (@day_keys) {
7676 push @series, ($by_file{$fname}{$k} || 0);
7777 }
7878 $spark{$fname} = \@series;
7979 }
8080 }
8181}
8282
8383foreach my $row (@rows) {
8484 $row->{status_pill} = $row->{status} && $row->{status} eq 'added' ? 'pill-ok'
8585 : $row->{status} && $row->{status} eq 'modified' ? 'pill-warn'
8686 : $row->{status} && $row->{status} eq 'deleted' ? 'pill-bad'
8787 : 'pill-mute';
8888 $row->{status} //= 'unknown';
8989 $row->{file_name_h} = $row->{file_name} // '';
9090 $row->{file_name_h} = length($row->{file_name_h}) > 90
9191 ? '...' . substr($row->{file_name_h}, -87)
9292 : $row->{file_name_h};
9393 $row->{blob_short} = $row->{blob_sha} ? substr($row->{blob_sha}, 0, 8) : '-';
9494 $row->{diff_url} = "/diff.cgi?kind=file&id=$row->{id}";
95 $row->{restore_url} = "/restore.cgi?id=$row->{id}";
96 $row->{can_restore} = ($row->{blob_sha} && $row->{status} ne 'deleted') ? 1 : 0;
9597 $row->{ts_epoch} //= 0;
9698 my $series = $spark{$row->{file_name} // ''};
9799 $row->{sparkline_svg} = $series
98100 ? MODS::Charts::sparkline(values => $series, width => 88, height => 20, color => '#14b8a6')
99101 : '';
100102}
101103my $total = scalar @rows;
102104
103105$db->db_disconnect($dbh);
104106
105107my $picker_html = MODS::RangePicker::picker_html(
106108 action => '/file_changes.cgi',
107109 range => $r,
108110 hidden => { q => $q, ($server_filter ? (server => $server_filter) : ()) },
109111);
110112
111113my $tvars = {
112114 rows => \@rows,
113115 has_rows => $total ? 1 : 0,
114116 total => $total,
115117 q => $q,
116118 picker_html => $picker_html,
117119 range_label => $r->{range_label},
118120 is_day_view => $r->{is_day} ? 1 : 0,
119121 day_label => $r->{on},
120122};
121123my @body = $tpl->template('file_changes.html', $tvars);
122124
123125MODS::PageWrapper->new->wrapper(
124126 page_title => 'File changes', page_key => 'file_changes',
125127 body_html => join('', @body),
126128 userinfo => { display_name => 'Operator' },
127129);