/[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 211 - (show annotations)
Sun Oct 16 10:57:55 2005 UTC (18 years, 7 months ago) by dpavlin
File size: 25614 byte(s)
 r8603@llin:  dpavlin | 2005-10-15 22:44:32 +0200
 implemented sort in search results

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

  ViewVC Help
Powered by ViewVC 1.1.26