implemented pager which work (with maximum of 10 pages at one time and 100 results on
[BackupPC.git] / lib / BackupPC / SearchLib.pm
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 vars qw(%In $MyURL);
9
10 my $on_page = 100;
11 my $pager_pages = 10;
12
13 sub getUnits() {
14     my @ret = ();
15     my $tmp;
16     my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",
17         "", "", { RaiseError => 1, AutoCommit => 1 } );
18     my $st =
19       $dbh->prepare(
20         " SELECT shares.ID AS ID, shares.share AS name FROM shares;");
21     $st->execute();
22     push (@ret, { 'ID' => '', 'name' => '-'});
23     while ( $tmp = $st->fetchrow_hashref() ) {
24         push( @ret, { 'ID' => $tmp->{'ID'}, 'name' => $tmp->{'name'} } );
25     }
26     $dbh->disconnect();
27     return @ret;
28 }
29
30 sub getWhere($) {
31         my ($param)    = @_;
32         my @conditions;
33
34         sub mk_iso_date($$) {
35                 my ($name,$suffix) = @_;
36
37                 my $yyyy = $param->{ $name . '_year_' . $suffix} || return;
38                 my $mm .= $param->{ $name . '_month_' . $suffix} ||
39                         ( $suffix eq 'from' ? 1 : 12);
40                 my $dd .= $param->{ $name . '_day_' . $suffix} ||
41                         ( $suffix eq 'from' ? 1 : 31);
42                 return sprintf("%04d-%02d-%02d", $yyyy, $mm, $dd);
43         }
44
45         my $backup_from = mk_iso_date('search_backup', 'from');
46         push @conditions, qq{ date(backups.date, 'unixepoch','localtime') >= '$backup_from' } if ($backup_from);
47         my $backup_to = mk_iso_date('search_backup', 'to');
48         push @conditions, qq{ date(backups.date, 'unixepoch','localtime') <= '$backup_to' } if ($backup_to);
49
50         my $files_from = mk_iso_date('search', 'from');
51         push @conditions, qq{ date(files.date, 'unixepoch','localtime') >= '$files_from' } if ($files_from);
52         my $files_to = mk_iso_date('search', 'to');
53         push @conditions, qq{ date(files.date, 'unixepoch','localtime') <= '$files_to' } if ($files_to);
54
55         print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:",join(" | ",@conditions);
56     
57         push( @conditions, ' backups.hostID = ' . $param->{'search_host'} ) if ($param->{'search_host'});
58
59         push (@conditions, " upper(files.name) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
60
61         return (
62                 join(" and ", @conditions),
63                 $files_from, $files_to,
64                 $backup_from, $backup_to
65         );
66 }
67
68
69 sub getFiles($$) {
70         my ($where, $offset) = @_;
71
72         my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",
73                 "", "", { RaiseError => 1, AutoCommit => 1 } );
74
75         my $sql_cols = qq{
76                 files.id                        AS fid,
77                 hosts.name                      AS hname,
78                 shares.name                     AS sname,
79                 shares.share                    AS sharename,
80                 files.backupNum                 AS backupNum,
81                 files.name                      AS filename,
82                 files.path                      AS filepath,
83                 shares.share||files.fullpath    AS networkPath,
84                 date(files.date, 'unixepoch', 'localtime') AS date,
85                 files.type                      AS filetype,
86                 files.size                      AS size,
87                 dvds.name                       AS dvd
88         };
89
90         my $sql_from = qq{
91                 FROM files 
92                         INNER JOIN shares       ON files.shareID=shares.ID
93                         INNER JOIN hosts        ON hosts.ID = shares.hostID
94                         INNER JOIN backups      ON backups.num = files.backupNum and backups.hostID = hosts.ID
95                         LEFT  JOIN dvds         ON dvds.ID = files.dvdid
96         };
97
98         my $sql_where;
99         $sql_where = " WHERE ". $where if ($where);
100
101         my $sql_order = qq{
102                 ORDER BY files.id
103                         LIMIT $on_page
104                         OFFSET ?
105         };
106
107         $offset ||= 0;
108         $offset = ($offset * $on_page) + 1;
109
110         my $sth = $dbh->prepare(qq{ select count(files.id) $sql_from $sql_where });
111         $sth->execute();
112
113         my ($results) = $sth->fetchrow_array();
114
115         $sth = $dbh->prepare(qq{ select $sql_cols $sql_from $sql_where $sql_order });
116         $sth->execute( $offset );
117
118         my @ret;
119       
120         while (my $row = $sth->fetchrow_hashref()) {
121                 push(@ret, { 
122                         'hname'         => $row->{'hname'}, 
123                         'sname'         => $row->{'sname'},
124                         'sharename'     => $row->{'sharename'},
125                         'backupno'      => $row->{'backupNum'},
126                         'fname'         => $row->{'filename'},
127                         'fpath'         => $row->{'filepath'},
128                         'networkpath'   => $row->{'networkPath'},
129                         'date'          => $row->{'date'},
130                         'type'          => $row->{'filetype'},
131                         'size'          => $row->{'size'},
132                         'id'            => $row->{'fid'},
133                         'dvd'           => $row->{'dvd'}
134                 });
135         }
136       
137         $sth->finish();
138         $dbh->disconnect();
139         return ($results, \@ret);
140 }
141
142 sub getBackupsNotBurned()
143   {
144       my $dbh = DBI->connect( "dbi:SQLite:dbname=${TopDir}/$Conf{SearchDB}",
145         "", "", { RaiseError => 1, AutoCommit => 1 } );      
146       my $sql = q{ 
147           SELECT
148             hosts.ID         AS hostID,
149             hosts.name       AS host,
150             backups.num      AS backupno,
151             backups.type     AS type,
152             backups.date     AS date
153           FROM backups, shares, files, hosts
154           WHERE 
155             backups.num    = files.backupNum  AND
156             shares.ID      = files.shareID    AND           
157             backups.hostID = shares.hostID    AND
158             hosts.ID       = backups.hostID   AND
159             files.dvdid    IS NULL
160           GROUP BY 
161             backups.hostID, backups.num
162       };
163       my $st = $dbh -> prepare( $sql );
164       my @ret = ();
165       $st -> execute();
166
167       while ( my $row = $st -> fetchrow_hashref() )
168         {           
169             push(@ret, { 
170                          'host'     => $row->{'host'},
171                          'hostid'   => $row->{'hostID'},
172                          'backupno' => $row->{'backupno'},
173                          'type'     => $row->{'type'},
174                          'date'     => $row->{'date'}
175                        }
176             );
177         }
178       
179       return @ret;      
180   }
181
182 sub displayBackupsGrid()
183   {
184       my $retHTML = "";
185       my $addForm = 1;
186       
187       if ($addForm) {
188
189             $retHTML .= <<EOF3;
190 <script language="javascript" type="text/javascript">
191 <!--
192
193     function checkAll(location)
194     {
195       for (var i=0;i<document.forma.elements.length;i++)
196       {
197         var e = document.forma.elements[i];
198         if ((e.checked || !e.checked) && e.name != \'all\') {
199             if (eval("document.forma."+location+".checked")) {
200                 e.checked = true;
201             } else {
202                 e.checked = false;
203             }
204         }
205       }
206     }
207 //-->
208 </script>      
209 EOF3
210               $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
211               $retHTML.= q{<input type="hidden" value="burn" name="action">};
212               $retHTML .= q{<input type="hidden" value="results" name="search_results">};
213         }
214         $retHTML .= qq{<table style="fview"><tr>};
215
216         if ($addForm) {
217             $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
218         }
219         $retHTML .=  qq{<td class="tableheader">Host</td><td class="tableheader">Backup no</td><td class="tableheader">Type</td><td class="tableheader">date</td></tr>};
220
221         my @backups = getBackupsNotBurned();
222         my $backup;
223
224         if ($addForm) {
225                 $retHTML .= qq{<tr><td colspan=7 style="tableheader">
226                         <input type="submit" value="Burn selected backups on medium" name="submitBurner">
227                         </td></tr>};
228         }
229
230         foreach $backup(@backups) {
231
232                 my $ftype = "";
233             
234                 $retHTML .= "<tr>";
235                 if ($addForm) {
236                         $retHTML .= qq{<td class="fview"><input type="checkbox" name="fcb} .
237                                 $backup->{'hostid'}."_".$backup->{'backupno'} . 
238                                 qq{" value="} . $backup->{'hostid'}."_".$backup->{'backupno'} .
239                                 qq{"></td>};
240                 }           
241             
242                 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
243                         '<td class="fviewborder">' . $backup->{'backupno'} . '</td>' .
244                         '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
245                         '<td class="fviewborder">' . $backup->{'date'} . '<td>' .
246                         '</tr>';
247         }
248
249         $retHTML .= "</table>";
250
251         if ($addForm) {
252                 $retHTML .= "</form>";
253         }
254       
255         return $retHTML;
256 }      
257
258 sub displayGrid($$$$) {
259         my ($where, $addForm, $offset, $hilite) = @_;
260         my $retHTML = "";
261  
262         if ($addForm) {
263                 $retHTML .= qq{<form name="forma" method="GET" action="$MyURL">};
264                 $retHTML.= qq{<input type="hidden" value="search" name="action">};
265                 $retHTML .= qq{<input type="hidden" value="results" name="search_results">};
266         }
267
268         my ($results, $files) = getFiles($where, $offset);
269
270         my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
271
272         $retHTML .= qq{
273         <br/>Found $results files, showing $from - $to
274         <table style="fview" width="100%">
275                 <tr> 
276                 <td class="tableheader">Share</td>
277                 <td class="tableheader">Name</td>
278                 <td class="tableheader">Type</td>
279                 <td class="tableheader">#</td>
280                 <td class="tableheader">Size</td>
281                 <td class="tableheader">Date</td>
282                 <td class="tableheader">Media</td>
283                 </tr>
284         };
285
286         my $file;
287
288         sub hilite_html($$) {
289                 my ($html, $search) = @_;
290                 $html =~ s#($search)#<b>$1</b>#gis;
291                 return $html;
292         }
293
294         sub restore_link($$$$$$) {
295                 my $type = shift;
296                 my $action = 'RestoreFile';
297                 $action = 'browse' if (lc($type) eq 'dir');
298                 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
299         }
300
301         foreach $file (@{ $files }) {
302                 my $typeStr  = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
303                 $retHTML .= "<tr>";
304
305                 foreach my $v ((
306                         $file->{'sharename'},
307                         qq{<img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" align="center">&nbsp;} . hilite_html( $file->{'fpath'}, $hilite ),
308                         $typeStr,
309                         restore_link( $typeStr, $file->{'hname'}, $file->{'backupno'}, $file->{'sname'}, $file->{'fpath'}, $file->{'backupno'} ),
310                         $file->{'size'},
311                         $file->{'date'},
312                         $file->{'dvd'}
313                 )) {
314                         $retHTML .= qq{<td class="fviewborder">$v</td>};
315                 }
316
317                 $retHTML .= "</tr>";
318         }
319         $retHTML .= "</table>";
320
321         # all variables which has to be transfered
322         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/) {
323                 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
324         }
325
326         my $del = '';
327         my $max_page = int( $results / $on_page );
328         my $page = 0;
329
330         my $link_fmt = '<a href = "#" onclick="document.forma.offset.value=%d;document.forma.submit();">%s</a>';
331
332         $retHTML .= '<div style="text-align: center;">';
333
334         if ($offset > 0) {
335                 $retHTML .= sprintf($link_fmt, $offset - 1, '&lt;&lt;') . ' ';
336         }
337
338         while ($page <= $max_page) {
339                 if ($page == $offset) {
340                         $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
341                 } else {
342                         $retHTML .= $del . sprintf($link_fmt, $page, $page + 1);
343                 }
344
345                 if ($page < $offset - $pager_pages && $page != 0) {
346                         $retHTML .= " ... ";
347                         $page = $offset - $pager_pages;
348                         $del = '';
349                 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
350                         $retHTML .= " ... ";
351                         $page = $max_page;
352                         $del = '';
353                 } else {
354                         $del = ' | ';
355                         $page++;
356                 }
357         }
358
359         if ($offset < $max_page) {
360                 $retHTML .= ' ' . sprintf($link_fmt, $offset + 1, '&gt;&gt;');
361         }
362
363         $retHTML .= "</div>";
364
365         $retHTML .= "</form>" if ($addForm);
366
367         return $retHTML;
368 }
369
370 1;