/[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 109 - (show annotations)
Thu Sep 1 18:30:51 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 13584 byte(s)
added Ivan's changes to show increment sizes and other minor fixes
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 my $index_path = $Conf{HyperEstraierIndex};
19 if ($index_path) {
20 $index_path = $TopDir . '/' . $index_path;
21 $index_path =~ s#//#/#g;
22 }
23
24 my $dbh;
25
26 sub get_dbh {
27 $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
28 return $dbh;
29 }
30
31 sub getUnits() {
32 my @ret;
33
34 my $dbh = get_dbh();
35 my $sth = $dbh->prepare(qq{
36 SELECT
37 shares.id as id,
38 hosts.name || ':' || shares.name as share
39 FROM shares
40 JOIN hosts on hostid = hosts.id
41 ORDER BY share
42 } );
43 $sth->execute();
44 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
45
46 while ( my $row = $sth->fetchrow_hashref() ) {
47 push @ret, $row;
48 }
49 return @ret;
50 }
51
52 sub epoch_to_iso {
53 my $t = shift || return;
54 my $iso = BackupPC::Lib::timeStamp(undef, $t);
55 $iso =~ s/\s/ /g;
56 return $iso;
57 }
58
59 sub dates_from_form($) {
60 my $param = shift || return;
61
62 sub mk_epoch_date($$) {
63 my ($name,$suffix) = @_;
64
65 my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
66 my $mm .= $param->{ $name . '_month_' . $suffix} ||
67 ( $suffix eq 'from' ? 1 : 12);
68 my $dd .= $param->{ $name . '_day_' . $suffix} ||
69 ( $suffix eq 'from' ? 1 : 31);
70
71 $yyyy =~ s/\D//g;
72 $mm =~ s/\D//g;
73 $dd =~ s/\D//g;
74
75 my $dt = new DateTime(
76 year => $yyyy,
77 month => $mm,
78 day => $dd
79 );
80 print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n";
81 return $dt->epoch || 'NULL';
82 }
83
84 my @ret = (
85 mk_epoch_date('search_backup', 'from'),
86 mk_epoch_date('search_backup', 'to'),
87 mk_epoch_date('search', 'from'),
88 mk_epoch_date('search', 'to'),
89 );
90
91 return @ret;
92
93 }
94
95
96 sub getWhere($) {
97 my $param = shift || return;
98
99 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
100
101 my @conditions;
102 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
103 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
104 push @conditions, qq{ files.date >= $files_from } if ($files_from);
105 push @conditions, qq{ files.date <= $files_to } if ($files_to);
106
107 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
108
109 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
110 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
111
112 return join(" and ", @conditions);
113 }
114
115
116 sub getFiles($) {
117 my ($param) = @_;
118
119 my $offset = $param->{'offset'} || 0;
120 $offset *= $on_page;
121
122 my $dbh = get_dbh();
123
124 my $sql_cols = qq{
125 files.id AS fid,
126 hosts.name AS hname,
127 shares.name AS sname,
128 files.backupnum AS backupnum,
129 files.path AS filepath,
130 files.date AS date,
131 files.type AS type,
132 files.size AS size
133 };
134
135 my $sql_from = qq{
136 FROM files
137 INNER JOIN shares ON files.shareID=shares.ID
138 INNER JOIN hosts ON hosts.ID = shares.hostID
139 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
140 };
141
142 my $sql_where;
143 my $where = getWhere($param);
144 $sql_where = " WHERE ". $where if ($where);
145
146 my $sql_order = qq{
147 ORDER BY files.date
148 LIMIT $on_page
149 OFFSET ?
150 };
151
152 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
153 my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
154
155 my $sth = $dbh->prepare($sql_count);
156 $sth->execute();
157 my ($results) = $sth->fetchrow_array();
158
159 $sth = $dbh->prepare($sql_results);
160 $sth->execute( $offset );
161
162 if ($sth->rows != $results) {
163 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
164 $bug =~ s/\s+/ /gs;
165 print STDERR "$bug\n";
166 }
167
168 my @ret;
169
170 while (my $row = $sth->fetchrow_hashref()) {
171 push @ret, $row;
172 }
173
174 $sth->finish();
175 return ($results, \@ret);
176 }
177
178 sub getFilesHyperEstraier($) {
179 my ($param) = @_;
180
181 my $offset = $param->{'offset'} || 0;
182 $offset *= $on_page;
183
184 die "no index_path?" unless ($index_path);
185
186 use HyperEstraier;
187
188 # open the database
189 my $db = HyperEstraier::Database->new();
190 $db->open($index_path, $HyperEstraier::ESTDBREADER);
191
192 # create a search condition object
193 my $cond = HyperEstraier::Condition->new();
194
195 my $q = $param->{'search_filename'};
196 my $shareid = $param->{'search_share'};
197
198 if (length($q) > 0) {
199 # exact match
200 $cond->add_attr("filepath ISTRINC $q");
201
202 $q =~ s/(.)/$1 /g;
203 # set the search phrase to the search condition object
204 $cond->set_phrase($q);
205 }
206
207 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
208
209 $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
210 $cond->add_attr("backup_date NUMLE $backup_to") if ($backup_to);
211
212 $cond->add_attr("date NUMGE $files_from") if ($files_from);
213 $cond->add_attr("date NUMLE $files_to") if ($files_to);
214
215 $cond->add_attr("shareid NUMEQ $shareid") if ($shareid);
216
217 # $cond->set_max( $offset + $on_page );
218 $cond->set_options( $HyperEstraier::Condition::SURE );
219 $cond->set_order( 'date NUMA' );
220
221 # get the result of search
222 my $result = $db->search($cond, 0);
223
224 my @res;
225 my $hits = $result->size;
226
227 # for each document in result
228 for my $i ($offset .. ($offset + $on_page - 1)) {
229 last if ($i >= $hits);
230
231 my $id = $result->get($i);
232 my $doc = $db->get_doc($id, 0);
233
234 my $row;
235 foreach my $c (qw/fid hname sname backupnum fiilename filepath date type size/) {
236 $row->{$c} = $doc->attr($c);
237 }
238 push @res, $row;
239 }
240
241 return ($hits, \@res);
242 }
243
244 sub getGzipName($$$)
245 {
246 my ($host, $share, $backupnum) = @_;
247 my $ret = $Conf{GzipSchema};
248
249 $share =~ s/\//_/g;
250 $ret =~ s/\\h/$host/ge;
251 $ret =~ s/\\s/$share/ge;
252 $ret =~ s/\\n/$backupnum/ge;
253
254 return $ret;
255
256 }
257
258 sub getBackupsNotBurned() {
259
260 my $dbh = get_dbh();
261 my $sql = q{
262 SELECT
263 backups.hostID AS hostid,
264 min(hosts.name) AS host,
265 min(shares.name) AS share,
266 backups.num AS backupnum,
267 min(backups.type) AS type,
268 min(backups.date) AS date,
269 min(backups.size) AS size
270 FROM files
271 INNER JOIN shares ON files.shareID=shares.ID
272 INNER JOIN hosts ON hosts.ID = shares.hostID
273 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
274 GROUP BY
275 backups.hostID, backups.num, backups.shareid
276 ORDER BY min(backups.date)
277 };
278 my $sth = $dbh->prepare( $sql );
279 my @ret;
280 $sth->execute();
281
282 while ( my $row = $sth->fetchrow_hashref() ) {
283 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
284 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
285 my (undef,undef,undef,undef,undef,undef,undef,$fs_size,undef,undef,undef,undef,undef) =
286 stat( $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'.
287 getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'}));
288 $row->{'fs_size'} = $fs_size;
289 push @ret, $row;
290 }
291
292 return @ret;
293 }
294
295 sub displayBackupsGrid()
296 {
297 my $retHTML = "";
298
299 $retHTML .= <<EOF3;
300 <script language="javascript" type="text/javascript">
301 <!--
302
303 function checkAll(location)
304 {
305 for (var i=0;i<document.forma.elements.length;i++)
306 {
307 var e = document.forma.elements[i];
308 if ((e.checked || !e.checked) && e.name != \'all\') {
309 if (eval("document.forma."+location+".checked")) {
310 e.checked = true;
311 } else {
312 e.checked = false;
313 }
314 }
315 }
316 }
317 //-->
318 </script>
319 EOF3
320 $retHTML .= q{
321 <form name="forma" method="GET" action="$MyURL?action=burn">
322 <input type="hidden" value="burn" name="action">
323 <input type="hidden" value="results" name="search_results">
324 <table style="fview" border="0" cellspacing="0" cellpadding="2">
325 <tr class="tableheader">
326 <td class="tableheader">
327 <input type="checkbox" name="allFiles" onClick="checkAll('allFiles');">
328 </td>
329 <td align="center">Share</td>
330 <td align="center">Backup no</td>
331 <td align="center">Type</td>
332 <td align="center">date</td>
333 <td align="center">age/days</td>
334 <td align="center">size/MB</td>
335 <td align="center">gzip size</td>
336 </tr>
337
338 <tr><td colspan=7 style="tableheader">
339 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
340 </td></tr>
341 };
342
343 my @color = (' bgcolor="#e0e0e0"', '');
344
345 my $i = 0;
346 my $host = '';
347
348 foreach my $backup ( getBackupsNotBurned() ) {
349
350 if ($host ne $backup->{'host'}) {
351 $i++;
352 $host = $backup->{'host'};
353 }
354 my $ftype = "";
355
356 $retHTML .= "<tr" . $color[$i %2 ] . ">";
357 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
358 $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
359 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
360 '"></td>';
361
362 $retHTML .=
363 '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
364 '<td align="center">' . $backup->{'backupnum'} . '</td>' .
365 '<td align="center">' . $backup->{'type'} . '</td>' .
366 '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
367 '<td align="center">' . $backup->{'age'} . '</td>' .
368 '<td align="right">' . $backup->{'size'} . '</td>' .
369 '<td align="right">' . $backup->{'fs_size'} .'</td>' .
370 "</tr>\n";
371
372
373 }
374
375 $retHTML .= "</table>";
376 $retHTML .= "</form>";
377
378 return $retHTML;
379 }
380
381 sub displayGrid($) {
382 my ($param) = @_;
383
384 my $offset = $param->{'offset'};
385 my $hilite = $param->{'search_filename'};
386
387 my $retHTML = "";
388
389 my $start_t = time();
390
391 my ($results, $files);
392 if ($param->{'use_hest'} && length($hilite) > 0) {
393 ($results, $files) = getFilesHyperEstraier($param);
394 } else {
395 ($results, $files) = getFiles($param);
396 }
397
398 my $dur_t = time() - $start_t;
399 my $dur = sprintf("%0.4fs", $dur_t);
400
401 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
402
403 if ($results <= 0) {
404 $retHTML .= qq{
405 <p style="color: red;">No results found...</p>
406 };
407 return $retHTML;
408 } else {
409 # DEBUG
410 #use Data::Dumper;
411 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
412 }
413
414
415 $retHTML .= qq{
416 <div>
417 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
418 </div>
419 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
420 <tr class="fviewheader">
421 <td></td>
422 <td align="center">Share</td>
423 <td align="center">Type and Name</td>
424 <td align="center">#</td>
425 <td align="center">Size</td>
426 <td align="center">Date</td>
427 <td align="center">Media</td>
428 </tr>
429 };
430
431 my $file;
432
433 sub hilite_html($$) {
434 my ($html, $search) = @_;
435 $html =~ s#($search)#<b>$1</b>#gis;
436 return $html;
437 }
438
439 sub restore_link($$$$$$) {
440 my $type = shift;
441 my $action = 'RestoreFile';
442 $action = 'browse' if (lc($type) eq 'dir');
443 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
444 }
445
446 my $i = $offset * $on_page;
447
448 foreach $file (@{ $files }) {
449 $i++;
450
451 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
452 $retHTML .= qq{<tr class="fviewborder">};
453
454 $retHTML .= qq{<td class="fviewborder">$i</td>};
455
456 $retHTML .=
457 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
458 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
459 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
460 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
461 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
462 qq{<td class="fviewborder">} . '?' . qq{</td>};
463
464 $retHTML .= "</tr>";
465 }
466 $retHTML .= "</table>";
467
468 # all variables which has to be transfered
469 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/) {
470 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
471 }
472
473 my $del = '';
474 my $max_page = int( $results / $on_page );
475 my $page = 0;
476
477 sub page_link($$$) {
478 my ($param,$page,$display) = @_;
479
480 $param->{'offset'} = $page;
481
482 my $html = '<a href = "' . $MyURL;
483 my $del = '?';
484 foreach my $k (keys %{ $param }) {
485 if ($param->{$k}) {
486 $html .= $del . $k . '=' . ${EscURI( $param->{$k} )};
487 $del = '&';
488 }
489 }
490 $html .= '">' . $display . '</a>';
491 }
492
493 $retHTML .= '<div style="text-align: center;">';
494
495 if ($offset > 0) {
496 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
497 }
498
499 while ($page <= $max_page) {
500 if ($page == $offset) {
501 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
502 } else {
503 $retHTML .= $del . page_link($param, $page, $page + 1);
504 }
505
506 if ($page < $offset - $pager_pages && $page != 0) {
507 $retHTML .= " ... ";
508 $page = $offset - $pager_pages;
509 $del = '';
510 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
511 $retHTML .= " ... ";
512 $page = $max_page;
513 $del = '';
514 } else {
515 $del = ' | ';
516 $page++;
517 }
518 }
519
520 if ($offset < $max_page) {
521 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
522 }
523
524 $retHTML .= "</div>";
525
526 return $retHTML;
527 }
528
529 1;

  ViewVC Help
Powered by ViewVC 1.1.26