/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 117 - (hide annotations)
Sun Sep 11 13:05:06 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 14480 byte(s)
added node search

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

  ViewVC Help
Powered by ViewVC 1.1.26