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

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

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

Added
+180
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
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.
1#!/usr/bin/perl
2#======================================================================
3# Meta-Admin -- /search.cgi
4#
5# Global search box from the topbar. Matches against:
6# - site_connections (slug, display_name, display_url, db_name,
7# db_user, vhost_path)
8# - platform_settings (setting_key, setting_value when not secret)
9#
10# Results render as two grouped lists with quick-jump links.
11#======================================================================
12use strict;
13use warnings;
14use lib '/var/www/vhosts/3dshawn.com/admin.3dshawn.com';
15use CGI;
16use MODS::Login;
17use MODS::DBConnect;
18use MODS::MetaAdmin::Config;
19use MODS::MetaAdmin::Wrapper;
20
21my $q = CGI->new;
22my $form = $q->Vars;
23my $auth = MODS::Login->new;
24my $u = $auth->login_verify;
25unless ($u) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; }
26
27my $query = $form->{q} || '';
28$query =~ s/^\s+|\s+$//g;
29$query = substr($query, 0, 80);
30
31sub _esc {
32 my $s = shift; $s //= '';
33 $s =~ s/&/&amp;/g; $s =~ s/</&lt;/g; $s =~ s/>/&gt;/g;
34 $s =~ s/"/&quot;/g;
35 return $s;
36}
37
38sub _highlight {
39 my ($txt, $q) = @_;
40 return _esc($txt) unless length $q;
41 my $e_txt = _esc($txt);
42 my $e_q = quotemeta _esc($q);
43 $e_txt =~ s{($e_q)}{<mark style="background:rgba(217,119,6,.28);color:#fff;padding:0 2px;border-radius:2px">$1</mark>}gi;
44 return $e_txt;
45}
46
47my $db = MODS::DBConnect->new;
48my $dbh = $db->db_connect;
49
50my (@sites, @settings);
51if (length $query) {
52 my $q_safe = $query; $q_safe =~ s/'/''/g;
53 my $like = "%$q_safe%";
54 @sites = $db->db_readwrite_multiple($dbh, qq~
55 SELECT id, slug, display_name, display_url, brand_color,
56 db_name, db_user, db_host, db_port, vhost_path, is_active
57 FROM site_connections
58 WHERE slug LIKE '$like'
59 OR display_name LIKE '$like'
60 OR display_url LIKE '$like'
61 OR db_name LIKE '$like'
62 OR db_user LIKE '$like'
63 OR vhost_path LIKE '$like'
64 ORDER BY sort_order, id
65 ~, __FILE__, __LINE__);
66
67 @settings = $db->db_readwrite_multiple($dbh, qq~
68 SELECT setting_key, setting_value, is_secret, updated_at
69 FROM platform_settings
70 WHERE setting_key LIKE '$like'
71 OR (is_secret=0 AND setting_value LIKE '$like')
72 ORDER BY setting_key
73 ~, __FILE__, __LINE__);
74}
75$db->db_disconnect($dbh);
76
77my $body = '';
78
79$body .= q~
80<div class="page-head"><div class="left">
81 <span class="page-eyebrow"><span class="dot"></span> Search</span>
82 <h1 class="page-title">Search results</h1>
83</div></div>
84~;
85
86my $q_h = _esc($query);
87$body .= qq~
88<form method="GET" action="/search.cgi" style="margin-bottom:18px">
89 <input type="text" name="q" value="$q_h" placeholder="Search sites, settings..." autocomplete="off"
90 autofocus style="width:100%;max-width:520px;padding:10px 14px;font-size:14px">
91</form>
92~;
93
94if (!length $query) {
95 $body .= q~<div class="banner">Type a search above to find sites or settings.</div>~;
96} else {
97 my $total = scalar(@sites) + scalar(@settings);
98 if (!$total) {
99 $body .= qq~<div class="banner danger">No matches for <strong>$q_h</strong>.</div>~;
100 } else {
101 $body .= qq~<div style="color:var(--col-text-dim);font-size:12px;margin-bottom:14px">
102 Found <strong style="color:var(--col-text)">$total</strong> match~ . ($total==1 ? '' : 'es') . qq~ for <strong style="color:var(--col-text)">$q_h</strong>.
103 </div>~;
104 }
105
106 if (@sites) {
107 my $n_s = scalar @sites;
108 $body .= qq~
109<div class="module" style="margin-bottom:16px">
110 <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>
111 <div class="module-body" style="padding:0">
112 <table class="tbl">
113 <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>
114 <tbody>
115~;
116 my %lmap = (webstls=>'WS',ptmatrix=>'PT',affsoft=>'AS',shopcart=>'SC',
117 repricer=>'RP',abforge=>'AB',contactforge=>'CF');
118 foreach my $s (@sites) {
119 my $color = _esc($s->{brand_color} || '#807aa8');
120 my $ltr = _esc($lmap{$s->{slug}} || uc(substr($s->{display_name} || '?', 0, 1)));
121 my $name = _highlight($s->{display_name}, $query);
122 my $url = _highlight($s->{display_url}, $query);
123 my $dbn = _highlight($s->{db_name}, $query);
124 my $vp = _highlight($s->{vhost_path} || '-', $query);
125 my $id = $s->{id};
126 $body .= qq~<tr>
127 <td><span class="brand-icon" style="--site-glow:$color" data-letter="$ltr"></span></td>
128 <td><strong>$name</strong></td>
129 <td>$url</td>
130 <td class="mono dim" style="font-size:11px">$dbn</td>
131 <td class="mono dim" style="font-size:11px">$vp</td>
132 <td style="text-align:right;white-space:nowrap">
133 <a href="/sites.cgi?edit=$id" class="btn btn-sm">Edit</a>
134 </td>
135 </tr>~;
136 }
137 $body .= q~ </tbody>
138 </table>
139 </div>
140</div>~;
141 }
142
143 if (@settings) {
144 my $n = scalar @settings;
145 $body .= qq~
146<div class="module">
147 <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>
148 <div class="module-body" style="padding:0">
149 <table class="tbl">
150 <thead><tr><th>Key</th><th>Value</th><th style="text-align:right">Updated</th></tr></thead>
151 <tbody>
152~;
153 foreach my $r (@settings) {
154 my $k = _highlight($r->{setting_key}, $query);
155 my $v;
156 if ($r->{is_secret}) {
157 $v = qq~<span class="pill" style="font-size:9px">SECRET</span>~;
158 } else {
159 my $raw = $r->{setting_value} // '';
160 $raw = substr($raw, 0, 80) . '...' if length $raw > 80;
161 $v = _highlight($raw, $query);
162 }
163 my $up = _esc($r->{updated_at} || '-');
164 $body .= qq~<tr>
165 <td class="mono"><strong>$k</strong></td>
166 <td class="mono dim" style="font-size:12px">$v</td>
167 <td style="text-align:right" class="dim">$up</td>
168 </tr>~;
169 }
170 $body .= q~ </tbody>
171 </table>
172 <div style="padding:12px 16px;border-top:1px solid var(--col-border)">
173 <a href="/settings.cgi" class="btn btn-sm">Open all settings</a>
174 </div>
175 </div>
176</div>~;
177 }
178}
179
180MODS::MetaAdmin::Wrapper->new->render(title => 'Search', page_key => 'search', body => $body, userinfo => $u);
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help