/[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 262 - (show annotations)
Tue Dec 13 00:10:44 2005 UTC (18 years, 5 months ago) by dpavlin
File size: 28533 byte(s)
 r11655@llin:  dpavlin | 2005-12-13 00:23:11 +0100
 various improvements and fixes. Might even work now.

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 . '/' . $use_hest;
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}.tar.gz") {
381 $size = (stat("${tgz}.tar.gz"))[7];
382 } elsif (-d $tgz) {
383 opendir(my $dir, $tgz) || die "can't opendir $tgz: $!";
384 my @parts = grep { !/^\./ && !/md5/ && -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 } else {
391 return -1;
392 }
393
394 return $size;
395 }
396
397 sub getGzipSize($$)
398 {
399 my ($hostID, $backupNum) = @_;
400 my $sql;
401 my $dbh = get_dbh();
402
403 $sql = q{
404 SELECT hosts.name as host,
405 shares.name as share,
406 backups.num as backupnum
407 FROM hosts, backups, shares
408 WHERE shares.id=backups.shareid AND
409 hosts.id =backups.hostid AND
410 hosts.id=? AND
411 backups.num=?
412 };
413 my $sth = $dbh->prepare($sql);
414 $sth->execute($hostID, $backupNum);
415
416 my $row = $sth->fetchrow_hashref();
417
418 return get_tgz_size_by_name(
419 getGzipName($row->{'host'}, $row->{share}, $row->{'backupnum'})
420 );
421 }
422
423 sub getVolumes($) {
424 my $id = shift;
425
426 my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
427
428 my $sth = $dbh->prepare(qq{
429 select
430 size
431 from backup_parts
432 where backup_id = ?
433 order by part_nr asc
434 });
435
436 $sth->execute($id);
437
438 my $cumulative_size = 0;
439 my $volumes = 1;
440
441 while(my ($size) = $sth->fetchrow_array) {
442 if ($cumulative_size + $size > $max_archive_size) {
443 $volumes++;
444 $cumulative_size = $size;
445 } else {
446 $cumulative_size += $size;
447 }
448 }
449
450 return ($volumes,$cumulative_size);
451 }
452
453 sub getBackupsNotBurned($) {
454
455 my $param = shift;
456 my $dbh = get_dbh();
457
458 my $order = getSort('burn', 'sql', $param->{'sort'});
459
460 print STDERR "## sort=". ($param->{'sort'} || 'no sort param') . " burn sql order: $order\n";
461
462 my $sql = qq{
463 SELECT
464 backups.hostID AS hostID,
465 hosts.name AS host,
466 shares.name AS share,
467 backups.num AS backupnum,
468 backups.type AS type,
469 backups.date AS date,
470 date_part('epoch',now()) - backups.date as age,
471 backups.size AS size,
472 backups.id AS id,
473 backups.inc_size AS inc_size,
474 backups.parts AS parts
475 FROM backups
476 INNER JOIN shares ON backups.shareID=shares.ID
477 INNER JOIN hosts ON backups.hostID = hosts.ID
478 LEFT OUTER JOIN archive_backup ON archive_backup.backup_id = backups.id
479 WHERE backups.inc_size > 0 AND backups.inc_deleted is false AND archive_backup.backup_id IS NULL
480 GROUP BY
481 backups.hostID,
482 hosts.name,
483 shares.name,
484 backups.num,
485 backups.shareid,
486 backups.id,
487 backups.type,
488 backups.date,
489 backups.size,
490 backups.inc_size,
491 backups.parts
492 ORDER BY $order
493 };
494 my $sth = $dbh->prepare( $sql );
495 my @ret;
496 $sth->execute();
497
498 while ( my $row = $sth->fetchrow_hashref() ) {
499 $row->{'age'} = sprintf("%0.1f", ( $row->{'age'} / 86400 ) );
500 #$row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
501
502 my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
503 if ($row->{size} > $max_archive_size) {
504 ($row->{volumes}, $row->{inc_size_calc}) = getVolumes($row->{id});
505 }
506
507 $row->{size} = sprintf("%0.2f", $row->{size} / 1024 / 1024);
508
509 # do some cluster calculation (approximate)
510 $row->{inc_size} = int(( ($row->{inc_size} + 1023 ) / 2 ) * 2);
511 $row->{inc_size_calc} ||= $row->{inc_size};
512 push @ret, $row;
513 }
514
515 return @ret;
516 }
517
518 sub displayBackupsGrid($) {
519
520 my $param = shift;
521
522 my $max_archive_size = $Conf{MaxArchiveSize} || die "no MaxArchiveSize";
523 my $max_archive_file_size = $Conf{MaxArchiveFileSize} || die "no MaxFileInSize";
524
525 my $retHTML .= q{
526 <form id="forma" method="POST" action="}.$MyURL.q{?action=burn">
527 };
528
529 $retHTML .= <<'EOF3';
530 <style type="text/css">
531 <!--
532 DIV#fixedBox {
533 position: absolute;
534 top: 50em;
535 left: -24%;
536 padding: 0.5em;
537 width: 20%;
538 background-color: #E0F0E0;
539 border: 1px solid #00C000;
540 }
541
542 DIV#fixedBox, DIV#fixedBox INPUT, DIV#fixedBox TEXTAREA {
543 font-size: 10pt;
544 }
545
546 FORM>DIV#fixedBox {
547 position: fixed !important;
548 left: 0.5em !important;
549 top: auto !important;
550 bottom: 1em !important;
551 width: 15% !important;
552 }
553
554 DIV#fixedBox INPUT[type=text], DIV#fixedBox TEXTAREA {
555 border: 1px solid #00C000;
556 }
557
558 DIV#fixedBox #note {
559 display: block;
560 width: 100%;
561 }
562
563 DIV#fixedBox #submitBurner {
564 display: block;
565 width: 100%;
566 margin-top: 0.5em;
567 cursor: pointer;
568 }
569
570 * HTML {
571 overflow-y: hidden;
572 }
573
574 * HTML BODY {
575 overflow-y: auto;
576 height: 100%;
577 font-size: 100%;
578 }
579
580 * HTML DIV#fixedBox {
581 position: absolute;
582 }
583
584 #mContainer, #gradient, #mask, #progressIndicator {
585 display: block;
586 width: 100%;
587 font-size: 10pt;
588 font-weight: bold;
589 text-align: center;
590 vertical-align: middle;
591 padding: 1px;
592 }
593
594 #gradient, #mask, #progressIndicator {
595 left: 0;
596 border-width: 1px;
597 border-style: solid;
598 border-color: #000000;
599 color: #404040;
600 margin: 0.4em;
601 position: absolute;
602 margin-left: -1px;
603 margin-top: -1px;
604 margin-bottom: -1px;
605 overflow: hidden;
606 }
607
608 #mContainer {
609 display: block;
610 position: relative;
611 padding: 0px;
612 margin-top: 0.4em;
613 margin-bottom: 0.5em;
614 }
615
616 #gradient {
617 z-index: 1;
618 background-color: #FFFF00;
619 }
620
621 #mask {
622 z-index: 2;
623 background-color: #FFFFFF;
624 }
625
626 #progressIndicator {
627 z-index: 3;
628 background-color: transparent;
629 }
630
631 #volumes {
632 padding: 0.4em;
633 display: none;
634 width: 100%;
635 font-size: 80%;
636 color: #ff0000;
637 text-align: center;
638 }
639 -->
640 </style>
641 <script type="text/javascript">
642 <!--
643
644 var debug_div = null;
645 EOF3
646
647 # take maximum archive size from configuration
648 $retHTML .= qq{
649 var media_size = $max_archive_size ;
650 var max_file_size = $max_archive_file_size;
651
652 };
653
654 $retHTML .= <<'EOF3';
655
656 function debug(msg) {
657 // return; // Disable debugging
658
659 if (! debug_div) debug_div = document.getElementById('debug');
660
661 // this will create debug div if it doesn't exist.
662 if (! debug_div) {
663 debug_div = document.createElement('div');
664 if (document.body) document.body.appendChild(debug_div);
665 else debug_div = null;
666 }
667 if (debug_div) {
668 debug_div.appendChild(document.createTextNode(msg));
669 debug_div.appendChild(document.createElement("br"));
670 }
671 }
672
673
674 var element_id_cache = Array();
675
676 function element_id(name,element) {
677 if (! element_id_cache[name]) {
678 element_id_cache[name] = self.document.getElementById(name);
679 }
680 return element_id_cache[name];
681 }
682
683 function checkAll(location) {
684 var f = element_id('forma') || null;
685 if (!f) return false;
686
687 var len = f.elements.length;
688 var check_all = element_id('allFiles');
689 var suma = check_all.checked ? (parseInt(f.elements['totalsize'].value) || 0) : 0;
690
691 for (var i = 0; i < len; i++) {
692 var e = f.elements[i];
693 if (e.name != 'all' && e.name.substr(0, 3) == 'fcb') {
694 if (check_all.checked) {
695 if (e.checked) continue;
696 var el = element_id("fss" + e.name.substr(3));
697 var size = parseInt(el.value) || 0;
698 debug('suma: '+suma+' size: '+size);
699 if ((suma + size) < media_size) {
700 suma += size;
701 e.checked = true;
702 } else {
703 break;
704 }
705 } else {
706 e.checked = false;
707 }
708 }
709 }
710 update_sum(suma);
711 }
712
713 function update_sum(suma, suma_disp) {
714 if (! suma_disp) suma_disp = suma;
715 suma_disp = Math.floor(suma_disp / 1024);
716 element_id('forma').elements['totalsize_kb'].value = suma_disp;
717 element_id('forma').elements['totalsize'].value = suma;
718 pbar_set(suma, media_size);
719 debug('total size: ' + suma);
720 }
721
722 function update_size(name, checked, suma) {
723 var size = parseInt( element_id("fss" + name).value);
724
725 if (checked) {
726 suma += size;
727 } else {
728 suma -= size;
729 }
730
731 var volumes = parseInt( element_id("prt" + name).value);
732 debug('update_size('+name+','+checked+') suma: '+suma+' volumes: '+volumes);
733 if (volumes > 1) {
734 if (checked) {
735 element_id("volumes").innerHTML = "This will take "+volumes+" mediums!";
736 element_id("volumes").style.display = 'block';
737 suma = size;
738 update_sum(suma);
739 } else {
740 suma -= size;
741 element_id("volumes").style.display = 'none';
742 }
743 }
744
745 return suma;
746 }
747
748 function sumiraj(e) {
749 var suma = parseInt(element_id('forma').elements['totalsize'].value) || 0;
750 var len = element_id('forma').elements.length;
751 if (e) {
752 suma = update_size(e.name.substr(3), e.checked, suma);
753 if (suma < 0) suma = 0;
754 } else {
755 suma = 0;
756 for (var i = 0; i < len; i++) {
757 var fel = element_id('forma').elements[i];
758 if (fel.name != 'all' && fel.checked && fel.name.substr(0,3) == 'fcb') {
759 suma = update_size(fel.name.substr(3), fel.checked, suma);
760 }
761 }
762 }
763 update_sum(suma);
764 return suma;
765 }
766
767 /* progress bar */
768
769 var _pbar_width = null;
770 var _pbar_warn = 10; // change color in last 10%
771
772 function pbar_reset() {
773 element_id("mask").style.left = "0px";
774 _pbar_width = element_id("mContainer").offsetWidth - 2;
775 element_id("mask").style.width = _pbar_width + "px";
776 element_id("mask").style.display = "block";
777 element_id("progressIndicator").style.zIndex = 10;
778 element_id("progressIndicator").innerHTML = "0";
779 }
780
781 function dec2hex(d) {
782 var hch = '0123456789ABCDEF';
783 var a = d % 16;
784 var q = (d - a) / 16;
785 return hch.charAt(q) + hch.charAt(a);
786 }
787
788 function pbar_set(amount, max) {
789 debug('pbar_set('+amount+', '+max+')');
790
791 if (_pbar_width == null) {
792 var _mc = element_id("mContainer");
793 if (_pbar_width == null) _pbar_width = parseInt(_mc.offsetWidth ? (_mc.offsetWidth - 2) : 0) || null;
794 if (_pbar_width == null) _pbar_width = parseInt(_mc.clientWidth ? (_mc.clientWidth + 2) : 0) || null;
795 if (_pbar_width == null) _pbar_width = 0;
796 }
797
798 var pcnt = Math.floor(amount * 100 / max);
799 var p90 = 100 - _pbar_warn;
800 var pcol = pcnt - p90;
801 if (Math.round(pcnt) <= 100) {
802 if (pcol < 0) pcol = 0;
803 var e = element_id("submitBurner");
804 debug('enable_button');
805 e.disabled = false;
806 var a = e.getAttributeNode('disabled') || null;
807 if (a) e.removeAttributeNode(a);
808 } else {
809 debug('disable button');
810 pcol = _pbar_warn;
811 var e = element_id("submitBurner");
812 if (!e.disabled) e.disabled = true;
813 }
814 var col_g = Math.floor((_pbar_warn - pcol) * 255 / _pbar_warn);
815 var col = '#FF' + dec2hex(col_g) + '00';
816
817 //debug('pcol: '+pcol+' g:'+col_g+' _pbar_warn:'+ _pbar_warn + ' color: '+col);
818 element_id("gradient").style.backgroundColor = col;
819
820 element_id("progressIndicator").innerHTML = pcnt + '%';
821 //element_id("progressIndicator").innerHTML = amount;
822
823 element_id("mask").style.clip = 'rect(' + Array(
824 '0px',
825 element_id("mask").offsetWidth + 'px',
826 element_id("mask").offsetHeight + 'px',
827 Math.round(_pbar_width * amount / max) + 'px'
828 ).join(' ') + ')';
829 }
830
831 if (!self.body) self.body = new Object();
832 self.onload = self.document.onload = self.body.onload = function() {
833 //pbar_reset();
834 sumiraj();
835 };
836
837 // -->
838 </script>
839 <div id="fixedBox">
840
841 <input type="hidden" name="totalsize"/>
842 Size: <input type="text" name="totalsize_kb" size="7" readonly="readonly" style="text-align:right;" value="0" /> kB
843
844 <div id="mContainer">
845 <div id="gradient">&nbsp;</div>
846 <div id="mask">&nbsp;</div>
847 <div id="progressIndicator">0%</div>
848 </div>
849 <br/>
850
851 <div id="volumes">&nbsp;</div>
852
853 Note:
854 <textarea name="note" cols="10" rows="5" id="note"></textarea>
855
856 <input type="submit" id="submitBurner" value="Burn selected" name="submitBurner" />
857
858 </div>
859 <div id="debug" style="float: right; width: 10em; border: 1px #ff0000 solid; background-color: #ffe0e0; -moz-opacity: 0.7;">
860 no debug output yet
861 </div>
862 EOF3
863 $retHTML .= q{
864 <input type="hidden" value="burn" name="action">
865 <input type="hidden" value="results" name="search_results">
866 <table style="fview" border="0" cellspacing="0" cellpadding="2">
867 <tr class="tableheader">
868 <td class="tableheader">
869 <input type="checkbox" name="allFiles" id="allFiles" onClick="checkAll('allFiles');">
870 </td>
871 } .
872 sort_header($param, 'Share', 'share', 'center') .
873 sort_header($param, '#', 'num', 'center') .
874 qq{
875 <td align="center">Type</td>
876 } .
877 sort_header($param, 'Date', 'date', 'center') .
878 sort_header($param, 'Age/days', 'age', 'center') .
879 sort_header($param, 'Size/Mb', 'size', 'center') .
880 sort_header($param, 'gzip size/Kb', 'incsize', 'center') .
881 qq{
882 <td align="center">medias</td></tr>
883 };
884
885 my @color = (' bgcolor="#e0e0e0"', '');
886
887 my $i = 0;
888 my $host = '';
889
890 foreach my $backup ( getBackupsNotBurned($param) ) {
891
892 if ($host ne $backup->{'host'}) {
893 $i++;
894 $host = $backup->{'host'};
895 }
896 my $ftype = "";
897
898 my $checkbox_key = $backup->{'hostid'}. '_' .$backup->{'backupnum'} . '_' . $backup->{'id'};
899
900 $retHTML .=
901 '<tr' . $color[$i %2 ] . '>
902 <td class="fview">';
903
904 if (($backup->{'inc_size'} || 0) > 0) {
905 $retHTML .= '
906 <input type="checkbox" name="fcb' . $checkbox_key . '" value="' . $checkbox_key . '" onClick="sumiraj(this);">';
907 }
908
909 my $img_url = $Conf{CgiImageDirURL};
910
911 $retHTML .=
912 '</td>' .
913 '<td align="right">' . $backup->{'host'} . ':' . $backup->{'share'} . '</td>' .
914 '<td align="center">' . $backup->{'backupnum'} . '</td>' .
915 '<td align="center">' . $backup->{'type'} . '</td>' .
916 '<td align="center">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
917 '<td align="center">' . $backup->{'age'} . '</td>' .
918 '<td align="right">' . $backup->{'size'} . '</td>' .
919 '<td align="right">' . sprintf("%0.1f", $backup->{'inc_size'} / 1024 ) .
920 '<input type="hidden" id="fss'.$checkbox_key .'" value="'. $backup->{'inc_size_calc'} .'"></td>' .
921 '<input type="hidden" id="prt'.$checkbox_key .'" value="'. $backup->{'volumes'} .'"></td>' .
922 '<td align="left">' . ( qq{<img src="$img_url/icon-cd.gif" alt="media">} x $backup->{volumes} ) . '</td>' .
923
924 "</tr>\n";
925 }
926
927 $retHTML .= "</table>";
928 $retHTML .= "</form>";
929
930 return $retHTML;
931 }
932
933 sub displayGrid($) {
934 my ($param) = @_;
935
936 my $offset = $param->{'offset'};
937 my $hilite = $param->{'search_filename'};
938
939 my $retHTML = "";
940
941 my $start_t = time();
942
943 my ($results, $files);
944 if ($param->{'use_hest'} && length($hilite) > 0) {
945 ($results, $files) = getFilesHyperEstraier($param);
946 } else {
947 ($results, $files) = getFiles($param);
948 }
949
950 my $dur_t = time() - $start_t;
951 my $dur = sprintf("%0.4fs", $dur_t);
952
953 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
954
955 if ($results <= 0) {
956 $retHTML .= qq{
957 <p style="color: red;">No results found...</p>
958 };
959 return $retHTML;
960 } else {
961 # DEBUG
962 #use Data::Dumper;
963 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
964 }
965
966
967 $retHTML .= qq{
968 <div>
969 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
970 </div>
971 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
972 <tr class="fviewheader">
973 <td></td>
974 };
975
976 sub sort_header($$$$) {
977 my ($param, $display, $name, $align) = @_;
978
979 my ($sort_what, $sort_direction) = split(/_/,$param->{'sort'},2);
980
981 my $old_sort = $param->{'sort'};
982
983 my $html = qq{<td align="$align"};
984 my $arrow = '';
985
986 if (lc($sort_what) eq lc($name)) {
987 my $direction = lc($sort_direction);
988
989 # swap direction or fallback to default
990 $direction =~ tr/ad/da/;
991 $direction = 'a' unless ($direction =~ /[ad]/);
992
993 $param->{'sort'} = $name . '_' . $direction;
994 $html .= ' style="border: 1px solid #808080;"';
995
996 # add unicode arrow for direction
997 $arrow .= '&nbsp;';
998 $arrow .= $direction eq 'a' ? '&#9650;'
999 : $direction eq 'd' ? '&#9660;'
1000 : ''
1001 ;
1002
1003 } else {
1004 $param->{'sort'} = $name . '_a';
1005 }
1006
1007 $html .= '><a href="' . page_uri($param) . '">' . $display . '</a>' . $arrow . '</td>';
1008 $param->{'sort'} = $old_sort;
1009
1010 return $html;
1011 }
1012
1013 $retHTML .=
1014 sort_header($param, 'Share', 'share', 'center') .
1015 sort_header($param, 'Type and Name', 'path', 'center') .
1016 sort_header($param, '#', 'num', 'center') .
1017 sort_header($param, 'Size', 'size', 'center') .
1018 sort_header($param, 'Date', 'date', 'center');
1019
1020 $retHTML .= qq{
1021 <td align="center">Media</td>
1022 </tr>
1023 };
1024
1025 my $file;
1026
1027 sub hilite_html($$) {
1028 my ($html, $search) = @_;
1029 $html =~ s#($search)#<b>$1</b>#gis;
1030 return $html;
1031 }
1032
1033 sub restore_link($$$$$$) {
1034 my $type = shift;
1035 my $action = 'RestoreFile';
1036 $action = 'browse' if (lc($type) eq 'dir');
1037 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
1038 }
1039
1040 my $sth_archived;
1041 my %archived_cache;
1042
1043 sub check_archived($$$) {
1044 my ($host, $share, $num) = @_;
1045
1046 if (my $html = $archived_cache{"$host $share $num"}) {
1047 return $html;
1048 }
1049
1050 $sth_archived ||= $dbh->prepare(qq{
1051 select
1052 dvd_nr, note,
1053 count(archive_burned.copy) as copies
1054 from archive
1055 inner join archive_burned on archive_burned.archive_id = archive.id
1056 inner join archive_backup on archive.id = archive_backup.archive_id
1057 inner join backups on backups.id = archive_backup.backup_id
1058 inner join hosts on hosts.id = backups.hostid
1059 inner join shares on shares.id = backups.shareid
1060 where hosts.name = ? and shares.name = ? and backups.num = ?
1061 group by dvd_nr, note
1062 });
1063
1064 my @mediums;
1065
1066 $sth_archived->execute($host, $share, $num);
1067 while (my $row = $sth_archived->fetchrow_hashref()) {
1068 push @mediums, '<abbr title="' .
1069 $row->{'note'} .
1070 ' [' . $row->{'copies'} . ']' .
1071 '">' .$row->{'dvd_nr'} .
1072 '</abbr>';
1073 }
1074
1075 my $html = join(", ",@mediums);
1076 $archived_cache{"$host $share $num"} = $html;
1077 return $html;
1078 }
1079
1080 my $i = $offset * $on_page;
1081
1082 foreach $file (@{ $files }) {
1083 $i++;
1084
1085 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
1086 $retHTML .= qq{<tr class="fviewborder">};
1087
1088 $retHTML .= qq{<td class="fviewborder">$i</td>};
1089
1090 $retHTML .=
1091 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
1092 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
1093 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
1094 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
1095 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
1096 qq{<td class="fviewborder">} . check_archived( $file->{'hname'}, $file->{'sname'}, $file->{'backupnum'} ) . qq{</td>};
1097
1098 $retHTML .= "</tr>";
1099 }
1100 $retHTML .= "</table>";
1101
1102 # all variables which has to be transfered
1103 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/) {
1104 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
1105 }
1106
1107 my $del = '';
1108 my $max_page = int( $results / $on_page );
1109 my $page = 0;
1110
1111 sub page_uri($) {
1112 my $param = shift || die "no param?";
1113
1114 my $uri = $MyURL;
1115 my $del = '?';
1116 foreach my $k (keys %{ $param }) {
1117 if ($param->{$k}) {
1118 $uri .= $del . $k . '=' . ${EscURI( $param->{$k} )};
1119 $del = '&';
1120 }
1121 }
1122 return $uri;
1123 }
1124
1125 sub page_link($$$) {
1126 my ($param,$page,$display) = @_;
1127
1128 $param->{'offset'} = $page if (defined($page));
1129
1130 my $html = '<a href = "' . page_uri($param) . '">' . $display . '</a>';
1131 }
1132
1133 $retHTML .= '<div style="text-align: center;">';
1134
1135 if ($offset > 0) {
1136 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
1137 }
1138
1139 while ($page <= $max_page) {
1140 if ($page == $offset) {
1141 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
1142 } else {
1143 $retHTML .= $del . page_link($param, $page, $page + 1);
1144 }
1145
1146 if ($page < $offset - $pager_pages && $page != 0) {
1147 $retHTML .= " ... ";
1148 $page = $offset - $pager_pages;
1149 $del = '';
1150 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
1151 $retHTML .= " ... ";
1152 $page = $max_page;
1153 $del = '';
1154 } else {
1155 $del = ' | ';
1156 $page++;
1157 }
1158 }
1159
1160 if ($offset < $max_page) {
1161 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
1162 }
1163
1164 $retHTML .= "</div>";
1165
1166 return $retHTML;
1167 }
1168
1169 1;

  ViewVC Help
Powered by ViewVC 1.1.26