/[BackupPC]/trunk/lib/BackupPC/SearchLib.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/lib/BackupPC/SearchLib.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations)
Sun Aug 21 15:59:55 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 11107 byte(s)
removed on-disk full path from database and queries, search now tries to
match full path and not only filename

1 #!/usr/bin/perl
2 package BackupPC::SearchLib;
3
4 use strict;
5 use BackupPC::CGI::Lib qw(:all);
6 use BackupPC::Attrib qw(:all);
7 use DBI;
8 use DateTime;
9 use vars qw(%In $MyURL);
10 use Time::HiRes qw/time/;
11
12 my $on_page = 100;
13 my $pager_pages = 10;
14
15 my $dsn = $Conf{SearchDSN};
16 my $db_user = $Conf{SearchUser} || '';
17
18 sub getUnits() {
19 my @ret;
20
21 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
22 my $sth = $dbh->prepare(qq{ SELECT id, share FROM shares} );
23 $sth->execute();
24 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
25
26 while ( my $row = $sth->fetchrow_hashref() ) {
27 push @ret, $row;
28 }
29 $dbh->disconnect();
30 return @ret;
31 }
32
33 sub epoch_to_iso {
34 my $t = shift || return;
35 my $dt = DateTime->from_epoch( epoch => $t ) || return;
36 print STDERR "BUG: $t != " . $dt->epoch . "\n" unless ($t == $dt->epoch);
37 return $dt->ymd . ' ' . $dt->hms;
38 }
39
40 sub getWhere($) {
41 my ($param) = @_;
42 my @conditions;
43
44 sub mk_epoch_date($$) {
45 my ($name,$suffix) = @_;
46
47 my $yyyy = $param->{ $name . '_year_' . $suffix} || return;
48 my $mm .= $param->{ $name . '_month_' . $suffix} ||
49 ( $suffix eq 'from' ? 1 : 12);
50 my $dd .= $param->{ $name . '_day_' . $suffix} ||
51 ( $suffix eq 'from' ? 1 : 31);
52 my $dt = new DateTime(
53 year => $yyyy,
54 month => $mm,
55 day => $dd
56 );
57 return $dt->epoch || 'NULL';
58 }
59
60 my $backup_from = mk_epoch_date('search_backup', 'from');
61 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
62 my $backup_to = mk_epoch_date('search_backup', 'to');
63 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
64
65 my $files_from = mk_epoch_date('search', 'from');
66 push @conditions, qq{ files.date >= $files_from } if ($files_from);
67 my $files_to = mk_epoch_date('search', 'to');
68 push @conditions, qq{ files.date <= $files_to } if ($files_to);
69
70 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
71
72 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
73
74 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
75
76 return (
77 join(" and ", @conditions),
78 $files_from, $files_to,
79 $backup_from, $backup_to
80 );
81 }
82
83
84 sub getFiles($$) {
85 my ($where, $offset) = @_;
86
87 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
88
89 my $sql_cols = qq{
90 files.id AS fid,
91 hosts.name AS hname,
92 shares.name AS sname,
93 shares.share AS sharename,
94 files.backupNum AS backupNum,
95 files.name AS filename,
96 files.path AS filepath,
97 files.date AS date,
98 files.type AS filetype,
99 files.size AS size,
100 dvds.name AS dvd
101 };
102
103 my $sql_from = qq{
104 FROM files
105 INNER JOIN shares ON files.shareID=shares.ID
106 INNER JOIN hosts ON hosts.ID = shares.hostID
107 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID
108 };
109
110 my $sql_dvd_from = qq{
111 LEFT JOIN dvds ON dvds.ID = files.dvdid
112 };
113
114 my $sql_where;
115 $sql_where = " WHERE ". $where if ($where);
116
117 my $sql_order = qq{
118 ORDER BY files.id
119 LIMIT $on_page
120 OFFSET ?
121 };
122
123 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
124 my $sql_results = qq{ select $sql_cols $sql_from $sql_dvd_from $sql_where $sql_order };
125
126 $offset ||= 0;
127 $offset = ($offset * $on_page);
128
129 my $sth = $dbh->prepare($sql_count);
130 $sth->execute();
131 my ($results) = $sth->fetchrow_array();
132
133 $sth = $dbh->prepare($sql_results);
134 $sth->execute( $offset );
135
136 if ($sth->rows != $results) {
137 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
138 $bug =~ s/\s+/ /gs;
139 print STDERR "$bug\n";
140 }
141
142 my @ret;
143
144 while (my $row = $sth->fetchrow_hashref()) {
145 push(@ret, {
146 'hname' => $row->{'hname'},
147 'sname' => $row->{'sname'},
148 'sharename' => $row->{'sharename'},
149 'backupno' => $row->{'backupnum'},
150 'fname' => $row->{'filename'},
151 'fpath' => $row->{'filepath'},
152 'networkpath' => $row->{'networkpath'},
153 'date' => $row->{'date'},
154 'type' => $row->{'filetype'},
155 'size' => $row->{'size'},
156 'id' => $row->{'fid'},
157 'dvd' => $row->{'dvd'}
158 });
159 }
160
161 $sth->finish();
162 $dbh->disconnect();
163 return ($results, \@ret);
164 }
165
166 sub getBackupsNotBurned() {
167
168 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
169 my $sql = q{
170 SELECT
171 hosts.ID AS hostid,
172 min(hosts.name) AS host,
173 backups.num AS backupno,
174 min(backups.type) AS type,
175 min(backups.date) AS date
176 FROM backups, shares, files, hosts
177 WHERE
178 backups.num = files.backupNum AND
179 shares.ID = files.shareID AND
180 backups.hostID = shares.hostID AND
181 hosts.ID = backups.hostID AND
182 files.dvdid IS NULL
183 GROUP BY
184 backups.hostID, backups.num, hosts.id
185 ORDER BY min(backups.date)
186 };
187 my $sth = $dbh->prepare( $sql );
188 my @ret;
189 $sth->execute();
190
191 while ( my $row = $sth->fetchrow_hashref() ) {
192 push(@ret, {
193 'host' => $row->{'host'},
194 'hostid' => $row->{'hostid'},
195 'backupno' => $row->{'backupno'},
196 'type' => $row->{'type'},
197 'date' => $row->{'date'},
198 'age' => sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) ),
199 }
200 );
201 }
202
203 return @ret;
204 }
205
206 sub displayBackupsGrid()
207 {
208 my $retHTML = "";
209 my $addForm = 1;
210
211 if ($addForm) {
212
213 $retHTML .= <<EOF3;
214 <script language="javascript" type="text/javascript">
215 <!--
216
217 function checkAll(location)
218 {
219 for (var i=0;i<document.forma.elements.length;i++)
220 {
221 var e = document.forma.elements[i];
222 if ((e.checked || !e.checked) && e.name != \'all\') {
223 if (eval("document.forma."+location+".checked")) {
224 e.checked = true;
225 } else {
226 e.checked = false;
227 }
228 }
229 }
230 }
231 //-->
232 </script>
233 EOF3
234 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
235 $retHTML.= q{<input type="hidden" value="burn" name="action">};
236 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
237 }
238 $retHTML .= qq{<table style="fview"><tr>};
239
240 if ($addForm) {
241 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
242 }
243 $retHTML .= qq{
244 <td class="tableheader">Host</td>
245 <td class="tableheader">Backup no</td>
246 <td class="tableheader">Type</td>
247 <td class="tableheader">date</td>
248 <td class="tableheader">age/days</td>
249 </tr>
250 };
251
252 my @backups = getBackupsNotBurned();
253 my $backup;
254
255 if ($addForm) {
256 $retHTML .= qq{
257 <tr><td colspan=7 style="tableheader">
258 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
259 </td></tr>
260 };
261 }
262
263 foreach $backup(@backups) {
264
265 my $ftype = "";
266
267 $retHTML .= "<tr>";
268 if ($addForm) {
269 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
270 $backup->{'hostid'}.'_'.$backup->{'backupno'} .
271 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupno'} .
272 '"></td>';
273 }
274
275 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
276 '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .
277 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
278 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
279 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
280 '</tr>';
281 }
282
283 $retHTML .= "</table>";
284
285 if ($addForm) {
286 $retHTML .= "</form>";
287 }
288
289 return $retHTML;
290 }
291
292 sub displayGrid($$$$) {
293 my ($where, $addForm, $offset, $hilite) = @_;
294 my $retHTML = "";
295
296 my $start_t = time();
297
298 my ($results, $files) = getFiles($where, $offset);
299
300 my $dur_t = time() - $start_t;
301 my $dur = sprintf("%0.4fs", $dur_t);
302
303 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
304
305 if ($results <= 0) {
306 $retHTML .= qq{
307 <p style="color: red;">No results found...</p>
308 };
309 return $retHTML;
310 } else {
311 # DEBUG
312 #use Data::Dumper;
313 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
314 }
315
316
317 if ($addForm) {
318 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};
319 $retHTML.= qq{<input type="hidden" value="search" name="action">};
320 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};
321 }
322
323
324 $retHTML .= qq{
325 <br/>Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
326 <table style="fview" width="100%">
327 <tr>
328 <td class="tableheader">Share</td>
329 <td class="tableheader">Name</td>
330 <td class="tableheader">Type</td>
331 <td class="tableheader">#</td>
332 <td class="tableheader">Size</td>
333 <td class="tableheader">Date</td>
334 <td class="tableheader">Media</td>
335 </tr>
336 };
337
338 my $file;
339
340 sub hilite_html($$) {
341 my ($html, $search) = @_;
342 $html =~ s#($search)#<b>$1</b>#gis;
343 return $html;
344 }
345
346 sub restore_link($$$$$$) {
347 my $type = shift;
348 my $action = 'RestoreFile';
349 $action = 'browse' if (lc($type) eq 'dir');
350 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
351 }
352
353 foreach $file (@{ $files }) {
354 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
355 $retHTML .= "<tr>";
356
357 foreach my $v ((
358 $file->{'sharename'},
359 qq{<img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" align="center">&nbsp;} . hilite_html( $file->{'fpath'}, $hilite ),
360 $typeStr,
361 restore_link( $typeStr, $file->{'hname'}, $file->{'backupno'}, $file->{'sname'}, $file->{'fpath'}, $file->{'backupno'} ),
362 $file->{'size'},
363 epoch_to_iso( $file->{'date'} ),
364 $file->{'dvd'}
365 )) {
366 $retHTML .= qq{<td class="fviewborder">$v</td>};
367 }
368
369 $retHTML .= "</tr>";
370 }
371 $retHTML .= "</table>";
372
373 # all variables which has to be transfered
374 foreach my $n (qw/search_day_from search_month_from search_year_from search_day_to search_month_to search_year_to search_backup_day_from search_backup_month_from search_backup_year_from search_backup_day_to search_backup_month_to search_backup_year_to search_filename offset/) {
375 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
376 }
377
378 my $del = '';
379 my $max_page = int( $results / $on_page );
380 my $page = 0;
381
382 my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';
383
384 $retHTML .= '<div style="text-align: center;">';
385
386 if ($offset > 0) {
387 $retHTML .= sprintf($link_fmt, $offset - 1, '&lt;&lt;') . ' ';
388 }
389
390 while ($page <= $max_page) {
391 if ($page == $offset) {
392 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
393 } else {
394 $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);
395 }
396
397 if ($page < $offset - $pager_pages && $page != 0) {
398 $retHTML .= " ... ";
399 $page = $offset - $pager_pages;
400 $del = '';
401 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
402 $retHTML .= " ... ";
403 $page = $max_page;
404 $del = '';
405 } else {
406 $del = ' | ';
407 $page++;
408 }
409 }
410
411 if ($offset < $max_page) {
412 $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '&gt;&gt;');
413 }
414
415 $retHTML .= "</div>";
416
417 $retHTML .= "</form>" if ($addForm);
418
419 return $retHTML;
420 }
421
422 1;

  ViewVC Help
Powered by ViewVC 1.1.26