2 package BackupPC::SearchLib;
5 use BackupPC::CGI::Lib qw(:all);
6 use BackupPC::Attrib qw(:all);
9 use vars qw(%In $MyURL);
10 use Time::HiRes qw/time/;
15 my $dsn = $Conf{SearchDSN};
16 my $db_user = $Conf{SearchUser} || '';
21 $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
29 my $sth = $dbh->prepare(qq{ SELECT id, share FROM shares ORDER BY share} );
31 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
33 while ( my $row = $sth->fetchrow_hashref() ) {
40 my $t = shift || return;
41 my $iso = BackupPC::Lib::timeStamp($t);
42 $iso =~ s/\s/ /g;
46 sub dates_from_form($) {
47 my $param = shift || return;
49 sub mk_epoch_date($$) {
50 my ($name,$suffix) = @_;
52 my $yyyy = $param->{ $name . '_year_' . $suffix} || return;
53 my $mm .= $param->{ $name . '_month_' . $suffix} ||
54 ( $suffix eq 'from' ? 1 : 12);
55 my $dd .= $param->{ $name . '_day_' . $suffix} ||
56 ( $suffix eq 'from' ? 1 : 31);
57 my $dt = new DateTime(
62 return $dt->epoch || 'NULL';
66 mk_epoch_date('search_backup', 'from'),
67 mk_epoch_date('search_backup', 'to'),
68 mk_epoch_date('search', 'from'),
69 mk_epoch_date('search', 'to'),
75 my $param = shift || return;
77 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
80 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
81 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
82 push @conditions, qq{ files.date >= $files_from } if ($files_from);
83 push @conditions, qq{ files.date <= $files_to } if ($files_to);
85 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
87 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
88 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
90 return join(" and ", @conditions);
95 my ($param, $offset) = @_;
102 shares.name AS sname,
103 shares.share AS sharename,
104 files.backupNum AS backupNum,
105 files.name AS filename,
106 files.path AS filepath,
108 files.type AS filetype,
116 INNER JOIN shares ON files.shareID=shares.ID
117 INNER JOIN hosts ON hosts.ID = shares.hostID
118 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
121 my $sql_dvd_from = qq{
122 -- LEFT JOIN dvds ON dvds.ID = files.dvdid
126 my $where = getWhere($param);
127 $sql_where = " WHERE ". $where if ($where);
135 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
136 my $sql_results = qq{ select $sql_cols $sql_from $sql_dvd_from $sql_where $sql_order };
139 $offset = ($offset * $on_page);
141 my $sth = $dbh->prepare($sql_count);
143 my ($results) = $sth->fetchrow_array();
145 $sth = $dbh->prepare($sql_results);
146 $sth->execute( $offset );
148 if ($sth->rows != $results) {
149 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
151 print STDERR "$bug\n";
156 while (my $row = $sth->fetchrow_hashref()) {
158 'hname' => $row->{'hname'},
159 'sname' => $row->{'sname'},
160 'sharename' => $row->{'sharename'},
161 'backupno' => $row->{'backupnum'},
162 'fname' => $row->{'filename'},
163 'fpath' => $row->{'filepath'},
164 'networkpath' => $row->{'networkpath'},
165 'date' => $row->{'date'},
166 'type' => $row->{'filetype'},
167 'size' => $row->{'size'},
168 'id' => $row->{'fid'},
169 'dvd' => $row->{'dvd'}
174 return ($results, \@ret);
177 sub getBackupsNotBurned() {
182 backups.hostID AS hostid,
183 min(hosts.name) AS host,
184 backups.num AS backupno,
185 min(backups.type) AS type,
186 min(backups.date) AS date,
187 min(backups.size) AS size
189 INNER JOIN shares ON files.shareID=shares.ID
190 INNER JOIN hosts ON hosts.ID = shares.hostID
191 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
195 backups.hostID, backups.num
196 ORDER BY min(backups.date)
198 my $sth = $dbh->prepare( $sql );
202 while ( my $row = $sth->fetchrow_hashref() ) {
203 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
204 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
211 sub displayBackupsGrid()
219 <script language="javascript" type="text/javascript">
222 function checkAll(location)
224 for (var i=0;i<document.forma.elements.length;i++)
226 var e = document.forma.elements[i];
227 if ((e.checked || !e.checked) && e.name != \'all\') {
228 if (eval("document.forma."+location+".checked")) {
239 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
240 $retHTML.= q{<input type="hidden" value="burn" name="action">};
241 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
244 <table style="fview" border="1" cellspacing="0" cellpadding="3">
245 <tr class="tableheader">
249 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
252 <td align="center">Host</td>
253 <td align="center">Backup no</td>
254 <td align="center">Type</td>
255 <td align="center">date</td>
256 <td align="center">age/days</td>
257 <td align="center">size/MB</td>
261 my @backups = getBackupsNotBurned();
266 <tr><td colspan=7 style="tableheader">
267 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
272 foreach $backup(@backups) {
278 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
279 $backup->{'hostid'}.'_'.$backup->{'backupno'} .
280 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupno'} .
284 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
285 '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .
286 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
287 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
288 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
289 '<td class="fviewborder">' . $backup->{'size'} . '</td>' .
293 $retHTML .= "</table>";
296 $retHTML .= "</form>";
302 sub displayGrid($$) {
303 my ($param, $addForm) = @_;
305 my $offset = $param->{'offset'};
306 my $hilite = $param->{'search_filename'};
310 my $start_t = time();
312 my ($results, $files) = getFiles($param, $offset);
314 my $dur_t = time() - $start_t;
315 my $dur = sprintf("%0.4fs", $dur_t);
317 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
321 <p style="color: red;">No results found...</p>
327 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
332 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};
333 $retHTML.= qq{<input type="hidden" value="search" name="action">};
334 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};
340 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
342 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
343 <tr class="fviewheader">
344 <td align="center">Share</td>
345 <td align="center">Type and Name</td>
346 <td align="center">#</td>
347 <td align="center">Size</td>
348 <td align="center">Date</td>
349 <td align="center">Media</td>
355 sub hilite_html($$) {
356 my ($html, $search) = @_;
357 $html =~ s#($search)#<b>$1</b>#gis;
361 sub restore_link($$$$$$) {
363 my $action = 'RestoreFile';
364 $action = 'browse' if (lc($type) eq 'dir');
365 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
368 foreach $file (@{ $files }) {
369 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
370 $retHTML .= qq{<tr class="fviewborder">};
373 qq{<td class="fviewborder" align="right">} . $file->{'sharename'} . qq{</td>} .
374 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle"> } . hilite_html( $file->{'fpath'}, $hilite ) . qq{</td>} .
375 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupno'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'fpath'} )}, $file->{'backupno'} ) . qq{</td>} .
376 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
377 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
378 qq{<td class="fviewborder">} . $file->{'dvd'} . qq{</td>};
382 $retHTML .= "</table>";
384 # all variables which has to be transfered
385 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/) {
386 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
390 my $max_page = int( $results / $on_page );
393 my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';
395 $retHTML .= '<div style="text-align: center;">';
398 $retHTML .= sprintf($link_fmt, $offset - 1, '<<') . ' ';
401 while ($page <= $max_page) {
402 if ($page == $offset) {
403 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
405 $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);
408 if ($page < $offset - $pager_pages && $page != 0) {
410 $page = $offset - $pager_pages;
412 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
422 if ($offset < $max_page) {
423 $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '>>');
426 $retHTML .= "</div>";
428 $retHTML .= "</form>" if ($addForm);