/[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 353 - (show annotations)
Wed Apr 26 11:10:54 2006 UTC (18 years, 1 month ago) by dpavlin
File size: 28672 byte(s)
 r590@athlon:  dpavlin | 2006-04-26 13:10:07 +0200
 added drop-down to select search results depending of their's status (all,
 burned on archival media, not burned [pending])

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

  ViewVC Help
Powered by ViewVC 1.1.26