/[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 66 - (show annotations)
Mon Aug 22 00:09:59 2005 UTC (18 years, 9 months ago) by dpavlin
File size: 11052 byte(s)
calculate size for each backup (this is more accurate than reading meta data
if you aren't staring from clean BackupPC installation).

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 sub getUnits() {
19 my @ret;
20
21 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
22 my $sth = $dbh->prepare(qq{ SELECT id, share FROM shares} );
23 $sth->execute();
24 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
25
26 while ( my $row = $sth->fetchrow_hashref() ) {
27 push @ret, $row;
28 }
29 $dbh->disconnect();
30 return @ret;
31 }
32
33 sub epoch_to_iso {
34 my $t = shift || return;
35 $t += 60 * 60 * +2; # FIXME add TZ
36 my $dt = DateTime->from_epoch( epoch => $t ) || return;
37 print STDERR "BUG: $t != " . $dt->epoch . "\n" unless ($t == $dt->epoch);
38 return $dt->ymd . ' ' . $dt->hms;
39 }
40
41 sub getWhere($) {
42 my ($param) = @_;
43 my @conditions;
44
45 sub mk_epoch_date($$) {
46 my ($name,$suffix) = @_;
47
48 my $yyyy = $param->{ $name . '_year_' . $suffix} || return;
49 my $mm .= $param->{ $name . '_month_' . $suffix} ||
50 ( $suffix eq 'from' ? 1 : 12);
51 my $dd .= $param->{ $name . '_day_' . $suffix} ||
52 ( $suffix eq 'from' ? 1 : 31);
53 my $dt = new DateTime(
54 year => $yyyy,
55 month => $mm,
56 day => $dd
57 );
58 return $dt->epoch || 'NULL';
59 }
60
61 my $backup_from = mk_epoch_date('search_backup', 'from');
62 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
63 my $backup_to = mk_epoch_date('search_backup', 'to');
64 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
65
66 my $files_from = mk_epoch_date('search', 'from');
67 push @conditions, qq{ files.date >= $files_from } if ($files_from);
68 my $files_to = mk_epoch_date('search', 'to');
69 push @conditions, qq{ files.date <= $files_to } if ($files_to);
70
71 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
72
73 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
74
75 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
76
77 return (
78 join(" and ", @conditions),
79 $files_from, $files_to,
80 $backup_from, $backup_to
81 );
82 }
83
84
85 sub getFiles($$) {
86 my ($where, $offset) = @_;
87
88 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
89
90 my $sql_cols = qq{
91 files.id AS fid,
92 hosts.name AS hname,
93 shares.name AS sname,
94 shares.share AS sharename,
95 files.backupNum AS backupNum,
96 files.name AS filename,
97 files.path AS filepath,
98 files.date AS date,
99 files.type AS filetype,
100 files.size AS size,
101 dvds.name AS dvd
102 };
103
104 my $sql_from = qq{
105 FROM files
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 AND backups.shareID = shares.ID
109 };
110
111 my $sql_dvd_from = qq{
112 LEFT JOIN dvds ON dvds.ID = files.dvdid
113 };
114
115 my $sql_where;
116 $sql_where = " WHERE ". $where if ($where);
117
118 my $sql_order = qq{
119 ORDER BY files.date
120 LIMIT $on_page
121 OFFSET ?
122 };
123
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 };
126
127 $offset ||= 0;
128 $offset = ($offset * $on_page);
129
130 my $sth = $dbh->prepare($sql_count);
131 $sth->execute();
132 my ($results) = $sth->fetchrow_array();
133
134 $sth = $dbh->prepare($sql_results);
135 $sth->execute( $offset );
136
137 if ($sth->rows != $results) {
138 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
139 $bug =~ s/\s+/ /gs;
140 print STDERR "$bug\n";
141 }
142
143 my @ret;
144
145 while (my $row = $sth->fetchrow_hashref()) {
146 push(@ret, {
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'}
159 });
160 }
161
162 $sth->finish();
163 $dbh->disconnect();
164 return ($results, \@ret);
165 }
166
167 sub getBackupsNotBurned() {
168
169 my $dbh = DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
170 my $sql = q{
171 SELECT
172 backups.hostID AS hostid,
173 min(hosts.name) AS host,
174 backups.num AS backupno,
175 min(backups.type) AS type,
176 min(backups.date) AS date,
177 min(backups.size) AS size
178 FROM backups
179 INNER JOIN hosts ON hosts.ID = backups.hostID
180 WHERE
181 files.dvdid IS NULL
182 GROUP BY
183 backups.hostID, backups.num
184 ORDER BY min(backups.date)
185 };
186 my $sth = $dbh->prepare( $sql );
187 my @ret;
188 $sth->execute();
189
190 while ( my $row = $sth->fetchrow_hashref() ) {
191 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
192 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
193 push @ret, $row;
194 }
195
196 return @ret;
197 }
198
199 sub displayBackupsGrid()
200 {
201 my $retHTML = "";
202 my $addForm = 1;
203
204 if ($addForm) {
205
206 $retHTML .= <<EOF3;
207 <script language="javascript" type="text/javascript">
208 <!--
209
210 function checkAll(location)
211 {
212 for (var i=0;i<document.forma.elements.length;i++)
213 {
214 var e = document.forma.elements[i];
215 if ((e.checked || !e.checked) && e.name != \'all\') {
216 if (eval("document.forma."+location+".checked")) {
217 e.checked = true;
218 } else {
219 e.checked = false;
220 }
221 }
222 }
223 }
224 //-->
225 </script>
226 EOF3
227 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
228 $retHTML.= q{<input type="hidden" value="burn" name="action">};
229 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
230 }
231 $retHTML .= qq{<table style="fview"><tr>};
232
233 if ($addForm) {
234 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
235 }
236 $retHTML .= qq{
237 <td class="tableheader">Host</td>
238 <td class="tableheader">Backup no</td>
239 <td class="tableheader">Type</td>
240 <td class="tableheader">date</td>
241 <td class="tableheader">age/days</td>
242 <td class="tableheader">size/MB</td>
243 </tr>
244 };
245
246 my @backups = getBackupsNotBurned();
247 my $backup;
248
249 if ($addForm) {
250 $retHTML .= qq{
251 <tr><td colspan=7 style="tableheader">
252 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
253 </td></tr>
254 };
255 }
256
257 foreach $backup(@backups) {
258
259 my $ftype = "";
260
261 $retHTML .= "<tr>";
262 if ($addForm) {
263 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
264 $backup->{'hostid'}.'_'.$backup->{'backupno'} .
265 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupno'} .
266 '"></td>';
267 }
268
269 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
270 '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .
271 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
272 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
273 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
274 '<td class="fviewborder">' . $backup->{'size'} . '</td>' .
275 '</tr>';
276 }
277
278 $retHTML .= "</table>";
279
280 if ($addForm) {
281 $retHTML .= "</form>";
282 }
283
284 return $retHTML;
285 }
286
287 sub displayGrid($$$$) {
288 my ($where, $addForm, $offset, $hilite) = @_;
289 my $retHTML = "";
290
291 my $start_t = time();
292
293 my ($results, $files) = getFiles($where, $offset);
294
295 my $dur_t = time() - $start_t;
296 my $dur = sprintf("%0.4fs", $dur_t);
297
298 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
299
300 if ($results <= 0) {
301 $retHTML .= qq{
302 <p style="color: red;">No results found...</p>
303 };
304 return $retHTML;
305 } else {
306 # DEBUG
307 #use Data::Dumper;
308 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
309 }
310
311
312 if ($addForm) {
313 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};
314 $retHTML.= qq{<input type="hidden" value="search" name="action">};
315 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};
316 }
317
318
319 $retHTML .= qq{
320 <br/>Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
321 <table style="fview" width="100%">
322 <tr>
323 <td class="tableheader">Share</td>
324 <td class="tableheader">Name</td>
325 <td class="tableheader">Type</td>
326 <td class="tableheader">#</td>
327 <td class="tableheader">Size</td>
328 <td class="tableheader">Date</td>
329 <td class="tableheader">Media</td>
330 </tr>
331 };
332
333 my $file;
334
335 sub hilite_html($$) {
336 my ($html, $search) = @_;
337 $html =~ s#($search)#<b>$1</b>#gis;
338 return $html;
339 }
340
341 sub restore_link($$$$$$) {
342 my $type = shift;
343 my $action = 'RestoreFile';
344 $action = 'browse' if (lc($type) eq 'dir');
345 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
346 }
347
348 foreach $file (@{ $files }) {
349 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
350 $retHTML .= "<tr>";
351
352 foreach my $v ((
353 $file->{'sharename'},
354 qq{<img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" align="center">&nbsp;} . hilite_html( $file->{'fpath'}, $hilite ),
355 $typeStr,
356 restore_link( $typeStr, $file->{'hname'}, $file->{'backupno'}, $file->{'sname'}, $file->{'fpath'}, $file->{'backupno'} ),
357 $file->{'size'},
358 epoch_to_iso( $file->{'date'} ),
359 $file->{'dvd'}
360 )) {
361 $retHTML .= qq{<td class="fviewborder">$v</td>};
362 }
363
364 $retHTML .= "</tr>";
365 }
366 $retHTML .= "</table>";
367
368 # all variables which has to be transfered
369 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/) {
370 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
371 }
372
373 my $del = '';
374 my $max_page = int( $results / $on_page );
375 my $page = 0;
376
377 my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';
378
379 $retHTML .= '<div style="text-align: center;">';
380
381 if ($offset > 0) {
382 $retHTML .= sprintf($link_fmt, $offset - 1, '&lt;&lt;') . ' ';
383 }
384
385 while ($page <= $max_page) {
386 if ($page == $offset) {
387 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
388 } else {
389 $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);
390 }
391
392 if ($page < $offset - $pager_pages && $page != 0) {
393 $retHTML .= " ... ";
394 $page = $offset - $pager_pages;
395 $del = '';
396 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
397 $retHTML .= " ... ";
398 $page = $max_page;
399 $del = '';
400 } else {
401 $del = ' | ';
402 $page++;
403 }
404 }
405
406 if ($offset < $max_page) {
407 $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '&gt;&gt;');
408 }
409
410 $retHTML .= "</div>";
411
412 $retHTML .= "</form>" if ($addForm);
413
414 return $retHTML;
415 }
416
417 1;

  ViewVC Help
Powered by ViewVC 1.1.26