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