/[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 379 - (show annotations)
Tue May 8 12:16:24 2007 UTC (16 years, 11 months ago) by iklaric
File size: 28981 byte(s)
foo

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

  ViewVC Help
Powered by ViewVC 1.1.26