/[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 86 - (show annotations)
Sun Aug 28 12:35:59 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 12976 byte(s)
first cut at implemeting HyperEstraier search,
shares are now formated like host:share, fix date display,
initial cut at removing unneeded database columns,
rename all fields to comply with database columns

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

  ViewVC Help
Powered by ViewVC 1.1.26