/[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 91 - (show annotations)
Sun Aug 28 17:53:46 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 13118 byte(s)
bug fix: require search string to be in filepath to produce same
results from HyperEstraier as from RDBMS.

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 getBackupsNotBurned() {
245
246 my $dbh = get_dbh();
247 my $sql = q{
248 SELECT
249 backups.hostID AS hostid,
250 min(hosts.name) AS host,
251 backups.num AS backupnum,
252 min(backups.type) AS type,
253 min(backups.date) AS date,
254 min(backups.size) AS size
255 FROM files
256 INNER JOIN shares ON files.shareID=shares.ID
257 INNER JOIN hosts ON hosts.ID = shares.hostID
258 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
259 GROUP BY
260 backups.hostID, backups.num
261 ORDER BY min(backups.date)
262 };
263 my $sth = $dbh->prepare( $sql );
264 my @ret;
265 $sth->execute();
266
267 while ( my $row = $sth->fetchrow_hashref() ) {
268 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
269 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
270 push @ret, $row;
271 }
272
273 return @ret;
274 }
275
276 sub displayBackupsGrid()
277 {
278 my $retHTML = "";
279 my $addForm = 1;
280
281 if ($addForm) {
282
283 $retHTML .= <<EOF3;
284 <script language="javascript" type="text/javascript">
285 <!--
286
287 function checkAll(location)
288 {
289 for (var i=0;i<document.forma.elements.length;i++)
290 {
291 var e = document.forma.elements[i];
292 if ((e.checked || !e.checked) && e.name != \'all\') {
293 if (eval("document.forma."+location+".checked")) {
294 e.checked = true;
295 } else {
296 e.checked = false;
297 }
298 }
299 }
300 }
301 //-->
302 </script>
303 EOF3
304 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
305 $retHTML.= q{<input type="hidden" value="burn" name="action">};
306 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
307 }
308 $retHTML .= qq{
309 <table style="fview" border="1" cellspacing="0" cellpadding="3">
310 <tr class="tableheader">
311 };
312
313 if ($addForm) {
314 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
315 }
316 $retHTML .= qq{
317 <td align="center">Host</td>
318 <td align="center">Backup no</td>
319 <td align="center">Type</td>
320 <td align="center">date</td>
321 <td align="center">age/days</td>
322 <td align="center">size/MB</td>
323 </tr>
324 };
325
326 my @backups = getBackupsNotBurned();
327 my $backup;
328
329 if ($addForm) {
330 $retHTML .= qq{
331 <tr><td colspan=7 style="tableheader">
332 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
333 </td></tr>
334 };
335 }
336
337 foreach $backup(@backups) {
338
339 my $ftype = "";
340
341 $retHTML .= "<tr>";
342 if ($addForm) {
343 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
344 $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
345 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
346 '"></td>';
347 }
348
349 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
350 '<td class="fviewborder">' . $backup->{'backupnum'} . '</td>' .
351 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
352 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
353 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
354 '<td class="fviewborder">' . $backup->{'size'} . '</td>' .
355 '</tr>';
356 }
357
358 $retHTML .= "</table>";
359
360 if ($addForm) {
361 $retHTML .= "</form>";
362 }
363
364 return $retHTML;
365 }
366
367 sub displayGrid($) {
368 my ($param) = @_;
369
370 my $offset = $param->{'offset'};
371 my $hilite = $param->{'search_filename'};
372
373 my $retHTML = "";
374
375 my $start_t = time();
376
377 my ($results, $files);
378 if ($param->{'use_hest'} && length($hilite) > 0) {
379 ($results, $files) = getFilesHyperEstraier($param);
380 } else {
381 ($results, $files) = getFiles($param);
382 }
383
384 my $dur_t = time() - $start_t;
385 my $dur = sprintf("%0.4fs", $dur_t);
386
387 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
388
389 if ($results <= 0) {
390 $retHTML .= qq{
391 <p style="color: red;">No results found...</p>
392 };
393 return $retHTML;
394 } else {
395 # DEBUG
396 #use Data::Dumper;
397 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
398 }
399
400
401 $retHTML .= qq{
402 <div>
403 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
404 </div>
405 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
406 <tr class="fviewheader">
407 <td></td>
408 <td align="center">Share</td>
409 <td align="center">Type and Name</td>
410 <td align="center">#</td>
411 <td align="center">Size</td>
412 <td align="center">Date</td>
413 <td align="center">Media</td>
414 </tr>
415 };
416
417 my $file;
418
419 sub hilite_html($$) {
420 my ($html, $search) = @_;
421 $html =~ s#($search)#<b>$1</b>#gis;
422 return $html;
423 }
424
425 sub restore_link($$$$$$) {
426 my $type = shift;
427 my $action = 'RestoreFile';
428 $action = 'browse' if (lc($type) eq 'dir');
429 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
430 }
431
432 my $i = $offset * $on_page;
433
434 foreach $file (@{ $files }) {
435 $i++;
436
437 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
438 $retHTML .= qq{<tr class="fviewborder">};
439
440 $retHTML .= qq{<td class="fviewborder">$i</td>};
441
442 $retHTML .=
443 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
444 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
445 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
446 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
447 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
448 qq{<td class="fviewborder">} . '?' . qq{</td>};
449
450 $retHTML .= "</tr>";
451 }
452 $retHTML .= "</table>";
453
454 # all variables which has to be transfered
455 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/) {
456 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
457 }
458
459 my $del = '';
460 my $max_page = int( $results / $on_page );
461 my $page = 0;
462
463 sub page_link($$$) {
464 my ($param,$page,$display) = @_;
465
466 $param->{'offset'} = $page;
467
468 my $html = '<a href = "' . $MyURL;
469 my $del = '?';
470 foreach my $k (keys %{ $param }) {
471 if ($param->{$k}) {
472 $html .= $del . $k . '=' . ${EscURI( $param->{$k} )};
473 $del = '&';
474 }
475 }
476 $html .= '">' . $display . '</a>';
477 }
478
479 $retHTML .= '<div style="text-align: center;">';
480
481 if ($offset > 0) {
482 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
483 }
484
485 while ($page <= $max_page) {
486 if ($page == $offset) {
487 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
488 } else {
489 $retHTML .= $del . page_link($param, $page, $page + 1);
490 }
491
492 if ($page < $offset - $pager_pages && $page != 0) {
493 $retHTML .= " ... ";
494 $page = $offset - $pager_pages;
495 $del = '';
496 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
497 $retHTML .= " ... ";
498 $page = $max_page;
499 $del = '';
500 } else {
501 $del = ' | ';
502 $page++;
503 }
504 }
505
506 if ($offset < $max_page) {
507 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
508 }
509
510 $retHTML .= "</div>";
511
512 return $retHTML;
513 }
514
515 1;

  ViewVC Help
Powered by ViewVC 1.1.26