Diff -- /var/www/vhosts/3dshawn.com/site1/pin_hotspots.cgi
Diff
/var/www/vhosts/3dshawn.com/site1/pin_hotspots.cgi
modified on local at 2026-07-12 00:04:56
Added
+12
lines
Removed
-8
lines
Context
105
unchanged
Blobs
from 37a1a9fc1137
to e108e89453cb
to e108e89453cb
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.| 1 | 1 | #!/usr/bin/perl |
| 2 | 2 | #====================================================================== |
| 3 | 3 | # DriftSense -- /pin_hotspots.cgi |
| 4 | 4 | # |
| 5 | 5 | # Bulk-pin the top-N most-changed files into a new Named Release. |
| 6 | 6 | # GET shows a preview form (default N=20 over 30 days). |
| 7 | 7 | # POST creates a NAMED_RELEASES row + one NAMED_RELEASE_PINS row per |
| 8 | 8 | # top-file (references the file's latest file_changes_id). |
| 9 | 9 | #====================================================================== |
| 10 | 10 | use strict; |
| 11 | 11 | use warnings; |
| 12 | 12 | use CGI (); |
| 13 | 13 | use MODS::Config; |
| 14 | 14 | use MODS::DBConnect; |
| 15 | 15 | use MODS::Template; |
| 16 | 16 | use MODS::PageWrapper; |
| 17 | use POSIX (); | |
| 17 | 18 | |
| 18 | 19 | my $cgi = CGI->new; |
| 19 | 20 | my $db = MODS::DBConnect->new; |
| 20 | 21 | my $tpl = MODS::Template->new; |
| 21 | 22 | $|=1; |
| 22 | 23 | |
| 23 | 24 | my $dbh = $db->db_connect or die "DriftSense: DB connect failed\n"; |
| 24 | 25 | |
| 25 | 26 | my $method = $ENV{REQUEST_METHOD} || 'GET'; |
| 26 | 27 | my $limit = int($cgi->param('n') || 20); $limit = 5 if $limit < 5; $limit = 100 if $limit > 100; |
| 27 | 28 | my $days = int($cgi->param('days') || 30); $days = 1 if $days < 1; $days = 365 if $days > 365; |
| 28 | 29 | |
| 29 | 30 | # ---- Top-N most-changed files in the window ------------------------- |
| 30 | 31 | my @top = $db->db_readwrite_multiple($dbh, qq~ |
| 31 | 32 | SELECT fc.file_name, |
| 32 | 33 | m.scan_name, |
| 33 | 34 | m.file_monitor_list_id AS mid, |
| 34 | 35 | COUNT(*) AS change_ct, |
| 35 | MAX(fc.file_changes_id) AS latest_id, | |
| 36 | (SELECT bs.blob_sha FROM FILE_CHANGES fc2 | |
| 37 | WHERE fc2.file_changes_id = MAX(fc.file_changes_id) | |
| 38 | AND fc2.blob_sha IS NOT NULL | |
| 39 | LIMIT 1) AS blob_sha | |
| 36 | MAX(fc.file_changes_id) AS latest_id | |
| 40 | 37 | FROM FILE_CHANGES fc |
| 41 | 38 | LEFT JOIN FILE_MONITOR_SETTINGS m ON m.file_monitor_list_id = fc.file_monitor_list_id |
| 42 | 39 | WHERE fc.date_time >= DATE_SUB(NOW(), INTERVAL $days DAY) |
| 43 | 40 | AND fc.blob_sha IS NOT NULL |
| 44 | 41 | GROUP BY fc.file_name, m.file_monitor_list_id, m.scan_name |
| 45 | 42 | ORDER BY change_ct DESC, latest_id DESC |
| 46 | 43 | LIMIT $limit |
| 47 | 44 | ~, __FILE__, __LINE__); |
| 45 | ||
| 46 | # Second pass: fetch each top row's latest blob_sha | |
| 47 | foreach my $t (@top) { | |
| 48 | next unless $t->{latest_id}; | |
| 49 | my $r = $db->db_readwrite($dbh, | |
| 50 | "SELECT blob_sha FROM FILE_CHANGES WHERE file_changes_id = " . int($t->{latest_id}) . " LIMIT 1", | |
| 51 | __FILE__, __LINE__); | |
| 52 | $t->{blob_sha} = $r ? $r->{blob_sha} : undef; | |
| 53 | } | |
| 48 | 54 | |
| 49 | 55 | # ---- POST: create the pin release ---------------------------------- |
| 50 | 56 | if ($method eq 'POST' && $cgi->param('confirm')) { |
| 51 | 57 | my $name = $cgi->param('name') || 'hotspot-pin-' . time(); |
| 52 | 58 | my $desc = $cgi->param('description') |
| 53 | 59 | || "Auto-pinned top-$limit files by change count over last $days days"; |
| 54 | 60 | my $by = 'Operator'; |
| 55 | 61 | |
| 56 | 62 | my $q_name = $dbh->quote($name); |
| 57 | 63 | my $q_desc = $dbh->quote($desc); |
| 58 | 64 | my $q_by = $dbh->quote($by); |
| 59 | 65 | $db->db_readwrite($dbh, qq~ |
| 60 | 66 | INSERT INTO NAMED_RELEASES |
| 61 | 67 | (name, description, released_at, released_by, is_locked, created_at) |
| 62 | 68 | VALUES |
| 63 | 69 | ($q_name, $q_desc, NOW(), $q_by, 1, NOW()) |
| 64 | 70 | ~, __FILE__, __LINE__); |
| 65 | 71 | my $rel = $db->db_readwrite($dbh, "SELECT LAST_INSERT_ID() AS id", __FILE__, __LINE__); |
| 66 | 72 | my $rid = $rel && $rel->{id}; |
| 67 | 73 | |
| 68 | 74 | my $pinned = 0; |
| 69 | 75 | if ($rid) { |
| 70 | 76 | foreach my $t (@top) { |
| 71 | 77 | next unless $t->{latest_id} && $t->{blob_sha}; |
| 72 | 78 | my $q_file = $dbh->quote($t->{file_name}); |
| 73 | 79 | my $q_sha = $dbh->quote($t->{blob_sha}); |
| 74 | 80 | $db->db_readwrite($dbh, qq~ |
| 75 | 81 | INSERT INTO NAMED_RELEASE_PINS |
| 76 | 82 | (named_release_id, file_changes_id, file_name, blob_sha) |
| 77 | 83 | VALUES |
| 78 | 84 | ($rid, $t->{latest_id}, $q_file, $q_sha) |
| 79 | 85 | ~, __FILE__, __LINE__); |
| 80 | 86 | $pinned++; |
| 81 | 87 | } |
| 82 | 88 | } |
| 83 | 89 | $db->db_disconnect($dbh); |
| 84 | 90 | print "Status: 302 Found\nLocation: /named_releases.cgi?pinned=$pinned\n\n"; |
| 85 | 91 | exit; |
| 86 | 92 | } |
| 87 | 93 | |
| 88 | 94 | # ---- GET: preview page --------------------------------------------- |
| 89 | 95 | foreach my $t (@top) { |
| 90 | 96 | $t->{file_short} = length($t->{file_name} // '') > 70 |
| 91 | 97 | ? '...' . substr($t->{file_name}, -67) : ($t->{file_name} // ''); |
| 92 | 98 | $t->{sha_short} = substr($t->{blob_sha} // '', 0, 12); |
| 93 | 99 | $t->{diff_url} = "/diff.cgi?kind=file&id=" . ($t->{latest_id} || 0); |
| 94 | 100 | } |
| 95 | 101 | $db->db_disconnect($dbh); |
| 96 | 102 | |
| 97 | my $suggest_name = sprintf('hotspot-pin-%s', POSIX::strftime('%Y%m%d-%H%M', localtime)); | |
| 98 | require POSIX; | |
| 99 | $suggest_name = 'hotspot-pin-' . POSIX::strftime('%Y%m%d-%H%M', localtime); | |
| 103 | my $suggest_name = 'hotspot-pin-' . POSIX::strftime('%Y%m%d-%H%M', localtime); | |
| 100 | 104 | |
| 101 | 105 | print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n"; |
| 102 | 106 | my @body = $tpl->template('pin_hotspots.html', { |
| 103 | 107 | top => \@top, |
| 104 | 108 | has_top => scalar(@top) ? 1 : 0, |
| 105 | 109 | total => scalar @top, |
| 106 | 110 | limit => $limit, |
| 107 | 111 | days => $days, |
| 108 | 112 | suggest_name => $suggest_name, |
| 109 | 113 | }); |
| 110 | 114 | MODS::PageWrapper->new->wrapper( |
| 111 | 115 | page_title => 'Pin hotspots', page_key => '', |
| 112 | 116 | body_html => join('', @body), userinfo => { display_name => 'Operator' }, |
| 113 | 117 | ); |