Diff -- /var/www/vhosts/3dshawn.com/admin.3dshawn.com/search.cgi

O Operator
Diff

/var/www/vhosts/3dshawn.com/admin.3dshawn.com/search.cgi

added on local at 2026-06-22 01:10:13

Added
+0
lines
Removed
-0
lines
Context
180
unchanged
Blobs
from 52c895f08f9d
to 52c895f08f9d
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
22#======================================================================
33# Meta-Admin -- /search.cgi
44#
55# Global search box from the topbar. Matches against:
66# - site_connections (slug, display_name, display_url, db_name,
77# db_user, vhost_path)
88# - platform_settings (setting_key, setting_value when not secret)
99#
1010# Results render as two grouped lists with quick-jump links.
1111#======================================================================
1212use strict;
1313use warnings;
1414use lib '/var/www/vhosts/3dshawn.com/admin.3dshawn.com';
1515use CGI;
1616use MODS::Login;
1717use MODS::DBConnect;
1818use MODS::MetaAdmin::Config;
1919use MODS::MetaAdmin::Wrapper;
2020
2121my $q = CGI->new;
2222my $form = $q->Vars;
2323my $auth = MODS::Login->new;
2424my $u = $auth->login_verify;
2525unless ($u) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; }
2626
2727my $query = $form->{q} || '';
2828$query =~ s/^\s+|\s+$//g;
2929$query = substr($query, 0, 80);
3030
3131sub _esc {
3232 my $s = shift; $s //= '';
3333 $s =~ s/&/&amp;/g; $s =~ s/</&lt;/g; $s =~ s/>/&gt;/g;
3434 $s =~ s/"/&quot;/g;
3535 return $s;
3636}
3737
3838sub _highlight {
3939 my ($txt, $q) = @_;
4040 return _esc($txt) unless length $q;
4141 my $e_txt = _esc($txt);
4242 my $e_q = quotemeta _esc($q);
4343 $e_txt =~ s{($e_q)}{<mark style="background:rgba(217,119,6,.28);color:#fff;padding:0 2px;border-radius:2px">$1</mark>}gi;
4444 return $e_txt;
4545}
4646
4747my $db = MODS::DBConnect->new;
4848my $dbh = $db->db_connect;
4949
5050my (@sites, @settings);
5151if (length $query) {
5252 my $q_safe = $query; $q_safe =~ s/'/''/g;
5353 my $like = "%$q_safe%";
5454 @sites = $db->db_readwrite_multiple($dbh, qq~
5555 SELECT id, slug, display_name, display_url, brand_color,
5656 db_name, db_user, db_host, db_port, vhost_path, is_active
5757 FROM site_connections
5858 WHERE slug LIKE '$like'
5959 OR display_name LIKE '$like'
6060 OR display_url LIKE '$like'
6161 OR db_name LIKE '$like'
6262 OR db_user LIKE '$like'
6363 OR vhost_path LIKE '$like'
6464 ORDER BY sort_order, id
6565 ~, __FILE__, __LINE__);
6666
6767 @settings = $db->db_readwrite_multiple($dbh, qq~
6868 SELECT setting_key, setting_value, is_secret, updated_at
6969 FROM platform_settings
7070 WHERE setting_key LIKE '$like'
7171 OR (is_secret=0 AND setting_value LIKE '$like')
7272 ORDER BY setting_key
7373 ~, __FILE__, __LINE__);
7474}
7575$db->db_disconnect($dbh);
7676
7777my $body = '';
7878
7979$body .= q~
8080<div class="page-head"><div class="left">
8181 <span class="page-eyebrow"><span class="dot"></span> Search</span>
8282 <h1 class="page-title">Search results</h1>
8383</div></div>
8484~;
8585
8686my $q_h = _esc($query);
8787$body .= qq~
8888<form method="GET" action="/search.cgi" style="margin-bottom:18px">
8989 <input type="text" name="q" value="$q_h" placeholder="Search sites, settings..." autocomplete="off"
9090 autofocus style="width:100%;max-width:520px;padding:10px 14px;font-size:14px">
9191</form>
9292~;
9393
9494if (!length $query) {
9595 $body .= q~<div class="banner">Type a search above to find sites or settings.</div>~;
9696} else {
9797 my $total = scalar(@sites) + scalar(@settings);
9898 if (!$total) {
9999 $body .= qq~<div class="banner danger">No matches for <strong>$q_h</strong>.</div>~;
100100 } else {
101101 $body .= qq~<div style="color:var(--col-text-dim);font-size:12px;margin-bottom:14px">
102102 Found <strong style="color:var(--col-text)">$total</strong> match~ . ($total==1 ? '' : 'es') . qq~ for <strong style="color:var(--col-text)">$q_h</strong>.
103103 </div>~;
104104 }
105105
106106 if (@sites) {
107107 my $n_s = scalar @sites;
108108 $body .= qq~
109109<div class="module" style="margin-bottom:16px">
110110 <div class="module-head"><div class="left"><div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/></svg></div><div class="module-title">Sites ($n_s)</div></div></div>
111111 <div class="module-body" style="padding:0">
112112 <table class="tbl">
113113 <thead><tr><th></th><th>Site</th><th>URL</th><th>DB</th><th>Vhost</th><th style="text-align:right">Actions</th></tr></thead>
114114 <tbody>
115115~;
116116 my %lmap = (webstls=>'WS',ptmatrix=>'PT',affsoft=>'AS',shopcart=>'SC',
117117 repricer=>'RP',abforge=>'AB',contactforge=>'CF');
118118 foreach my $s (@sites) {
119119 my $color = _esc($s->{brand_color} || '#807aa8');
120120 my $ltr = _esc($lmap{$s->{slug}} || uc(substr($s->{display_name} || '?', 0, 1)));
121121 my $name = _highlight($s->{display_name}, $query);
122122 my $url = _highlight($s->{display_url}, $query);
123123 my $dbn = _highlight($s->{db_name}, $query);
124124 my $vp = _highlight($s->{vhost_path} || '-', $query);
125125 my $id = $s->{id};
126126 $body .= qq~<tr>
127127 <td><span class="brand-icon" style="--site-glow:$color" data-letter="$ltr"></span></td>
128128 <td><strong>$name</strong></td>
129129 <td>$url</td>
130130 <td class="mono dim" style="font-size:11px">$dbn</td>
131131 <td class="mono dim" style="font-size:11px">$vp</td>
132132 <td style="text-align:right;white-space:nowrap">
133133 <a href="/sites.cgi?edit=$id" class="btn btn-sm">Edit</a>
134134 </td>
135135 </tr>~;
136136 }
137137 $body .= q~ </tbody>
138138 </table>
139139 </div>
140140</div>~;
141141 }
142142
143143 if (@settings) {
144144 my $n = scalar @settings;
145145 $body .= qq~
146146<div class="module">
147147 <div class="module-head"><div class="left"><div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M12 1v6m0 10v6m11-11h-6M7 12H1m17.07-7.07l-4.24 4.24M9.17 14.83l-4.24 4.24m0-14.14l4.24 4.24M14.83 14.83l4.24 4.24"/></svg></div><div class="module-title">Settings ($n)</div></div></div>
148148 <div class="module-body" style="padding:0">
149149 <table class="tbl">
150150 <thead><tr><th>Key</th><th>Value</th><th style="text-align:right">Updated</th></tr></thead>
151151 <tbody>
152152~;
153153 foreach my $r (@settings) {
154154 my $k = _highlight($r->{setting_key}, $query);
155155 my $v;
156156 if ($r->{is_secret}) {
157157 $v = qq~<span class="pill" style="font-size:9px">SECRET</span>~;
158158 } else {
159159 my $raw = $r->{setting_value} // '';
160160 $raw = substr($raw, 0, 80) . '...' if length $raw > 80;
161161 $v = _highlight($raw, $query);
162162 }
163163 my $up = _esc($r->{updated_at} || '-');
164164 $body .= qq~<tr>
165165 <td class="mono"><strong>$k</strong></td>
166166 <td class="mono dim" style="font-size:12px">$v</td>
167167 <td style="text-align:right" class="dim">$up</td>
168168 </tr>~;
169169 }
170170 $body .= q~ </tbody>
171171 </table>
172172 <div style="padding:12px 16px;border-top:1px solid var(--col-border)">
173173 <a href="/settings.cgi" class="btn btn-sm">Open all settings</a>
174174 </div>
175175 </div>
176176</div>~;
177177 }
178178}
179179
180180MODS::MetaAdmin::Wrapper->new->render(title => 'Search', page_key => 'search', body => $body, userinfo => $u);