/[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 229 - (show annotations)
Tue Oct 25 09:30:51 2005 UTC (18 years, 6 months ago) by dpavlin
File size: 27092 byte(s)
 r8684@llin:  dpavlin | 2005-10-25 10:42:58 +0200
 added unicode arrows to show sort order, cleanup sort_header a bit

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 use XML::Writer;
12 use IO::File;
13
14 my $on_page = 100;
15 my $pager_pages = 10;
16
17 my $dsn = $Conf{SearchDSN};
18 my $db_user = $Conf{SearchUser} || '';
19
20 my $hest_index_path = $Conf{HyperEstraierIndex};
21
22 my $dbh;
23
24 sub get_dbh {
25 $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
26 return $dbh;
27 }
28
29 sub getUnits() {
30 my @ret;
31
32 my $dbh = get_dbh();
33 my $sth = $dbh->prepare(qq{
34 SELECT
35 shares.id as id,
36 hosts.name || ':' || shares.name as share
37 FROM shares
38 JOIN hosts on hostid = hosts.id
39 ORDER BY share
40 } );
41 $sth->execute();
42 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
43
44 while ( my $row = $sth->fetchrow_hashref() ) {
45 push @ret, $row;
46 }
47 return @ret;
48 }
49
50 sub epoch_to_iso {
51 my $t = shift || return;
52 my $iso = BackupPC::Lib::timeStamp(undef, $t);
53 $iso =~ s/\s/ /g;
54 return $iso;
55 }
56
57 sub dates_from_form($) {
58 my $param = shift || return;
59
60 sub mk_epoch_date($$) {
61 my ($name,$suffix) = @_;
62
63 my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
64 my $mm .= $param->{ $name . '_month_' . $suffix} ||
65 ( $suffix eq 'from' ? 1 : 12);
66 my $dd .= $param->{ $name . '_day_' . $suffix} ||
67 ( $suffix eq 'from' ? 1 : 31);
68
69 $yyyy =~ s/\D//g;
70 $mm =~ s/\D//g;
71 $dd =~ s/\D//g;
72
73 my $h = my $m = my $s = 0;
74 if ($suffix eq 'to') {
75 $h = 23;
76 $m = 59;
77 $s = 59;
78 }
79
80 my $dt = new DateTime(
81 year => $yyyy,
82 month => $mm,
83 day => $dd,
84 hour => $h,
85 minute => $m,
86 second => $s,
87 );
88 print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n";
89 return $dt->epoch || 'NULL';
90 }
91
92 my @ret = (
93 mk_epoch_date('search_backup', 'from'),
94 mk_epoch_date('search_backup', 'to'),
95 mk_epoch_date('search', 'from'),
96 mk_epoch_date('search', 'to'),
97 );
98
99 return @ret;
100
101 }
102
103
104 sub getWhere($) {
105 my $param = shift || return;
106
107 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
108
109 my @conditions;
110 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
111 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
112 push @conditions, qq{ files.date >= $files_from } if ($files_from);
113 push @conditions, qq{ files.date <= $files_to } if ($files_to);
114
115 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" and ",@conditions);
116
117 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
118 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
119
120 return join(" and ", @conditions);
121 }
122
123 my $sort_def = {
124 search => {
125 default => 'date_a',
126 sql => {
127 share_d => 'shares.name DESC',
128 share_a => 'shares.name ASC',
129 path_d => 'files.path DESC',
130 path_a => 'files.path ASC',
131 num_d => 'files.backupnum DESC',
132 num_a => 'files.backupnum ASC',
133 size_d => 'files.size DESC',
134 size_a => 'files.size ASC',
135 date_d => 'files.date DESC',
136 date_a => 'files.date ASC',
137 },
138 est => {
139 share_d => 'sname STRD',
140 share_a => 'sname STRA',
141 path_d => 'filepath STRD',
142 path_a => 'filepath STRA',
143 num_d => 'backupnum NUMD',
144 num_a => 'backupnum NUMA',
145 size_d => 'size NUMD',
146 size_a => 'size NUMA',
147 date_d => 'date NUMD',
148 date_a => 'date NUMA',
149 }
150 }, burn => {
151 default => 'date_a',
152 sql => {
153 share_d => 'host DESC, share DESC',
154 share_a => 'host ASC, share ASC',
155 num_d => 'backupnum DESC',
156 num_a => 'backupnum ASC',
157 date_d => 'date DESC',
158 date_a => 'date ASC',
159 age_d => 'age DESC',
160 age_a => 'age ASC',
161 size_d => 'size DESC',
162 size_a => 'size ASC',
163 incsize_d => 'inc_size DESC',
164 incsize_a => 'inc_size ASC',
165 }
166 }
167 };
168
169 sub getSort($$$) {
170 my ($part,$type, $sort_order) = @_;
171
172 die "unknown part: $part" unless ($sort_def->{$part});
173 die "unknown type: $type" unless ($sort_def->{$part}->{$type});
174
175 $sort_order ||= $sort_def->{$part}->{'default'};
176
177 if (my $ret = $sort_def->{$part}->{$type}->{$sort_order}) {
178 return $ret;
179 } else {
180 # fallback to default sort order
181 return $sort_def->{$part}->{$type}->{ $sort_def->{$part}->{'default'} };
182 }
183 }
184
185 sub getFiles($) {
186 my ($param) = @_;
187
188 my $offset = $param->{'offset'} || 0;
189 $offset *= $on_page;
190
191 my $dbh = get_dbh();
192
193 my $sql_cols = qq{
194 files.id AS fid,
195 hosts.name AS hname,
196 shares.name AS sname,
197 files.backupnum AS backupnum,
198 files.path AS filepath,
199 files.date AS date,
200 files.type AS type,
201 files.size AS size
202 };
203
204 my $sql_from = qq{
205 FROM files
206 INNER JOIN shares ON files.shareID=shares.ID
207 INNER JOIN hosts ON hosts.ID = shares.hostID
208 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
209 };
210
211 my $sql_where;
212 my $where = getWhere($param);
213 $sql_where = " WHERE ". $where if ($where);
214
215 my $order = getSort('search', 'sql', $param->{'sort'});
216
217 my $sql_order = qq{
218 ORDER BY $order
219 LIMIT $on_page
220 OFFSET ?
221 };
222
223 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
224 my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
225
226 my $sth = $dbh->prepare($sql_count);
227 $sth->execute();
228 my ($results) = $sth->fetchrow_array();
229
230 $sth = $dbh->prepare($sql_results);
231 $sth->execute( $offset );
232
233 if ($sth->rows != $results) {
234 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
235 $bug =~ s/\s+/ /gs;
236 print STDERR "$bug\n";
237 }
238
239 my @ret;
240
241 while (my $row = $sth->fetchrow_hashref()) {
242 push @ret, $row;
243 }
244
245 $sth->finish();
246 return ($results, \@ret);
247 }
248
249 sub getHyperEstraier_url($) {
250 my ($use_hest) = @_;
251
252 return unless $use_hest;
253
254 use HyperEstraier;
255 my ($index_path, $index_node_url);
256
257 if ($use_hest =~ m#^http://#) {
258 $index_node_url = $use_hest;
259 } else {
260 $index_path = $TopDir . '/' . $index_path;
261 $index_path =~ s#//#/#g;
262 }
263 return ($index_path, $index_node_url);
264 }
265
266 sub getFilesHyperEstraier($) {
267 my ($param) = @_;
268
269 my $offset = $param->{'offset'} || 0;
270 $offset *= $on_page;
271
272 die "no index_path?" unless ($hest_index_path);
273
274 use HyperEstraier;
275
276 my ($index_path, $index_node_url) = getHyperEstraier_url($hest_index_path);
277
278 # open the database
279 my $db;
280 if ($index_path) {
281 $db = HyperEstraier::Database->new();
282 $db->open($index_path, $HyperEstraier::ESTDBREADER);
283 } elsif ($index_node_url) {
284 $db ||= HyperEstraier::Node->new($index_node_url);
285 $db->set_auth('admin', 'admin');
286 } else {
287 die "BUG: unimplemented";
288 }
289
290 # create a search condition object
291 my $cond = HyperEstraier::Condition->new();
292
293 my $q = $param->{'search_filename'};
294 my $shareid = $param->{'search_share'};
295
296 if (length($q) > 0) {
297 # exact match
298 $cond->add_attr("filepath ISTRINC $q");
299
300 $q =~ s/(.)/$1 /g;
301 # set the search phrase to the search condition object
302 $cond->set_phrase($q);
303 }
304
305 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
306
307 $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
308 $cond->add_attr("backup_date NUMLE $backup_to") if ($backup_to);
309
310 $cond->add_attr("date NUMGE $files_from") if ($files_from);
311 $cond->add_attr("date NUMLE $files_to") if ($files_to);
312
313 $cond->add_attr("shareid NUMEQ $shareid") if ($shareid);
314
315 # $cond->set_max( $offset + $on_page );
316 $cond->set_options( $HyperEstraier::Condition::SURE );
317 $cond->set_order( getSort('search', 'est', $param->{'sort'} ) );
318
319 # get the result of search
320 my @res;
321 my ($result, $hits);
322
323 if ($index_path) {
324 $result = $db->search($cond, 0);
325 $hits = $result->size;
326 } elsif ($index_node_url) {
327 $result = $db->search($cond, 0);
328 $hits = $result->doc_num;
329 } else {
330 die "BUG: unimplemented";
331 }
332
333 # for each document in result
334 for my $i ($offset .. ($offset + $on_page - 1)) {
335 last if ($i >= $hits);
336
337 my $doc;
338 if ($index_path) {
339 my $id = $result->get($i);
340 $doc = $db->get_doc($id, 0);
341 } elsif ($index_node_url) {
342 $doc = $result->get_doc($i);
343 } else {
344 die "BUG: unimplemented";
345 }
346
347 my $row;
348 foreach my $c (qw/fid hname sname backupnum filepath date type size/) {
349 $row->{$c} = $doc->attr($c);
350 }
351 push @res, $row;
352 }
353
354 return ($hits, \@res);
355 }
356
357 sub getGzipName($$$)
358 {
359 my ($host, $share, $backupnum) = @_;
360 my $ret = $Conf{GzipSchema};
361
362 $share =~ s/\//_/g;
363 $ret =~ s/\\h/$host/ge;
364 $ret =~ s/\\s/$share/ge;
365 $ret =~ s/\\n/$backupnum/ge;
366
367 $ret =~ s/__+/_/g;
368
369 return $ret;
370
371 }
372
373 sub get_tgz_size_by_name($) {
374 my $name = shift;
375
376 my $tgz = $Conf{InstallDir}.'/'.$Conf{GzipTempDir}.'/'.$name;
377
378 my $size = -1;
379
380 if (-f $tgz) {
381 $size = (stat($tgz))[7];
382 } elsif (-d $tgz) {
383 opendir(my $dir, $tgz) || die "can't opendir $tgz: $!";
384 my @parts = grep { !/^\./ && -f "$tgz/$_" } readdir($dir);
385 $size = 0;
386 foreach my $part (@parts) {
387 $size += (stat("$tgz/$part"))[7] || die "can't stat $tgz/$part: $!";
388 }
389 closedir $dir;
390 }
391
392 return $size;
393 }
394
395 sub getGzipSize($$)
396 {
397 my ($hostID, $backupNum) = @_;
398 my $sql;
399 my $dbh = get_dbh();
400
401 $sql = q{
402 SELECT hosts.name as host,
403 shares.name as share,
404 backups.num as backupnum
405 FROM hosts, backups, shares
406 WHERE shares.id=backups.shareid AND
407 hosts.id =backups.hostid AND
408 hosts.id=? AND
409 backups.num=?
410 };
411 my $sth = $dbh->prepare($sql);
412 $sth->execute($hostID, $backupNum);
413
414 my $row = $sth->fetchrow_hashref();
415
416 return get_tgz_size_by_name(
417 getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'})
418 );
419 }
420
421 sub getBackupsNotBurned($) {
422
423 my $param = shift;
424 my $dbh = get_dbh();
425
426 my $order = getSort('burn', 'sql', $param->{'sort'});
427
428 print STDERR "## sort=". ($param->{'sort'} || 'no sort param') . " burn sql order: $order\n";
429
430 my $sql = qq{
431 SELECT
432 backups.hostID AS hostID,
433 hosts.name AS host,
434 shares.name AS share,
435 backups.num AS backupnum,
436 backups.type AS type,
437 backups.date AS date,
438 date_part('epoch',now()) - backups.date as age,
439 backups.size AS size,
440 backups.id AS id,
441 backups.inc_size AS inc_size,
442 backups.parts AS parts
443 FROM backups
444 INNER JOIN shares ON backups.shareID=shares.ID
445 INNER JOIN hosts ON backups.hostID = hosts.ID
446 LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id
447 WHERE backups.inc_size > 0 AND backups.inc_deleted is false AND archive_backup.backup_id IS NULL
448 GROUP BY
449 backups.hostID,
450 hosts.name,
451 shares.name,
452 backups.num,
453 backups.shareid,
454 backups.id,
455 backups.type,
456 backups.date,
457 backups.size,
458 backups.inc_size,
459 backups.parts
460 ORDER BY $order
461 };
462 my $sth = $dbh->prepare( $sql );
463 my @ret;
464 $sth->execute();
465
466 while ( my $row = $sth->fetchrow_hashref() ) {
467 $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) );
468 #$row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
469 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
470
471 # do some cluster calculation (approximate) and convert to kB
472 $row->{'inc_size'} = int(($row->{'inc_size'} + 1023 ) / ( 2 * 1024 ) * 2);
473 push @ret, $row;
474 }
475
476 return @ret;
477 }
478
479 sub displayBackupsGrid($) {
480
481 my $param = shift;
482
483 my $retHTML .= q{
484 <form id="forma" method="POST" action="}.$MyURL.q{?action=burn">
485 };
486
487 $retHTML .= <<'EOF3';
488 <style type="text/css">
489 <!--
490 DIV#fixedBox {
491 position: absolute;
492 top: 50em;
493 left: -24%;
494 padding: 0.5em;
495 width: 20%;
496 background-color: #E0F0E0;
497 border: 1px solid #00C000;
498 }
499
500 DIV#fixedBox, DIV#fixedBox INPUT, DIV#fixedBox TEXTAREA {
501 font-size: 10pt;
502 }
503
504 FORM>DIV#fixedBox {
505 position: fixed !important;
506 left: 0.5em !important;
507 top: auto !important;
508 bottom: 1em !important;
509 width: 15% !important;
510 }
511
512 DIV#fixedBox INPUT[type=text], DIV#fixedBox TEXTAREA {
513 border: 1px solid #00C000;
514 }
515
516 DIV#fixedBox #note {
517 display: block;
518 width: 100%;
519 }
520
521 DIV#fixedBox #submitBurner {
522 display: block;
523 width: 100%;
524 margin-top: 0.5em;
525 cursor: pointer;
526 }
527
528 * HTML {
529 overflow-y: hidden;
530 }
531
532 * HTML BODY {
533 overflow-y: auto;
534 height: 100%;
535 font-size: 100%;
536 }
537
538 * HTML DIV#fixedBox {
539 position: absolute;
540 }
541
542 #mContainer, #gradient, #mask, #progressIndicator {
543 display: block;
544 width: 100%;
545 font-size: 10pt;
546 font-weight: bold;
547 text-align: center;
548 vertical-align: middle;
549 padding: 1px;
550 }
551
552 #gradient, #mask, #progressIndicator {
553 left: 0;
554 border-width: 1px;
555 border-style: solid;
556 border-color: #000000;
557 color: #404040;
558 margin: 0.4em;
559 position: absolute;
560 margin-left: -1px;
561 margin-top: -1px;
562 margin-bottom: -1px;
563 overflow: hidden;
564 }
565
566 #mContainer {
567 display: block;
568 position: relative;
569 padding: 0px;
570 margin-top: 0.4em;
571 margin-bottom: 0.5em;
572 }
573
574 #gradient {
575 z-index: 1;
576 background-color: #FFFF00;
577 }
578
579 #mask {
580 z-index: 2;
581 background-color: #FFFFFF;
582 }
583
584 #progressIndicator {
585 z-index: 3;
586 background-color: transparent;
587 }
588
589 #parts {
590 padding: 0.4em;
591 display: none;
592 width: 100%;
593 font-size: 80%;
594 color: #ff0000;
595 text-align: center;
596 }
597 -->
598 </style>
599 <script type="text/javascript">
600 <!--
601
602 var debug_div = null;
603 EOF3
604
605 # take maximum archive size from configuration
606 $retHTML .= 'var media_size = '. $Conf{MaxArchiveSize} .';';
607
608 $retHTML .= <<'EOF3';
609
610 function debug(msg) {
611 return; // Disable debugging
612
613 if (! debug_div) debug_div = document.getElementById('debug');
614
615 // this will create debug div if it doesn't exist.
616 if (! debug_div) {
617 debug_div = document.createElement('div');
618 if (document.body) document.body.appendChild(debug_div);
619 else debug_div = null;
620 }
621 if (debug_div) {
622 debug_div.appendChild(document.createTextNode(msg));
623 debug_div.appendChild(document.createElement("br"));
624 }
625 }
626
627
628 var element_id_cache = Array();
629
630 function element_id(name,element) {
631 if (! element_id_cache[name]) {
632 element_id_cache[name] = self.document.getElementById(name);
633 }
634 return element_id_cache[name];
635 }
636
637 function checkAll(location) {
638 var f = element_id('forma') || null;
639 if (!f) return false;
640
641 var len = f.elements.length;
642 var check_all = element_id('allFiles');
643 var suma = check_all.checked ? (parseInt(f.elements['totalsize'].value) || 0) : 0;
644
645 for (var i = 0; i < len; i++) {
646 var e = f.elements[i];
647 if (e.name != 'all' && e.name.substr(0, 3) == 'fcb') {
648 if (check_all.checked) {
649 if (e.checked) continue;
650 var el = element_id("fss" + e.name.substr(3));
651 var size = parseInt(el.value) || 0;
652 debug('suma: '+suma+' size: '+size);
653 if ((suma + size) < media_size) {
654 suma += size;
655 e.checked = true;
656 } else {
657 break;
658 }
659 } else {
660 e.checked = false;
661 }
662 }
663 }
664 update_sum(suma);
665 }
666
667 function update_sum(suma, suma_disp) {
668 if (! suma_disp) suma_disp = suma;
669 element_id('forma').elements['totalsize'].value = suma_disp;
670 pbar_set(suma, media_size);
671 debug('total size: ' + suma);
672 }
673
674 function sumiraj(e) {
675 var suma = parseInt(element_id('forma').elements['totalsize'].value) || 0;
676 var len = element_id('forma').elements.length;
677 if (e) {
678 var size = parseInt( element_id("fss" + e.name.substr(3)).value);
679 if (e.checked) {
680 suma += size;
681 } else {
682 suma -= size;
683 }
684
685 var parts = parseInt( element_id("prt" + e.name.substr(3)).value);
686 if (suma > media_size && suma == size && parts > 1) {
687 element_id("parts").innerHTML = "This will take "+parts+" mediums!";
688 element_id("parts").style.display = 'block';
689 update_sum(media_size, suma);
690 suma = media_size;
691 return suma;
692 } else {
693 element_id("parts").style.display = 'none';
694 }
695
696 if (suma < 0) suma = 0;
697 } else {
698 suma = 0;
699 for (var i = 0; i < len; i++) {
700 var e = element_id('forma').elements[i];
701 if (e.name != 'all' && e.checked && e.name.substr(0,3) == 'fcb') {
702 var el = element_id("fss" + e.name.substr(3));
703 if (el && el.value) suma += parseInt(el.value) || 0;
704 }
705 }
706 }
707 update_sum(suma);
708 return suma;
709 }
710
711 /* progress bar */
712
713 var _pbar_width = null;
714 var _pbar_warn = 10; // change color in last 10%
715
716 function pbar_reset() {
717 element_id("mask").style.left = "0px";
718 _pbar_width = element_id("mContainer").offsetWidth - 2;
719 element_id("mask").style.width = _pbar_width + "px";
720 element_id("mask").style.display = "block";
721 element_id("progressIndicator").style.zIndex = 10;
722 element_id("progressIndicator").innerHTML = "0";
723 }
724
725 function dec2hex(d) {
726 var hch = '0123456789ABCDEF';
727 var a = d % 16;
728 var q = (d - a) / 16;
729 return hch.charAt(q) + hch.charAt(a);
730 }
731
732 function pbar_set(amount, max) {
733 debug('pbar_set('+amount+', '+max+')');
734
735 if (_pbar_width == null) {
736 var _mc = element_id("mContainer");
737 if (_pbar_width == null) _pbar_width = parseInt(_mc.offsetWidth ? (_mc.offsetWidth - 2) : 0) || null;
738 if (_pbar_width == null) _pbar_width = parseInt(_mc.clientWidth ? (_mc.clientWidth + 2) : 0) || null;
739 if (_pbar_width == null) _pbar_width = 0;
740 }
741
742 var pcnt = Math.floor(amount * 100 / max);
743 var p90 = 100 - _pbar_warn;
744 var pcol = pcnt - p90;
745 if (Math.round(pcnt) <= 100) {
746 if (pcol < 0) pcol = 0;
747 var e = element_id("submitBurner");
748 debug('enable_button');
749 e.disabled = false;
750 var a = e.getAttributeNode('disabled') || null;
751 if (a) e.removeAttributeNode(a);
752 } else {
753 debug('disable button');
754 pcol = _pbar_warn;
755 var e = element_id("submitBurner");
756 if (!e.disabled) e.disabled = true;
757 }
758 var col_g = Math.floor((_pbar_warn - pcol) * 255 / _pbar_warn);
759 var col = '#FF' + dec2hex(col_g) + '00';
760
761 //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
762 element_id("gradient").style.backgroundColor = col;
763
764 element_id("progressIndicator").innerHTML = pcnt + '%';
765 //element_id("progressIndicator").innerHTML = amount;
766
767 element_id("mask").style.clip = 'rect(' + Array(
768 '0px',
769 element_id("mask").offsetWidth + 'px',
770 element_id("mask").offsetHeight + 'px',
771 Math.round(_pbar_width * amount / max) + 'px'
772 ).join(' ') + ')';
773 }
774
775 if (!self.body) self.body = new Object();
776 self.onload = self.document.onload = self.body.onload = function() {
777 //pbar_reset();
778 sumiraj();
779 };
780
781 // -->
782 </script>
783 <div id="fixedBox">
784
785 Size: <input type="text" name="totalsize" size="7" readonly="readonly" style="text-align:right;" value="0" /> kB
786
787 <div id="mContainer">
788 <div id="gradient">&nbsp;</div>
789 <div id="mask">&nbsp;</div>
790 <div id="progressIndicator">0%</div>
791 </div>
792 <br/>
793
794 <div id="parts">&nbsp;</div>
795
796 Note:
797 <textarea name="note" cols="10" rows="5" id="note"></textarea>
798
799 <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner" />
800
801 </div>
802 <!--
803 <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
804 no debug output yet
805 </div>
806 -->
807 EOF3
808 $retHTML .= q{
809 <input type="hidden" value="burn" name="action">
810 <input type="hidden" value="results" name="search_results">
811 <table style="fview" border="0" cellspacing="0" cellpadding="2">
812 <tr class="tableheader">
813 <td class="tableheader">
814 <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
815 </td>
816 } .
817 sort_header($param, 'Share', 'share', 'center') .
818 sort_header($param, '#', 'num', 'center') .
819 qq{
820 <td align="center">Type</td>
821 } .
822 sort_header($param, 'Date', 'date', 'center') .
823 sort_header($param, 'Age/days', 'age', 'center') .
824 sort_header($param, 'Size/Mb', 'size', 'center') .
825 sort_header($param, 'gzip size/Kb', 'incsize', 'center') .
826 qq{
827 </tr>
828 };
829
830 my @color = (' bgcolor="#e0e0e0"', '');
831
832 my $i = 0;
833 my $host = '';
834
835 foreach my $backup ( getBackupsNotBurned($param) ) {
836
837 if ($host ne $backup->{'host'}) {
838 $i++;
839 $host = $backup->{'host'};
840 }
841 my $ftype = "";
842
843 my $checkbox_key = $backup->{'hostid'}. '_' .$backup->{'backupnum'} . '_' . $backup->{'id'};
844
845 $retHTML .=
846 '<tr' . $color[$i %2 ] . '>
847 <td class="fview">';
848
849 if (($backup->{'inc_size'} || 0) > 0) {
850 $retHTML .= '
851 <input type="checkbox" name="fcb' . $checkbox_key . '" value="' . $checkbox_key . '" onClick="sumiraj(this);">';
852 }
853
854 $retHTML .=
855 '</td>' .
856 '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
857 '<td align="center">' . $backup->{'backupnum'} . '</td>' .
858 '<td align="center">' . $backup->{'type'} . '</td>' .
859 '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
860 '<td align="center">' . $backup->{'age'} . '</td>' .
861 '<td align="right">' . $backup->{'size'} . '</td>' .
862 '<td align="right">' . $backup->{'inc_size'} .
863 '<input type="hidden" id="fss'.$checkbox_key .'" value="'. $backup->{'inc_size'} .'"></td>' .
864 '<input type="hidden" id="prt'.$checkbox_key .'" value="'. $backup->{'parts'} .'"></td>' .
865
866 "</tr>\n";
867 }
868
869 $retHTML .= "</table>";
870 $retHTML .= "</form>";
871
872 return $retHTML;
873 }
874
875 sub displayGrid($) {
876 my ($param) = @_;
877
878 my $offset = $param->{'offset'};
879 my $hilite = $param->{'search_filename'};
880
881 my $retHTML = "";
882
883 my $start_t = time();
884
885 my ($results, $files);
886 if ($param->{'use_hest'} && length($hilite) > 0) {
887 ($results, $files) = getFilesHyperEstraier($param);
888 } else {
889 ($results, $files) = getFiles($param);
890 }
891
892 my $dur_t = time() - $start_t;
893 my $dur = sprintf("%0.4fs", $dur_t);
894
895 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
896
897 if ($results <= 0) {
898 $retHTML .= qq{
899 <p style="color: red;">No results found...</p>
900 };
901 return $retHTML;
902 } else {
903 # DEBUG
904 #use Data::Dumper;
905 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
906 }
907
908
909 $retHTML .= qq{
910 <div>
911 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
912 </div>
913 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
914 <tr class="fviewheader">
915 <td></td>
916 };
917
918 sub sort_header($$$$) {
919 my ($param, $display, $name, $align) = @_;
920
921 my ($sort_what, $sort_direction) = split(/_/,$param->{'sort'},2);
922
923 my $old_sort = $param->{'sort'};
924
925 my $html = qq{<td align="$align"};
926 my $arrow = '';
927
928 if (lc($sort_what) eq lc($name)) {
929 my $direction = lc($sort_direction);
930
931 # swap direction or fallback to default
932 $direction =~ tr/ad/da/;
933 $direction = 'a' unless ($direction =~ /[ad]/);
934
935 $param->{'sort'} = $name . '_' . $direction;
936 $html .= ' style="border: 1px solid #808080;"';
937
938 # add unicode arrow for direction
939 $arrow .= '&nbsp;';
940 $arrow .= $direction eq 'a' ? '&#9650;'
941 : $direction eq 'd' ? '&#9660;'
942 : ''
943 ;
944
945 } else {
946 $param->{'sort'} = $name . '_a';
947 }
948
949 $html .= '><a href="' . page_uri($param) . '">' . $display . '</a>' . $arrow . '</td>';
950 $param->{'sort'} = $old_sort;
951
952 return $html;
953 }
954
955 $retHTML .=
956 sort_header($param, 'Share', 'share', 'center') .
957 sort_header($param, 'Type and Name', 'path', 'center') .
958 sort_header($param, '#', 'num', 'center') .
959 sort_header($param, 'Size', 'size', 'center') .
960 sort_header($param, 'Date', 'date', 'center');
961
962 $retHTML .= qq{
963 <td align="center">Media</td>
964 </tr>
965 };
966
967 my $file;
968
969 sub hilite_html($$) {
970 my ($html, $search) = @_;
971 $html =~ s#($search)#<b>$1</b>#gis;
972 return $html;
973 }
974
975 sub restore_link($$$$$$) {
976 my $type = shift;
977 my $action = 'RestoreFile';
978 $action = 'browse' if (lc($type) eq 'dir');
979 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
980 }
981
982 my $sth_archived;
983 my %archived_cache;
984
985 sub check_archived($$$) {
986 my ($host, $share, $num) = @_;
987
988 if (my $html = $archived_cache{"$host $share $num"}) {
989 return $html;
990 }
991
992 $sth_archived ||= $dbh->prepare(qq{
993 select
994 dvd_nr, note,
995 count(archive_burned.copy) as copies
996 from archive
997 inner join archive_burned on archive_burned.archive_id = archive.id
998 inner join archive_backup on archive.id = archive_backup.archive_id
999 inner join backups on backups.id = archive_backup.backup_id
1000 inner join hosts on hosts.id = backups.hostid
1001 inner join shares on shares.id = backups.shareid
1002 where hosts.name = ? and shares.name = ? and backups.num = ?
1003 group by dvd_nr, note
1004 });
1005
1006 my @mediums;
1007
1008 $sth_archived->execute($host, $share, $num);
1009 while (my $row = $sth_archived->fetchrow_hashref()) {
1010 push @mediums, '<abbr title="' .
1011 $row->{'note'} .
1012 ' [' . $row->{'copies'} . ']' .
1013 '">' .$row->{'dvd_nr'} .
1014 '</abbr>';
1015 }
1016
1017 my $html = join(", ",@mediums);
1018 $archived_cache{"$host $share $num"} = $html;
1019 return $html;
1020 }
1021
1022 my $i = $offset * $on_page;
1023
1024 foreach $file (@{ $files }) {
1025 $i++;
1026
1027 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
1028 $retHTML .= qq{<tr class="fviewborder">};
1029
1030 $retHTML .= qq{<td class="fviewborder">$i</td>};
1031
1032 $retHTML .=
1033 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
1034 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
1035 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
1036 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
1037 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
1038 qq{<td class="fviewborder">} . check_archived( $file->{'hname'}, $file->{'sname'}, $file->{'backupnum'} ) . qq{</td>};
1039
1040 $retHTML .= "</tr>";
1041 }
1042 $retHTML .= "</table>";
1043
1044 # all variables which has to be transfered
1045 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/) {
1046 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
1047 }
1048
1049 my $del = '';
1050 my $max_page = int( $results / $on_page );
1051 my $page = 0;
1052
1053 sub page_uri($) {
1054 my $param = shift || die "no param?";
1055
1056 my $uri = $MyURL;
1057 my $del = '?';
1058 foreach my $k (keys %{ $param }) {
1059 if ($param->{$k}) {
1060 $uri .= $del . $k . '=' . ${EscURI( $param->{$k} )};
1061 $del = '&';
1062 }
1063 }
1064 return $uri;
1065 }
1066
1067 sub page_link($$$) {
1068 my ($param,$page,$display) = @_;
1069
1070 $param->{'offset'} = $page if (defined($page));
1071
1072 my $html = '<a href = "' . page_uri($param) . '">' . $display . '</a>';
1073 }
1074
1075 $retHTML .= '<div style="text-align: center;">';
1076
1077 if ($offset > 0) {
1078 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
1079 }
1080
1081 while ($page <= $max_page) {
1082 if ($page == $offset) {
1083 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
1084 } else {
1085 $retHTML .= $del . page_link($param, $page, $page + 1);
1086 }
1087
1088 if ($page < $offset - $pager_pages && $page != 0) {
1089 $retHTML .= " ... ";
1090 $page = $offset - $pager_pages;
1091 $del = '';
1092 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
1093 $retHTML .= " ... ";
1094 $page = $max_page;
1095 $del = '';
1096 } else {
1097 $del = ' | ';
1098 $page++;
1099 }
1100 }
1101
1102 if ($offset < $max_page) {
1103 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
1104 }
1105
1106 $retHTML .= "</div>";
1107
1108 return $retHTML;
1109 }
1110
1111 1;

  ViewVC Help
Powered by ViewVC 1.1.26