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 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
22 my $sth = $dbh->prepare(qq{ SELECT id, share FROM shares} );
24 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
26 while ( my $row = $sth->fetchrow_hashref() ) {
34 my $t = shift || return;
35 my $dt = DateTime->from_epoch( epoch => $t ) || return;
36 print STDERR "BUG: $t != " . $dt->epoch . "\n" unless ($t == $dt->epoch);
37 return $dt->ymd . ' ' . $dt->hms;
44 sub mk_epoch_date($$) {
45 my ($name,$suffix) = @_;
47 my $yyyy = $param->{ $name . '_year_' . $suffix} || return;
48 my $mm .= $param->{ $name . '_month_' . $suffix} ||
49 ( $suffix eq 'from' ? 1 : 12);
50 my $dd .= $param->{ $name . '_day_' . $suffix} ||
51 ( $suffix eq 'from' ? 1 : 31);
52 my $dt = new DateTime(
57 return $dt->epoch || 'NULL';
60 my $backup_from = mk_epoch_date('search_backup', 'from');
61 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
62 my $backup_to = mk_epoch_date('search_backup', 'to');
63 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
65 my $files_from = mk_epoch_date('search', 'from');
66 push @conditions, qq{ files.date >= $files_from } if ($files_from);
67 my $files_to = mk_epoch_date('search', 'to');
68 push @conditions, qq{ files.date <= $files_to } if ($files_to);
70 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
72 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
74 push (@conditions, " upper(files.name) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
77 join(" and ", @conditions),
78 $files_from, $files_to,
79 $backup_from, $backup_to
85 my ($where, $offset) = @_;
87 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
93 shares.share AS sharename,
94 files.backupNum AS backupNum,
95 files.name AS filename,
96 files.path AS filepath,
97 shares.share||files.fullpath AS networkPath,
99 files.type AS filetype,
106 INNER JOIN shares ON files.shareID=shares.ID
107 INNER JOIN hosts ON hosts.ID = shares.hostID
108 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID
111 my $sql_dvd_from = qq{
112 LEFT JOIN dvds ON dvds.ID = files.dvdid
116 $sql_where = " WHERE ". $where if ($where);
124 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
125 my $sql_results = qq{ select $sql_cols $sql_from $sql_dvd_from $sql_where $sql_order };
128 $offset = ($offset * $on_page);
130 my $sth = $dbh->prepare($sql_count);
132 my ($results) = $sth->fetchrow_array();
134 $sth = $dbh->prepare($sql_results);
135 $sth->execute( $offset );
137 if ($sth->rows != $results) {
138 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
140 print STDERR "$bug\n";
145 while (my $row = $sth->fetchrow_hashref()) {
147 'hname' => $row->{'hname'},
148 'sname' => $row->{'sname'},
149 'sharename' => $row->{'sharename'},
150 'backupno' => $row->{'backupnum'},
151 'fname' => $row->{'filename'},
152 'fpath' => $row->{'filepath'},
153 'networkpath' => $row->{'networkpath'},
154 'date' => $row->{'date'},
155 'type' => $row->{'filetype'},
156 'size' => $row->{'size'},
157 'id' => $row->{'fid'},
158 'dvd' => $row->{'dvd'}
164 return ($results, \@ret);
167 sub getBackupsNotBurned() {
169 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
173 min(hosts.name) AS host,
174 backups.num AS backupno,
175 min(backups.type) AS type,
176 min(backups.date) AS date
177 FROM backups, shares, files, hosts
179 backups.num = files.backupNum AND
180 shares.ID = files.shareID AND
181 backups.hostID = shares.hostID AND
182 hosts.ID = backups.hostID AND
185 backups.hostID, backups.num, hosts.id
186 ORDER BY min(backups.date)
188 my $sth = $dbh->prepare( $sql );
192 while ( my $row = $sth->fetchrow_hashref() ) {
194 'host' => $row->{'host'},
195 'hostid' => $row->{'hostid'},
196 'backupno' => $row->{'backupno'},
197 'type' => $row->{'type'},
198 'date' => $row->{'date'},
199 'age' => sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) ),
207 sub displayBackupsGrid()
215 <script language="javascript" type="text/javascript">
218 function checkAll(location)
220 for (var i=0;i<document.forma.elements.length;i++)
222 var e = document.forma.elements[i];
223 if ((e.checked || !e.checked) && e.name != \'all\') {
224 if (eval("document.forma."+location+".checked")) {
235 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
236 $retHTML.= q{<input type="hidden" value="burn" name="action">};
237 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
239 $retHTML .= qq{<table style="fview"><tr>};
242 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
245 <td class="tableheader">Host</td>
246 <td class="tableheader">Backup no</td>
247 <td class="tableheader">Type</td>
248 <td class="tableheader">date</td>
249 <td class="tableheader">age/days</td>
253 my @backups = getBackupsNotBurned();
258 <tr><td colspan=7 style="tableheader">
259 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
264 foreach $backup(@backups) {
270 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
271 $backup->{'hostid'}.'_'.$backup->{'backupno'} .
272 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupno'} .
276 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
277 '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .
278 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
279 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
280 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
284 $retHTML .= "</table>";
287 $retHTML .= "</form>";
293 sub displayGrid($$$$) {
294 my ($where, $addForm, $offset, $hilite) = @_;
297 my $start_t = time();
299 my ($results, $files) = getFiles($where, $offset);
301 my $dur_t = time() - $start_t;
302 my $dur = sprintf("%0.4fs", $dur_t);
304 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
308 <p style="color: red;">No results found...</p>
314 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
319 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};
320 $retHTML.= qq{<input type="hidden" value="search" name="action">};
321 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};
326 <br/>Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
327 <table style="fview" width="100%">
329 <td class="tableheader">Share</td>
330 <td class="tableheader">Name</td>
331 <td class="tableheader">Type</td>
332 <td class="tableheader">#</td>
333 <td class="tableheader">Size</td>
334 <td class="tableheader">Date</td>
335 <td class="tableheader">Media</td>
341 sub hilite_html($$) {
342 my ($html, $search) = @_;
343 $html =~ s#($search)#<b>$1</b>#gis;
347 sub restore_link($$$$$$) {
349 my $action = 'RestoreFile';
350 $action = 'browse' if (lc($type) eq 'dir');
351 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
354 foreach $file (@{ $files }) {
355 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
359 $file->{'sharename'},
360 qq{<img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" align="center"> } . hilite_html( $file->{'fpath'}, $hilite ),
362 restore_link( $typeStr, $file->{'hname'}, $file->{'backupno'}, $file->{'sname'}, $file->{'fpath'}, $file->{'backupno'} ),
364 epoch_to_iso( $file->{'date'} ),
367 $retHTML .= qq{<td class="fviewborder">$v</td>};
372 $retHTML .= "</table>";
374 # all variables which has to be transfered
375 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/) {
376 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
380 my $max_page = int( $results / $on_page );
383 my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';
385 $retHTML .= '<div style="text-align: center;">';
388 $retHTML .= sprintf($link_fmt, $offset - 1, '<<') . ' ';
391 while ($page <= $max_page) {
392 if ($page == $offset) {
393 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
395 $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);
398 if ($page < $offset - $pager_pages && $page != 0) {
400 $page = $offset - $pager_pages;
402 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
412 if ($offset < $max_page) {
413 $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '>>');
416 $retHTML .= "</div>";
418 $retHTML .= "</form>" if ($addForm);