]> git.sur5r.net Git - bacula/bacula/commitdiff
Merge in changes from trunk
authorKern Sibbald <kern@sibbald.com>
Sat, 10 Nov 2007 10:44:24 +0000 (10:44 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 10 Nov 2007 10:44:24 +0000 (10:44 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/branches/Branch-2.2@5884 91ce42f0-d328-0410-95d8-f526ca767f89

63 files changed:
gui/brestore/ReleaseNotes
gui/brestore/brestore.pl
gui/bweb/ReleaseNotes
gui/bweb/cgi/bgraph.pl
gui/bweb/cgi/bweb.pl
gui/bweb/html/bresto.html [new file with mode: 0644]
gui/bweb/html/bresto.js [new file with mode: 0644]
gui/bweb/lang/es/tpl/begin.tpl
gui/bweb/lang/es/tpl/change_location.tpl
gui/bweb/lang/es/tpl/config_edit.tpl
gui/bweb/lang/es/tpl/config_view.tpl
gui/bweb/lang/es/tpl/display_client_job.tpl
gui/bweb/lang/es/tpl/display_form_media.tpl
gui/bweb/lang/es/tpl/display_job_zoom.tpl
gui/bweb/lang/es/tpl/display_log.tpl
gui/bweb/lang/es/tpl/display_media.tpl
gui/bweb/lang/es/tpl/display_media_zoom.tpl
gui/bweb/lang/es/tpl/help_extern_compute.tpl
gui/bweb/lang/es/tpl/help_intern_compute.tpl
gui/bweb/lang/es/tpl/move_media.tpl
gui/bweb/lang/es/tpl/update_location.tpl
gui/bweb/lang/es/tpl/update_media.tpl
gui/bweb/lang/fr/tpl/begin.tpl
gui/bweb/lang/fr/tpl/change_location.tpl
gui/bweb/lang/fr/tpl/config_edit.tpl
gui/bweb/lang/fr/tpl/config_view.tpl
gui/bweb/lang/fr/tpl/display_client_job.tpl
gui/bweb/lang/fr/tpl/display_form_media.tpl
gui/bweb/lang/fr/tpl/display_job_zoom.tpl
gui/bweb/lang/fr/tpl/display_log.tpl
gui/bweb/lang/fr/tpl/display_media.tpl
gui/bweb/lang/fr/tpl/display_media_zoom.tpl
gui/bweb/lang/fr/tpl/help_extern_compute.tpl
gui/bweb/lang/fr/tpl/help_intern_compute.tpl
gui/bweb/lang/fr/tpl/move_media.tpl
gui/bweb/lang/fr/tpl/update_location.tpl
gui/bweb/lang/fr/tpl/update_media.tpl
gui/bweb/lib/Bconsole.pm
gui/bweb/lib/Bweb.pm
gui/bweb/script/bweb-postgresql.sql
gui/bweb/script/tpl_extract_msg.pl [new file with mode: 0755]
gui/bweb/script/upgrade-2.2_3.0_postgresql.sql [new file with mode: 0644]
gui/bweb/tpl/begin.tpl
gui/bweb/tpl/change_location.tpl
gui/bweb/tpl/config_edit.tpl
gui/bweb/tpl/config_view.tpl
gui/bweb/tpl/display_client_job.tpl
gui/bweb/tpl/display_form_job.tpl
gui/bweb/tpl/display_form_media.tpl
gui/bweb/tpl/display_job_zoom.tpl
gui/bweb/tpl/display_log.tpl
gui/bweb/tpl/display_media.tpl
gui/bweb/tpl/display_media_zoom.tpl
gui/bweb/tpl/display_user.tpl [new file with mode: 0644]
gui/bweb/tpl/display_users.tpl [new file with mode: 0644]
gui/bweb/tpl/help_extern_compute.tpl
gui/bweb/tpl/help_intern_compute.tpl
gui/bweb/tpl/move_media.tpl
gui/bweb/tpl/update_location.tpl
gui/bweb/tpl/update_media.tpl
gui/debian/bweb.postinst
gui/debian/changelog
gui/debian/control

index 892442079258a067c3cabfd6338e1eda40dd55d4..163243ba012b3c644f15e903879c97f19a650728 100644 (file)
@@ -1,5 +1,12 @@
           Release Notes for brestore 2.2.0
 
+Version 2.2.5-2:
+ - Use 2 transactions in brestore.pl -b
+   (you can use Ctrl-C in cleanup)
+
+Version 2.2.5-1:
+ - Fix warning, thanks to Tuomas Jormola
+
 Version 2.2.0-2:
  - cleanup brestore
  - update brestore_xxx only when job is in (T, f, A)
index 6a8da818357256bf68496d20268b5312b3db847f..bfcbeaba63c3454302aa8a646baa5f7c497cd1b9 100755 (executable)
@@ -2397,6 +2397,9 @@ sub update_cache
 
     $self->update_brestore_table(map { $_->[0] } @$jobs);
 
+    $self->{conf}->{dbh}->commit();
+    $self->{conf}->{dbh}->begin_work();
+
     print STDERR "Cleaning path visibility\n";
     
     my $nb = $self->dbh_do("
@@ -3275,7 +3278,7 @@ sub HELP_MESSAGE
     exit 1;
 }
 
-my $file_conf = "$ENV{HOME}/.brestore.conf" ;
+my $file_conf = (exists $ENV{HOME})? "$ENV{HOME}/.brestore.conf" : undef ;
 my $batch_mod;
 
 GetOptions("conf=s"   => \$file_conf,
@@ -3283,6 +3286,11 @@ GetOptions("conf=s"   => \$file_conf,
           "debug"    => \$debug,
           "help"     => \&HELP_MESSAGE) ;
 
+if (! defined $file_conf) {
+    print STDERR "Could not detect default config and no config file specified\n";
+    HELP_MESSAGE();
+}
+
 my $p = new Pref($file_conf);
 
 if (! -f $file_conf) {
@@ -3300,7 +3308,7 @@ if ($batch_mod) {
     exit (0);
 }
 
-$glade_file = $p->{glade_file};
+$glade_file = $p->{glade_file} || $glade_file;
 
 foreach my $path ('','.','/usr/share/brestore','/usr/local/share/brestore') {
     if (-f "$path/$glade_file") {
index a4c3f51ee111c32661cc2b31f49ad0fcfb32799e..fe08902b62bedf6aee01adb4bb512ba29a6a9e8a 100644 (file)
@@ -1,4 +1,19 @@
           Release Notes for bweb 2.2
+2007/11/08
+ - Add Prev/Next on job log output
+
+2007/10/31
+ - Add a error filter to Job zoom view
+
+2007/10/30
+ - Replace VolStatus by Enabled in volume location 
+ - Add Enabled in volume update and zoom
+
+2007/10/26
+ - add an option to view only expired media
+
+2007/09/26
+ - add bresto.pl, bresto.html and bresto.js
 
 2007/08/20
  - fix update of locationid field during label barcodes 
index e3d0024d4442cf49e2e7cb95951c872dfab06d1e..cb3cdcab610f5605d6af87c0ee01e28ace82c135 100755 (executable)
@@ -110,6 +110,9 @@ if ($arg->{jclient_groups}) {
     $groupq = " AND client_group_name IN ($arg->{jclient_groups}) ";
 }
 
+$bweb->can_do('r_view_job');
+my $filter = $bweb->get_client_filter();
+
 my $gtype = CGI::param('gtype') || 'bars';
 
 print CGI::header('image/png');
@@ -205,7 +208,7 @@ SELECT
        Client.Name                      AS clientname,
        $jobt.Name                       AS jobname,
        $jobt.JobBytes                   AS jobbytes
-FROM $jobt, FileSet, Client $groupf
+FROM $jobt, FileSet, Client $filter $groupf
 WHERE $jobt.ClientId = Client.ClientId
   AND $jobt.FileSetId = FileSet.FileSetId
   AND $jobt.Type = 'B'
@@ -243,7 +246,7 @@ SELECT
        Client.Name                      AS clientname,
        $jobt.Name                       AS jobname,
        $jobt.JobFiles                   AS jobfiles
-FROM $jobt, FileSet, Client $groupf
+FROM $jobt, FileSet, Client $filter $groupf
 WHERE $jobt.ClientId = Client.ClientId
   AND $jobt.FileSetId = FileSet.FileSetId
   AND $jobt.Type = 'B'
@@ -285,7 +288,7 @@ SELECT UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
        Job.Name                         AS jobname,
        base64_decode_lstat(8,LStat)     AS lstat
 
-FROM Job, FileSet, Filename, Path, File, Client
+FROM Job, FileSet, Filename, Path, File, Client $filter
 WHERE Job.ClientId = Client.ClientId
   AND Job.FileSetId = FileSet.FileSetId
   AND Job.Type = 'B'
@@ -335,7 +338,7 @@ SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
        Job.Name                      AS jobname,
        brestore_pathvisibility.size  AS size
 
-FROM Job, Client, FileSet, Path, brestore_pathvisibility
+FROM Job, Client $filter, FileSet, Path, brestore_pathvisibility
 WHERE Job.ClientId = Client.ClientId
   AND Job.FileSetId = FileSet.FileSetId
   AND Job.Type = 'B'
@@ -382,7 +385,7 @@ SELECT
                         - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01) 
          AS rate
 
-FROM $jobt, FileSet, Client $groupf
+FROM $jobt, FileSet, Client $filter $groupf
 WHERE $jobt.ClientId = Client.ClientId
   AND $jobt.FileSetId = FileSet.FileSetId
   AND $jobt.Type = 'B'
@@ -424,7 +427,7 @@ SELECT
   $bweb->{sql}->{SEC_TO_INT}(  $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
                              - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
          AS duration
-FROM $jobt, FileSet, Client $groupf
+FROM $jobt, FileSet, Client $filter $groupf
 WHERE $jobt.ClientId = Client.ClientId
   AND $jobt.FileSetId = FileSet.FileSetId
   AND $jobt.Type = 'B'
@@ -485,7 +488,7 @@ $limitq
 SELECT
      " . ($per_t?"":"UNIX_TIMESTAMP") . "($stime) AS A,
      $t(JobBytes)                  AS nb
-FROM $jobt, FileSet, Client $groupf
+FROM $jobt, FileSet, Client $filter $groupf
 WHERE $jobt.ClientId = Client.ClientId
   AND $jobt.FileSetId = FileSet.FileSetId
   AND $jobt.Type = 'B'
@@ -507,7 +510,7 @@ $limit
                        );
 
     my $all = $dbh->selectall_arrayref($query) ;
-    print STDERR Data::Dumper::Dumper($all);
+#    print STDERR Data::Dumper::Dumper($all);
     my ($ret) = make_tab_sum($all);
 
     print $obj->plot([$ret->{date}, $ret->{nb}])->png;    
index b6d1e97dfa99c86cc2c279f736b6ce7d35e4ecf8..1fc7b768a725d47f8a3aa872592313169671f4a3 100755 (executable)
@@ -84,14 +84,32 @@ if ($action eq 'begin') {           # main display
     $bweb->display_job(limit => 10); 
 
 } elsif ($action eq 'view_conf') {
+    $bweb->can_do('r_configure');
     $conf->view()
 
 } elsif ($action eq 'edit_conf') {
+    $bweb->can_do('r_configure');
     $conf->edit();
 
 } elsif ($action eq 'apply_conf') {
+    $bweb->can_do('r_configure');
     $conf->modify();
 
+} elsif ($action eq 'user_del') {
+    $bweb->users_del();
+
+} elsif ($action eq 'user_add') {
+    $bweb->users_add();
+
+} elsif ($action eq 'user_edit') {
+    $bweb->display_user();
+
+} elsif ($action eq 'user_save') {
+    $bweb->users_add();
+
+} elsif ($action eq 'users') {
+    $bweb->display_users();
+
 } elsif ($action eq 'client') {        
     $bweb->display_clients();
 
@@ -112,7 +130,7 @@ if ($action eq 'begin') {           # main display
 
 } elsif ($action eq 'media') {
     print "<div><table border='0'><tr><td valign='top'>\n";
-    my $fields = $bweb->get_form(qw/db_locations db_pools
+    my $fields = $bweb->get_form(qw/db_locations db_pools expired
                                    qlocations qpools volstatus qre_media
                                    limit  qmediatypes db_mediatypes/);
     $bweb->display($fields, "display_form_media.tpl");
@@ -122,10 +140,12 @@ if ($action eq 'begin') {         # main display
                         limit => $arg->{limit});
     print "</td></tr></table></div>";
 
-} elsif ($action eq 'medias') {
-    $bweb->display_medias();
+} elsif ($action eq 'allmedia') {
+    $bweb->display_allmedia();
 
 } elsif ($action eq 'eject') {
+    $bweb->can_do('r_autochanger_mgnt');
+
     my $arg = $bweb->get_form("ach");
     my $a = $bweb->ach_get($arg->{ach});
     
@@ -147,6 +167,8 @@ if ($action eq 'begin') {           # main display
     $bweb->eject_media();
 
 } elsif ($action eq 'clear_io') {
+    $bweb->can_do('r_autochanger_mgnt');
+
     my $arg = $bweb->get_form('ach');
 
     my $a = $bweb->ach_get($arg->{ach});
@@ -163,6 +185,8 @@ if ($action eq 'begin') {           # main display
     $bweb->ach_del();
 
 } elsif ($action eq 'ach_view') {
+    $bweb->can_do('r_autochanger_mgnt');
+
     # TODO : get autochanger name and create it
     $bweb->connect_db();
     my $arg = $bweb->get_form('ach');
@@ -177,6 +201,8 @@ if ($action eq 'begin') {           # main display
     $bweb->ach_add();
 
 } elsif ($action eq 'ach_load') {
+    $bweb->can_do('r_autochanger_mgnt');
+
     my $arg = $bweb->get_form('ach', 'drive', 'slot');
     
     my $a = $bweb->ach_get($arg->{ach});
@@ -193,6 +219,8 @@ if ($action eq 'begin') {           # main display
     }
     
 } elsif ($action eq 'ach_unload') {
+    $bweb->can_do('r_autochanger_mgnt');
+
     my $arg = $bweb->get_form('drive', 'slot', 'ach');
 
     my $a = $bweb->ach_get($arg->{ach});
@@ -221,6 +249,9 @@ if ($action eq 'begin') {           # main display
     $bweb->help_extern_compute();
 
 } elsif ($action eq 'extern') {
+    $bweb->can_do('r_media_mgnt');
+    $bweb->can_do('r_autochanger_mgnt');
+
     print "<div style='float: left;'>";
     my @achs = $bweb->eject_media();
     for my $ach (@achs) {
@@ -228,7 +259,7 @@ if ($action eq 'begin') {           # main display
        $bweb->update_slots();
     }
     print "</div><div style='float: left;margin-left: 20px;'>";
-    $bweb->move_media();
+    $bweb->move_media('no');   # enabled = no
     print "</div>";
 
 } elsif ($action eq 'move_email') {
@@ -244,10 +275,11 @@ if ($action eq 'begin') {         # main display
     $bweb->display($bweb, 'about.tpl');
 
 } elsif ($action eq 'intern') {
-    $bweb->move_media(); # TODO : remove that
+    $bweb->move_media('yes'); # TODO : remove that
 
 } elsif ($action eq 'move_media') {
-    $bweb->move_media(); 
+    my $a = $bweb->get_form('enabled');
+    $bweb->move_media($a->{enabled}); 
 
 } elsif ($action eq 'save_location') {
     $bweb->save_location();
@@ -292,9 +324,10 @@ if ($action eq 'begin') {          # main display
     $bweb->groups_del();
 
 } elsif ($action eq 'job') {
-
+    $bweb->can_do('r_view_job');
     print "<div><table border='0'><tr><td valign='top'>\n";
-    my $fields = $bweb->get_form(qw/status level db_clients db_filesets
+    my $fields = $bweb->get_form(qw/status level filter db_clients
+                                   db_filesets 
                                    limit age offset qclients qfilesets
                                    jobtype qpools db_pools
                                    db_client_groups qclient_groups/); # drop this to hide 
@@ -307,9 +340,9 @@ if ($action eq 'begin') {           # main display
                       limit => $arg->{limit});
     print "</td></tr></table></div>";
 } elsif ($action eq 'job_group') {
-
+    $bweb->can_do('r_view_job');
     print "<div><table border='0'><tr><td valign='top'>\n";
-    my $fields = $bweb->get_form(qw/limit level age 
+    my $fields = $bweb->get_form(qw/limit level age filter 
                                     db_client_groups qclient_groups/); # drop this to hide 
 
     $fields->{hide_status} = 1;
@@ -332,7 +365,6 @@ if ($action eq 'begin') {           # main display
     }
 
 } elsif ($action eq 'group_stats') {
-
     $bweb->display_group_stats(age => $arg->{age});
 
 } elsif ($action eq 'running') {
@@ -342,6 +374,7 @@ if ($action eq 'begin') {           # main display
     $bweb->display_running_job();
 
 } elsif ($action eq 'update_from_pool') {
+    $bweb->can_do('r_media_mgnt');
     my $elt = $bweb->get_form(qw/media pool/);
     unless ($elt->{media} || $elt->{pool}) {
        $bweb->error("Can't get media or pool param");
@@ -358,6 +391,7 @@ if ($action eq 'begin') {           # main display
     $bweb->update_media();
 
 } elsif ($action eq 'client_status') {
+    $bweb->can_do('r_client_status');
     my $b;
     foreach my $client (CGI::param('client')) {
        if ($client =~ m/$client_re/) {
@@ -415,7 +449,7 @@ if ($action eq 'begin') {           # main display
     $bweb->fileset_view();
 
 } else {
-    $bweb->error("Sorry, this action don't exist");
+    $bweb->error("Sorry, this action doesn't exist");
 }
 
 $bweb->display_end();
diff --git a/gui/bweb/html/bresto.html b/gui/bweb/html/bresto.html
new file mode 100644 (file)
index 0000000..ecc139b
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+       <head>
+       <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+       <title>Bweb - restore</title>
+
+       <link rel="stylesheet" type="text/css" href="/bweb/ext/resources/css/ext-all.css" />
+
+    <script type="text/javascript" src="/bweb/ext/adapter/ext/ext-base.js"></script>     <!-- ENDLIBS -->
+
+<!--    <script type="text/javascript" src="/bweb/ext/ext-all.js"></script> -->
+    <script type="text/javascript" src="/bweb/ext/ext-all-debug.js"></script>
+       <script type="text/javascript" src="bweb.js"></script>
+       <script type="text/javascript" src="bresto.js"></script>
+       
+       </head>
+       <body>
+<div id="div-container"          >
+    <div id="div-main-menu"      >
+    <div id="div-toolbar"        ></div>
+    <div id="div-tb-sel"         ></div>
+    <div id="div-files"          ></div>
+    <div id="div-file-versions"  ></div>
+    <div id="div-file-selection" ></div>
+    <div id="div-tree"           ></div>
+</div>         
+
+<div id="div-resto-dlg" style="visibility:hidden;">
+<div id="div-resto-form" >
+<div id="div-resto-form-bp1"></div> <div id="div-resto-form-bp2"></div> 
+</div>
+</div>
+       </body>
+</html>
diff --git a/gui/bweb/html/bresto.js b/gui/bweb/html/bresto.js
new file mode 100644 (file)
index 0000000..5598500
--- /dev/null
@@ -0,0 +1,772 @@
+
+//   Bweb - A Bacula web interface
+//   Bacula® - The Network Backup Solution
+//
+//   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+//
+//   The main author of Bweb is Eric Bollengier.
+//   The main author of Bacula is Kern Sibbald, with contributions from
+//   many others, a complete list can be found in the file AUTHORS.
+//
+//   This program is Free Software; you can redistribute it and/or
+//   modify it under the terms of version two of the GNU General Public
+//   License as published by the Free Software Foundation plus additions
+//   that are listed in the file LICENSE.
+//
+//   This program is distributed in the hope that it will be useful, but
+//   WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//   General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public License
+//   along with this program; if not, write to the Free Software
+//   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+//   02110-1301, USA.
+//
+//   Bacula® is a registered trademark of John Walker.
+//   The licensor of Bacula is the Free Software Foundation Europe
+//   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+//   Switzerland, email:ftf@fsfeurope.org.
+
+// render if vol is online/offline
+function rd_vol_is_online(val)
+{
+   return '<img src="/bweb/inflag' + val + '.png">';
+}
+
+// TODO: fichier ou rep
+function rd_file_or_dir(val)
+{
+   if (val == 'F') {
+      return '<img src="/bweb/A.png">';
+   } else {
+      return '<img src="/bweb/R.png">';
+   }
+}
+
+Ext.namespace('Ext.brestore');
+
+Ext.brestore.jobid=0;            // selected jobid
+Ext.brestore.jobdate='';         // selected date
+Ext.brestore.client='';          // selected client
+Ext.brestore.path='';            // current path (without user location)
+Ext.brestore.root_path='';       // user location
+
+Ext.brestore.option_vosb = false;
+Ext.brestore.option_vafv = false;
+
+
+function get_node_path(node)
+{
+   var temp='';
+   for (var p = node; p; p = p.parentNode) {
+       if (p.parentNode) {
+          if (p.text == '/') {
+             temp = p.text + temp;
+          } else {
+          temp = p.text + '/' + temp;
+          }
+       }
+   }
+   return Ext.brestore.root_path + temp;
+}
+
+
+function init_params(baseParams)
+{
+   baseParams['client']= Ext.brestore.client;
+
+   if (Ext.brestore.option_vosb) {        
+      baseParams['jobid'] = Ext.brestore.jobid;
+   } else {
+      baseParams['date'] = Ext.brestore.jobdate;
+   }
+   return baseParams;
+}
+
+
+function ext_init()
+{
+//////////////////////////////////////////////////////////////:
+    var Tree = Ext.tree;
+    var tree_loader = new Ext.tree.TreeLoader({
+            baseParams:{}, 
+            dataUrl:'/cgi-bin/bweb/bresto.pl'
+        });
+
+    var tree = new Ext.tree.TreePanel('div-tree', {
+        animate:true, 
+        loader: tree_loader,
+        enableDD:true,
+        enableDragDrop: true,
+        containerScroll: true
+    });
+
+    // set the root node
+    var root = new Ext.tree.AsyncTreeNode({
+        text: 'Select a job',
+        draggable:false,
+        id:'source'
+    });
+    tree.setRootNode(root);
+
+    // render the tree
+    tree.render();
+//    root.expand();
+
+    tree.on('click', function(node, event) { 
+        Ext.brestore.path = get_node_path(node);
+
+        file_store.removeAll();
+       file_versions_store.removeAll();
+        file_store.load({params:init_params({action: 'list_files',
+                                             node:node.id})
+                       });
+        return true;
+    });
+
+    tree.on('beforeload', function(e) {
+        file_store.removeAll();
+        return true;
+    });
+
+
+////////////////////////////////////////////////////////////////
+
+  var file_store = new Ext.data.Store({
+        proxy: new Ext.data.HttpProxy({
+            url: '/cgi-bin/bweb/bresto.pl',
+            method: 'GET',
+            params:{}
+        }),
+
+        reader: new Ext.data.ArrayReader({
+        }, Ext.data.Record.create([
+   {name: 'fileid'    },
+   {name: 'filenameid'},
+   {name: 'pathid'    },
+   {name: 'name'      },
+   {name: 'size',     type: 'int'  },
+   {name: 'mtime',    type: 'date', dateFormat: 'Y-m-d h:i:s'}
+        ]))
+   });
+
+   var cm = new Ext.grid.ColumnModel([{
+           id:        'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
+           header:    'File',
+           dataIndex: 'name',
+           width:     100,
+           css:       'white-space:normal;'
+        },{
+           header:    "Size",
+           dataIndex: 'size',
+           renderer:  human_size,
+           width:     50
+        },{
+           header:    "Date",
+           dataIndex: 'mtime',
+           width:     100
+        },{
+           dataIndex: 'pathid',
+           hidden: true
+        },{
+           dataIndex: 'filenameid',
+           hidden: true
+        },{
+           dataIndex: 'fileid',
+           hidden: true
+        }
+        ]);
+
+    // by default columns are sortable
+   cm.defaultSortable = true;
+
+    // create the grid
+   var files_grid = new Ext.grid.Grid('div-files', {
+        ds: file_store,
+        cm: cm,
+        ddGroup : 'TreeDD',
+        enableDrag: true,
+        enableDragDrop: true,
+        selModel: new Ext.grid.RowSelectionModel(),
+        loadMask: true,
+        enableColLock:false
+        
+    });
+
+    // when we reload the view,
+    // we clear the file version box
+    file_store.on('beforeload', function(e) {
+        file_versions_store.removeAll();
+        return true;
+    });
+
+    // TODO: selection only when using dblclick
+    files_grid.selModel.on('rowselect', function(e,i,r) { 
+        Ext.brestore.filename = r.json[3];
+        file_versions_store.load({params:init_params({action: 'list_versions',
+                                                    vafv: Ext.brestore.option_vafv,
+                                                    pathid: r.json[2],
+                                                    filenameid: r.json[1]
+                                                     })
+                                 });
+        return true;
+    });
+    files_grid.render();
+
+//////////////////////////////////////////////////////////////:
+
+  var file_selection_store = new Ext.data.Store({
+        proxy: new Ext.data.MemoryProxy(),
+
+        reader: new Ext.data.ArrayReader({
+        }, Ext.data.Record.create([
+   {name: 'jobid'     },
+   {name: 'fileid'    },
+   {name: 'filenameid'},
+   {name: 'pathid'    },
+   {name: 'name'      },
+   {name: 'size',     type: 'int'  },
+   {name: 'mtime',    type: 'date', dateFormat: 'Y-m-d h:i:s'}
+        ]))
+   });
+
+   var file_selection_cm = new Ext.grid.ColumnModel([{
+           id:        'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
+           header:    "Name",
+           dataIndex: 'name',
+           width:     250
+        },{
+           header:    "JobId",
+           width:     50,
+           dataIndex: 'jobid'
+        },{
+           header:    "Size",
+           dataIndex: 'size',
+           renderer:  human_size,
+           width:     50
+        },{
+           header:    "Date",
+           dataIndex: 'mtime',
+           width:     100
+        },{
+           dataIndex: 'pathid',
+           hidden: true
+        },{
+           dataIndex: 'filenameid',
+           hidden: true
+        },{
+           dataIndex: 'fileid',
+           hidden: true
+        }
+        ]);
+
+
+    // create the grid
+   var file_selection_grid = new Ext.grid.Grid('div-file-selection', {
+        cm: file_selection_cm,
+        ds: file_selection_store,
+        ddGroup : 'TreeDD',
+        enableDrag: false,
+        enableDrop: true,
+        selModel: new Ext.grid.RowSelectionModel(),
+        loadMask: true,
+        enableColLock:false
+        
+    });
+
+    var file_selection_record = Ext.data.Record.create(
+      {name: 'jobid'},
+      {name: 'fileid'},
+      {name: 'filenameid'},
+      {name: 'pathid'},
+      {name: 'size'},
+      {name: 'mtime'}
+    );
+// data.selections[0].json[]
+// data.node.id
+// http://extjs.com/forum/showthread.php?t=12582&highlight=drag+drop
+    var ddrow = new Ext.dd.DropTarget(file_selection_grid.container, {
+        ddGroup : 'TreeDD',
+        copy:false,
+        notifyDrop : function(dd, e, data){
+           var r;
+           if (data.selections) {
+             if (data.grid.id == 'div-files') {
+                 for(var i=0;i<data.selections.length;i++) {
+                    r = new file_selection_record({
+                      jobid:     Ext.brestore.jobid,
+                      fileid:    data.selections[i].json[0],
+                      filenameid:data.selections[i].json[1],
+                      pathid:    data.selections[i].json[2],
+                      name: Ext.brestore.path + data.selections[i].json[3],
+                      size:      data.selections[i].json[4],
+                      mtime:     data.selections[i].json[5]
+                    });
+                    file_selection_store.add(r)
+                 }
+             }
+
+             if (data.grid.id == 'div-file-versions') {
+                    r = new file_selection_record({
+                      jobid:     data.selections[0].json[3],
+                      fileid:    data.selections[0].json[0],
+                      filenameid:data.selections[0].json[1],
+                      pathid:    data.selections[0].json[2],
+                      name: Ext.brestore.path + Ext.brestore.filename,
+                      size:      data.selections[0].json[7],
+                      mtime:     data.selections[0].json[8]     
+                    });
+                    file_selection_store.add(r)
+             }
+           }
+  
+           if (data.node) {
+              var path= get_node_path(data.node);
+              r = new file_selection_record({
+                      jobid:     Ext.brestore.jobid,
+                      fileid:    0,
+                      filenameid:0,
+                      pathid:    data.node.id,
+                      name:      path,
+                      size:      4096,
+                      mtime:     0
+              });
+              file_selection_store.add(r)
+           }
+  
+           return true;
+    }});
+
+
+   file_selection_grid.on('enddrag', function(dd,e) { 
+        alert(e) ; return true;
+    });
+   file_selection_grid.on('notifyDrop', function(dd,e) { 
+        alert(e) ; return true;
+    });
+   file_selection_grid.render();
+
+///////////////////////////////////////////////////////
+
+  var file_versions_store = new Ext.data.Store({
+        proxy: new Ext.data.HttpProxy({
+            url: '/cgi-bin/bweb/bresto.pl',
+            method: 'GET',
+            params:{offset:0, limit:50 }
+        }),
+
+        reader: new Ext.data.ArrayReader({
+        }, Ext.data.Record.create([
+   {name: 'fileid'    },
+   {name: 'filenameid'},
+   {name: 'pathid'    },
+   {name: 'jobid'     },
+   {name: 'volume'    },
+   {name: 'inchanger' },
+   {name: 'md5'       },
+   {name: 'size',     type: 'int'  },
+   {name: 'mtime'} //,    type: 'date', dateFormat: 'Y-m-d h:i:s'}
+        ]))
+   });
+
+   var file_versions_cm = new Ext.grid.ColumnModel([{
+           id:        'name', // id assigned so we can apply custom css (e.g. .x-grid-col-topic b { color:#333 })
+           dataIndex: 'name',
+           hidden: true
+        },{
+           header:    "InChanger",
+           dataIndex: 'inchanger',
+           width:     60,
+           renderer:  rd_vol_is_online
+        },{
+           header:    "Volume",
+           dataIndex: 'volume'
+        },{
+           header:    "JobId",
+           width:     50,
+           dataIndex: 'jobid'
+        },{
+           header:    "Size",
+           dataIndex: 'size',
+           renderer:  human_size,
+           width:     50
+        },{
+           header:    "Date",
+           dataIndex: 'mtime',
+           width:     100
+        },{
+           header:    "MD5",
+           dataIndex: 'md5',
+           width:     160
+        },{
+           dataIndex: 'pathid',
+           hidden: true
+        },{
+           dataIndex: 'filenameid',
+           hidden: true
+        },{
+           dataIndex: 'fileid',
+           hidden: true
+        }
+   ]);
+
+    // by default columns are sortable
+   file_versions_cm.defaultSortable = true;
+
+    // create the grid
+   var file_versions_grid = new Ext.grid.Grid('div-file-versions', {
+        ds: file_versions_store,
+        cm: file_versions_cm,
+        ddGroup : 'TreeDD',
+        enableDrag: true,
+        enableDrop: false,
+        selModel: new Ext.grid.RowSelectionModel(),
+        loadMask: true,
+        enableColLock:false
+        
+    });
+
+    file_versions_grid.on('rowdblclick', function(e) { 
+        alert(e) ; file_versions_store.removeAll(); return true;
+    });
+    file_versions_grid.render();
+
+//////////////////////////////////////////////////////////////:
+
+
+    var client_store = new Ext.data.Store({
+        proxy: new Ext.data.HttpProxy({
+            url: '/cgi-bin/bweb/bresto.pl',
+            method: 'GET',
+            params:{action:'list_client'}
+        }),
+
+        reader: new Ext.data.ArrayReader({
+        }, Ext.data.Record.create([
+           {name: 'name' }
+        ]))
+    });
+
+    var client_combo = new Ext.form.ComboBox({
+        fieldLabel: 'Clients',
+        store: client_store,
+        displayField:'name',
+        typeAhead: true,
+        mode: 'local',
+        triggerAction: 'all',
+        emptyText:'Select a client...',
+        selectOnFocus:true,
+        forceSelection: true,
+        width:135
+    });
+
+    client_combo.on('valid', function(e) { 
+        Ext.brestore.client = e.getValue();
+        job_store.load( {params:{action: 'list_job',
+                                 client:Ext.brestore.client}});
+        return true;
+    });
+
+//////////////////////////////////////////////////////////////:
+
+    var job_store = new Ext.data.Store({
+        proxy: new Ext.data.HttpProxy({
+            url: '/cgi-bin/bweb/bresto.pl',
+            method: 'GET',
+            params:{offset:0, limit:50 }
+        }),
+
+        reader: new Ext.data.ArrayReader({
+        }, Ext.data.Record.create([
+           {name: 'jobid' },
+           {name: 'date'  },
+           {name: 'jobname' }
+        ]))
+    });
+
+    var job_combo = new Ext.form.ComboBox({
+        fieldLabel: 'Jobs',
+        store: job_store,
+        displayField:'jobname',
+        typeAhead: true,
+        mode: 'local',
+        triggerAction: 'all',
+        emptyText:'Select a job...',
+        selectOnFocus:true,
+        forceSelection: true,
+        width:350
+    });
+
+    job_combo.on('select', function(e,c) {
+        Ext.brestore.jobid = c.json[0];
+       Ext.brestore.jobdate = c.json[1];
+        Ext.brestore.root_path='';
+        root.setText("Root");
+        tree_loader.baseParams = init_params({init:1, action: 'list_dirs'});
+        root.reload();
+    });
+
+////////////////////////////////////////////////////////////////
+
+    function sel_option(item, check)
+    {
+       if (item.id == 'id_vosb') {
+          Ext.brestore.option_vosb = check;
+       }
+       if (item.id == 'id_vafv') {
+          Ext.brestore.option_vafv = check;
+       }
+    }
+
+    var menu = new Ext.menu.Menu({
+        id: 'div-main-menu',
+        items: [ 
+          new Ext.menu.CheckItem({
+               id: 'id_vosb',
+                text: 'View only selected backup',
+                checked: Ext.brestore.option_vosb,
+                checkHandler: sel_option
+            }),
+          new Ext.menu.CheckItem({
+               id: 'id_vafv',
+                text: 'View all file versions',
+                checked: Ext.brestore.option_vafv,
+                checkHandler: sel_option
+            })
+        ]
+    });
+////////////////////////////////////////////////////////////////:
+
+    // create the primary toolbar
+    var tb2 = new Ext.Toolbar('div-tb-sel');
+    tb2.add({
+        id:'save',
+        text:'Save',
+        disabled:true,
+//        handler:save,
+        cls:'x-btn-text-icon save',
+        tooltip:'Saves all components to the server'
+    },'-', {
+        id:'add',
+        text:'Component',
+//        handler:addComponent,
+        cls:'x-btn-text-icon add-cmp',
+        tooltip:'Add a new Component to the dependency builder'
+    }, {
+        id:'option',
+        text:'Option',
+        disabled:true,
+//        handler:addOption,
+        cls:'x-btn-text-icon add-opt',
+        tooltip:'Add a new optional dependency to the selected component'
+    },'-',{
+        id:'remove',
+        text:'Remove',
+        disabled:true,
+//        handler:removeNode,
+        cls:'x-btn-text-icon remove',
+        tooltip:'Remove the selected item'
+    });
+
+    var where_field = new Ext.form.TextField({
+            fieldLabel: 'Location',
+            name: 'where',
+            width:175,
+            allowBlank:false
+    });
+
+    var tb = new Ext.Toolbar('div-toolbar', [
+       client_combo,
+        job_combo,
+        '-',
+        {
+          id: 'tb_home',
+//        icon: '/bweb/up.gif',
+          text: 'Change location',
+          cls:'x-btn-text-icon',
+          handler: function() { 
+                var where = where_field.getValue();
+                Ext.brestore.root_path=where;
+                root.setText(where);
+                tree_loader.baseParams = init_params({ action:'list_dirs', path: where });
+                root.reload();
+          }
+        },
+        where_field,
+        '-',
+        {
+            cls: 'x-btn-text-icon bmenu', // icon and text class
+            text:'Options',
+            menu: menu  // assign menu by instance
+        },
+       {
+           icon: '/bweb/remove.png', // icons can also be specified inline
+            cls: 'x-btn-icon',
+           text: 'restore',
+           handler: function() { 
+               var dialog = new Ext.LayoutDialog("div-resto-dlg", { 
+//                        modal:true,
+                        width:600,
+                        height:400,
+                        shadow:true,
+                        minWidth:300,
+                        minHeight:300,
+                        proxyDrag: true,
+//                        west: {
+//                             split:true,
+//                             initialSize: 150,
+//                             minSize: 100,
+//                             maxSize: 250,
+//                             titlebar: true,
+//                             collapsible: true,
+//                             animate: true
+//                         },
+                       center: {
+                               autoScroll:true,
+//                             tabPosition: 'top',
+//                             closeOnTab: true,
+//                             alwaysShowTabs: true
+                       }
+                });
+                dialog.addKeyListener(27, dialog.hide, dialog);
+                dialog.addButton('Submit', dialog.hide, dialog);
+                dialog.addButton('Close', dialog.hide, dialog);
+
+    var fs = new Ext.form.Form({
+        labelAlign: 'right',
+        labelWidth: 80
+    });
+
+    fs.fieldset(
+        {legend:'Restore job'},
+        new Ext.form.ComboBox({
+            fieldLabel: 'Replace',
+            hiddenName:'replace',
+            store: new Ext.data.SimpleStore({
+                fields: ['replace'],
+                data : [['always'],['never'],['if newer']]
+           }),
+            displayField:'replace',
+            typeAhead: true,
+            mode: 'local',
+            triggerAction: 'all',
+            emptyText:'never',
+            selectOnFocus:true,
+            width:190
+        }),
+
+        new Ext.form.ComboBox({
+            fieldLabel: 'job',
+            hiddenName:'job',
+            store: client_store,
+            displayField:'name',
+            typeAhead: true,
+            mode: 'local',
+            triggerAction: 'all',
+            emptyText:'Select a job...',
+            selectOnFocus:true,
+            width:190
+        })
+//     ,
+//        new Ext.form.TextField({
+//            fieldLabel: 'Where',
+//            name: 'where',
+//            width:190
+//        }),
+//
+//        new Ext.form.ComboBox({
+//            fieldLabel: 'client',
+//            hiddenName:'client',
+//            store: client_store,
+//            displayField:'name',
+//            typeAhead: true,
+//            mode: 'local',
+//            triggerAction: 'all',
+//            emptyText:'Select a client...',
+//            selectOnFocus:true,
+//            width:190
+//        }),
+//        new Ext.form.ComboBox({
+//            fieldLabel: 'storage',
+//            hiddenName:'storage',
+//            store: client_store,
+//            displayField:'name',
+//            typeAhead: true,
+//            mode: 'local',
+//            triggerAction: 'all',
+//            emptyText:'Select a storage...',
+//            selectOnFocus:true,
+//            width:190
+//        })
+    );
+
+    fs.render('div-resto-form');
+
+//      var f = new Ext.form.BasicForm('div-resto-form', {url: '/bweb/test', method: 'GET',
+//                                                     baseParams: {init: 1}
+//                                                    }
+//                                     );
+
+               var layout = dialog.getLayout();
+                layout.beginUpdate();
+               layout.add('center', new Ext.ContentPanel('div-resto-form', {
+                                    autoCreate:true, title: 'Third Tab', closable:true, background:true}));
+               layout.endUpdate();
+               dialog.show();
+           }
+       }
+    ]);
+
+////////////////////////////////////////////////////////////////
+
+    var layout = new Ext.BorderLayout(document.body, {
+        north: {
+//            split: true
+        },
+        south: {
+            split: true, initialSize: 300
+        },
+        east: {
+            split: true, initialSize: 550
+        },
+        west: {
+            split: true, initialSize: 300
+        },
+        center: {
+            initialSize: 450
+        }        
+        
+    });
+
+layout.beginUpdate();
+  layout.add('north', new Ext.ContentPanel('div-toolbar', {
+      fitToFrame: true, autoCreate:true,closable: false 
+  }));
+  layout.add('south', new Ext.ContentPanel('div-file-selection', {
+      toolbar: tb2,resizeEl:'div-file-selection',
+      fitToFrame: true, autoCreate:true,closable: false
+  }));
+  layout.add('east', new Ext.ContentPanel('div-file-versions', {
+      fitToFrame: true, autoCreate:true,closable: false
+  }));
+  layout.add('west', new Ext.ContentPanel('div-tree', {
+      autoScroll:true, fitToFrame: true, 
+      autoCreate:true,closable: false
+  }));
+  layout.add('center', new Ext.ContentPanel('div-files', {
+      autoScroll:true,autoCreate:true,fitToFrame: true
+  }));
+layout.endUpdate();     
+
+
+////////////////////////////////////////////////////////////////
+
+//    job_store.load();
+    client_store.load({params:{action: 'list_client'}});
+//    file_store.load({params:{offset:0, limit:50}});
+//    file_versions_store.load({params:{offset:0, limit:50}});
+//    file_selection_store.load();
+
+}
+Ext.onReady( ext_init );
index c9c8f6194ae9dd0d0f21023b2c8bfcc999471a35..a476204a29706ccd64e8482ae2e7dba023a4a1d2 100644 (file)
@@ -55,7 +55,13 @@ if (navigator.appName == 'Konqueror') {
  </li>
 </TMPL_IF> 
  <li><a href="bweb.pl?action=graph"> Estadísticas </a></li>
- <li> <a href="bweb.pl?action=view_conf"> Configuración </a> </li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuración </a> 
+<TMPL_IF enable_security>
+  <ul> <li> <a href="bweb.pl?action=view_conf"> Configuration </a> 
+       <li> <a href="bweb.pl?action=users"> Manage users </a>
+  </ul>
+</TMPL_IF>
+</li>
  <li> <a href="bweb.pl?action=about"> Acerca </a> </li>
  <li style="padding: 0.25em 2em;float: right;">&nbsp;Usuario  <TMPL_VAR NAME=loginname> </li>
  <li style="float: right;white-space: nowrap;">
index 496c61ab06916439d3272b7120d2b681630b0677..58d3ae26590968847d6952448d58d39649495af0 100644 (file)
@@ -20,7 +20,7 @@ Estimado,
 
 Puede mover este medio a <TMPL_VAR newlocation>
 Medio :
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
  - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
 </TMPL_LOOP>
 
index 3c9b6900be99f072cf458419783a0183d150481e..fde3b6014976a024e19c516a62252503c9f05e2f 100644 (file)
      <tr><td>display_log_time :</td>
          <td> <input class="formulaire" title="display log timestamp" type='checkbox' name='display_log_time' <TMPL_IF display_log_time> checked='checked' value='on' </TMPL_IF> >
          </td></tr>
+     <tr><td>security :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security' title='Use user managment in bweb. Read INSTALL first' <TMPL_IF enable_security> checked='checked' value='on' </TMPL_IF> > 
+     <tr><td>security acl:</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security_acl' title='Use user acl in bweb. Read INSTALL first' <TMPL_IF enable_security_acl> checked='checked' value='on' </TMPL_IF> > 
      <tr><td>debug :</td> 
          <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
          </td></tr>
index 7380b743d857aa316516fba8eb9ca6d9394941f9..dffc499e0ed33a9c140fd3147f5cb5db803f2b9b 100644 (file)
@@ -18,6 +18,8 @@
     <tr><td title="You can choose the Job table that you want to use to get statistics">stat_job_table :</td> <td> <TMPL_IF stat_job_table><TMPL_VAR stat_job_table><TMPL_ELSE>Job</TMPL_IF> </td></tr>
     <tr><td title="/path/a/bconsole -n -c /path/to/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
     <tr><td title="display timestamp in job log">display_log_time :</td> <td> <TMPL_VAR display_log_time> </td></tr>
+    <tr><td>security :</td> <td> <TMPL_VAR enable_security> </td></tr>
+    <tr><td title="user filter">security acl :</td> <td> <TMPL_VAR enable_security_acl> </td></tr>
     <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
     <TMPL_IF achs>
     <tr>  <td><b>Libreria</b></td>  <td/></tr>
index ba62845fd3a4f17be344c31ff2bebd79bd7bb7c1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,65 +0,0 @@
-<br/>
- <div class='titlediv'>
-  <h1 class='newstitle'> Ã¼ltimos jobs de <TMPL_VAR clientname> (<TMPL_VAR Filter>)
-  </h1>
- </div>
- <div class='bodydiv'>
-
-   <table id='id<TMPL_VAR ID>'></table>
-
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
-    <img src="/bweb/chart.png" alt="backup size" title="backup size evolution"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
-    <img src="/bweb/chart.png" alt="backup duration" title="backup time evolution"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
-    <img src="/bweb/chart.png" alt="backup rate" title="backup rate evolution"/>
-    </a>                               
- </div>
-
-
-<script type="text/javascript" language="JavaScript">
-var header = new Array("IdJob", "Nombre Job", "File Set", "Nivel", "Tiempo Inicio", 
-                  "Archivos Job", "Bytes Job", "Errors");
-
-var data = new Array();
-
-<TMPL_LOOP Jobs>
-data.push( new Array(
-"<TMPL_VAR JobId>",
-"<TMPL_VAR JobName>",    
-"<TMPL_VAR FileSet>",
-"<TMPL_VAR Level>",
-"<TMPL_VAR StartTime>",
-"<TMPL_VAR JobFiles>",   
-human_size(<TMPL_VAR JobBytes>),
-"<TMPL_VAR JobErrors>"   
- )
-);
-</TMPL_LOOP>
-
-nrsTable.setup(
-{
- table_name:     "id<TMPL_VAR ID>",
- table_header: header,
- table_data: data,
- up_icon: up_icon,
- down_icon: down_icon,
- prev_icon: prev_icon,
- next_icon: next_icon,
- rew_icon:  rew_icon,
- fwd_icon:  fwd_icon,
-// natural_compare: true,
- even_cell_color: even_cell_color,
- odd_cell_color: odd_cell_color, 
- header_color: header_color,
- page_nav: true,
- rows_per_page: rows_per_page,
- disable_sorting: new Array(5,6)
-}
-);
-
-// get newest job first
-nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
-</script>
index 3839f5122dd50a52d4196a85a851664ef4480caa..46e7f4f57c5fe4f53ff72da623d9367d2daad259 100644 (file)
       <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
        class='formulaire' size='8'>
   </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Expired media</h2>
+    <input type='checkbox' name='expired' <TMPL_IF expired> checked </TMPL_IF> 
+       class='formulaire'>
+  </td>
 </tr>
  <tr>
   <td valign='bottom'> 
index b314ea95f06de32e26402df6158ab420072aba73..3f72329a96d10cc9bcc67577efb1dd7f75cb90db 100644 (file)
   </label>
  </form>
  </td>
+<TMPL_IF joberrors>
+ <td>
+    <a href="<TMPL_VAR thisurl>;error=1"
+         title="View only errors">
+    <img src='/bweb/doc.png' alt="view errors"></a> View only errors
+  </td>
+</TMPL_IF>
  </table>
 </div>
 
index f71f2098c915c245e39b8f4c922983237d8acb79..22164090c0d0c244455af027c165588d86eee5db 100644 (file)
@@ -6,4 +6,75 @@
   <pre id='log'>
 <TMPL_VAR lines>
   </pre>
+
+<a id='prev'><img border='0' src='/bweb/prev.png'></a>
+<a id='next'><img border='0' src='/bweb/next.png'></a>
  </div>
+<script type="text/javascript" language='JavaScript'>
+
+var url='<TMPL_VAR thisurl>';
+var urlprev=url;
+var urlnext=url;
+
+var reoff = new RegExp('offset=[0-9]+', "");
+var relim = new RegExp('limit=[0-9]+', "");
+
+var offset=0;
+var limit=1000;
+var nbline=0;
+<TMPL_IF offset>
+offset = <TMPL_VAR offset>;
+</TMPL_IF>
+<TMPL_IF limit>
+limit = <TMPL_VAR limit>;
+</TMPL_IF>
+<TMPL_IF nbline>
+nbline=<TMPL_VAR nbline>;
+</TMPL_IF>
+
+if (nbline == limit) {
+   var offset_next = offset + limit;
+   
+   if (url.match(reoff)) {
+       urlnext = urlnext.replace(reoff, 'offset=' + offset_next);
+   } else {
+       urlnext = urlnext + ';offset=' + offset_next;
+   }
+   
+   if (url.match(relim)) {
+       urlnext = urlnext.replace(relim, 'limit=' + limit);
+   } else {
+       urlnext = urlnext + ';limit=' + limit;
+   }
+   
+   document.getElementById('next').href = urlnext;
+
+} else {
+   document.getElementById('next').style.visibility="hidden";
+}
+
+if (offset > 0) {
+   var offset_prev = offset - limit;
+   if (offset_prev < 0) {
+        offset_prev=0;
+   }
+   if (url.match(reoff)) {
+       urlprev = urlprev.replace(reoff, 'offset=' + offset_prev);
+   } else {
+       urlprev = urlprev + ';offset=' + offset_prev ;
+   }
+   if (url.match(relim)) {
+       urlprev = urlprev.replace(relim, 'limit=' + limit);
+   } else {
+       urlprev = urlprev + ';limit=' + limit;
+   }
+
+   if (offset_prev >= 0) {
+       document.getElementById('prev').href = urlprev;
+   } else {
+       document.getElementById('prev').style.visibility="hidden";
+   }
+} else {
+   document.getElementById('prev').style.visibility="hidden";
+}   
+</script>
index f803c6e3b78551fe464e67cef2f73e2f77154fcc..b19014e58171482c3e622e61696be540cde8cade 100644 (file)
@@ -42,7 +42,7 @@ var img;
 var chkbox;
 var d;
 
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
 d = percent_usage(<TMPL_VAR volusage>);
 
 img = document.createElement('IMG');
index 6f7b564f4cf845bbe6f4a2984cf5febc9a489115..d9ef11eb4f257b7c088f58a84d1ff9f332855ab2 100644 (file)
@@ -40,7 +40,7 @@
 </table>
 <script type="text/javascript" language="JavaScript">
 
-var header = new Array("Pool","Online","Location","Vol Status", "Vol Bytes", "Expire",
+var header = new Array("Pool","Online","Enabled","Location","Vol Status", "Vol Bytes", "Expire",
                       "Retention","Max use duration", "Max jobs" );
 
 var data = new Array();
@@ -52,6 +52,7 @@ img.src = '/bweb/inflag<TMPL_VAR online>.png';
 data.push( new Array(
 "<TMPL_VAR poolname>",
 img,
+human_enabled("<TMPL_VAR enabled>"),
 "<TMPL_VAR location>",
 "<TMPL_VAR volstatus>",
 human_size(<TMPL_VAR nb_bytes>),
index ac1a3db8e49e11c6a08be6f36f626b25de77e377..2b94db3266a79804f883aa967662231f33016ff2 100644 (file)
@@ -24,7 +24,7 @@ var header = new Array("Nombre Volumen","Estado Volumen",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR NAME=volumename>';
index 8a8cd5c22dde4e22fb030c3df71d81aa16a28f12..c0731afb92e4a4b96d891e947482126375c5964a 100644 (file)
@@ -10,6 +10,7 @@
     <td style='align: left;'>
     <input type="image" onclick='javascript:window.history.go(-2);' title='Volver' src='/bweb/prev.png'>
     </td><td style='align: right;'>
+    <input type="hidden" name='enabled' value="yes">
     <input type="image" name='action' value='move_media' title='Cargar selección' src='/bweb/intern.png'>
    </td></tr>
    </form>
@@ -24,7 +25,7 @@ var header = new Array("Nombre Volumen","Estado Volumen",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.name = 'media';
index 797d766190a0703ae4aa1e4f52ebd3654cc18083..00c0bb99c935dec98494ab7f1564947d027614ae 100644 (file)
@@ -3,7 +3,7 @@
   <h1 class='newstitle'>Mover Medio</h1>
  </div>
  <div class="bodydiv">
-   <form action='?' method='get'>
+   <form name='form1' action='?' method='get'>
     <table id='id<TMPL_VAR NAME=ID>'></table>
     <table border='0'>
     <tr><td> Nueva Ubicación: </td><td>
     <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
     </TMPL_LOOP>
 </select>
-    </td></tr><tr><td> Estado: </td><td>
-<select name='volstatus' class='formulaire'>
-    <option value=''>No Actualizar</option>
-    <option value='Append'>Listo</option>
-    <option value='Archive'>Archivado</option>
-    <option value='Disabled'>Desactivado</option>
-    <option value='Cleaning'>Limpieza</option>
-    <option value='Error'>Error</option>
-    <option value='Full'>Lleno</option>
-    <option value='Purged'>Purgado</option>
-    <option value='Read-Only'>ectura</option>
-    <option value='Recycle'>Reciclado</option>
-    <option value='Used'>Usado</option>
+    </td></tr><tr><td> Enabled: </td><td>
+<select name='enabled' class='formulaire'>
+    <option value='no'>no</option>
+    <option value='yes'>yes</option>
+    <option value='archived'>archived</option>
 </select>
     </td><tr><td> Usuario: </td><td>
 <input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
@@ -46,7 +38,7 @@ var header = new Array("Nombre Volumen", "Ubicaci
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
@@ -82,4 +74,13 @@ nrsTable.setup(
  rows_per_page: rows_per_page
 }
 );
+<TMPL_IF enabled>
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
+</TMPL_IF>
 </script>
index 11b4335f2ac860d43fe491ea476c7b83a67b959b..5e54c0935c2d66ee5ece3323405461c77adfae06 100644 (file)
@@ -21,7 +21,7 @@ var header = new Array("Nombre del Volumen", "Ubicaci
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
index fd7af0f89e906eb41bf96e52a5aa0cec36d0dfe3..2ce07c7e621b9259ede13080067561c3ffc43ed4 100644 (file)
         </td>
     </tr>
 
+    <tr><td>Enabled:</td>
+        <td> <select name='enabled' class='formulaire'>
+           <option value='yes'>yes</option>
+           <option value='no'>no</option>
+           <option value='archived'>archived</option>
+           </select>
+        </td>
+    </tr>
+
     <tr><td> Ubicación : </td>
         <td><select name='location' class='formulaire'>
         <option value=''></option>
@@ -156,5 +165,12 @@ for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
       ok=0;
    }
 }
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
 
 </script>
index f5bdb53c52a1591a7e73d3615a9730df5fd6675e..27d2e603dfa6bb041be04fc274fa34bb6f380afa 100644 (file)
@@ -55,7 +55,13 @@ if (navigator.appName == 'Konqueror') {
  </li>
 </TMPL_IF> 
  <li><a href="bweb.pl?action=graph"> Statistiques </a></li>
- <li> <a href="bweb.pl?action=view_conf"> Configuration </a> </li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuration </a>
+<TMPL_IF enable_security>
+  <ul> <li> <a href="bweb.pl?action=view_conf"> Configuration </a> 
+       <li> <a href="bweb.pl?action=users"> Manage users </a>
+  </ul>
+</TMPL_IF>
+ </li>
  <li> <a href="bweb.pl?action=about"> A propos </a> </li>
  <li style="padding: 0.25em 2em;float: right;">&nbsp;Logged as <TMPL_VAR NAME=loginname> </li>
  <li style="float: right;white-space: nowrap;">
index 35029bc9c303ebe42277f5d86bf4be8386dd3f67..1f7c52937b8970f55abcb97e830f2dc8b11c9b76 100644 (file)
@@ -20,7 +20,7 @@ Bonjour,
 
 Pouvez vous déplacer ces médias vers <TMPL_VAR newlocation> ?
 Média :
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
  - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
 </TMPL_LOOP>
 
index 847c404059ad66ea4868737a867d066642c5b77a..98a562c88af5d60bf28220bf980327365ecb07ef 100644 (file)
      <tr><td>display_log_time :</td>
          <td> <input class="formulaire" title="affiche les heures dans les logs" type='checkbox' name='display_log_time' <TMPL_IF display_log_time> checked='checked' value='on' </TMPL_IF> >
          </td></tr>
+     <tr><td>security :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security' title='Active la gestion des utilisateurs dans bweb. Lire le manuel avant.' <TMPL_IF enable_security> checked='checked' value='on' </TMPL_IF> > 
+     <tr><td>security acl:</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security_acl' title='Use user acl in bweb. Read INSTALL first' <TMPL_IF enable_security_acl> checked='checked' value='on' </TMPL_IF> > 
      <tr><td>debug :</td> 
          <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
          </td></tr>
index c179d74b810a2a3abd09450987e46d21743b96aa..3ca01a2ab3456a468db0becbe5a7f9d3099b1c11 100644 (file)
@@ -18,6 +18,8 @@
     <tr><td title="Vous pouvez utiliser une autre table que Job pour vos statistiques">stat_job_table :</td> <td> <TMPL_IF stat_job_table><TMPL_VAR stat_job_table><TMPL_ELSE>Job</TMPL_IF> </td></tr>
     <tr><td title="/chemin/vers/bconsole -n -c /chemin/vers/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
     <tr><td title="affiche les heures dans le log des jobs">display_log_time :</td> <td> <TMPL_VAR display_log_time> </td></tr>
+    <tr><td>security :</td> <td> <TMPL_VAR enable_security> </td></tr>
+    <tr><td title="user filter">security acl :</td> <td> <TMPL_VAR enable_security_acl> </td></tr>
     <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
     <TMPL_IF achs>
     <tr>  <td><b>Robotique (Autochanger)</b></td>  <td/></tr>
index 0440f5546b459779d8f1a605e4292537e7725b15..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,65 +0,0 @@
-<br/>
- <div class='titlediv'>
-  <h1 class='newstitle'> Historique de <TMPL_VAR clientname> (<TMPL_VAR Filter>)
-  </h1>
- </div>
- <div class='bodydiv'>
-
-   <table id='id<TMPL_VAR ID>'></table>
-
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
-    <img src="/bweb/chart.png" alt="taille des sauvegardes" title="évolution de la taille des sauvegardes"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
-    <img src="/bweb/chart.png" alt="durée des sauvegardes" title="évolution de la durée des sauvegardes"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
-    <img src="/bweb/chart.png" alt="vitesse des sauvegardes" title="évolution de la vitesse des sauvegardes"/>
-    </a>                               
- </div>
-
-
-<script type="text/javascript" language="JavaScript">
-var header = new Array("JobId", "Nom du Job", "File Set", "Niveau", "Début", 
-                  "Nb fichiers", "Taille", "Erreurs");
-
-var data = new Array();
-
-<TMPL_LOOP Jobs>
-data.push( new Array(
-"<TMPL_VAR JobId>",
-"<TMPL_VAR JobName>",    
-"<TMPL_VAR FileSet>",
-"<TMPL_VAR Level>",
-"<TMPL_VAR StartTime>",
-"<TMPL_VAR JobFiles>",   
-human_size(<TMPL_VAR JobBytes>),
-"<TMPL_VAR JobErrors>"   
- )
-);
-</TMPL_LOOP>
-
-nrsTable.setup(
-{
- table_name:     "id<TMPL_VAR ID>",
- table_header: header,
- table_data: data,
- up_icon: up_icon,
- down_icon: down_icon,
- prev_icon: prev_icon,
- next_icon: next_icon,
- rew_icon:  rew_icon,
- fwd_icon:  fwd_icon,
-// natural_compare: true,
- even_cell_color: even_cell_color,
- odd_cell_color: odd_cell_color, 
- header_color: header_color,
- page_nav: true,
- rows_per_page: rows_per_page,
- disable_sorting: new Array(5,6)
-}
-);
-
-// get newest job first
-nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
-</script>
index 58619705a0213b988eb87c14fc42f37148b4295c..d5ab73c83ae1a27bac4323b77ce64347c911b51e 100644 (file)
       <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
        class='formulaire' size='8'>
   </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Médias expirés</h2>
+    <input type='checkbox' name='expired' <TMPL_IF expired> checked </TMPL_IF> 
+       class='formulaire'>
+  </td>
 </tr>
  <tr>
   <td valign='bottom'> 
index 9259ecdb6a7c2c240589b6e1f4cd9373bd5fbca6..a464fa1f5b184b66162c53917b0d7c28307fe097 100644 (file)
   </label>
  </form>
  </td>
+<TMPL_IF joberrors>
+ <td>
+    <a href="<TMPL_VAR thisurl>;error=1"
+         title="Voir seulement les erreurs">
+    <img src='/bweb/doc.png' alt="Voir les erreurs"></a> Voir les erreurs
+  </td>
+</TMPL_IF>
  </table>
 </div>
 
index d093f58a3858c2a32e5ad3fdb5e2ec96b6c3b563..d4ffea3f3e14d61f56366e345f24818737857a1c 100644 (file)
@@ -6,4 +6,75 @@
   <pre id='log'>
 <TMPL_VAR lines>
   </pre>
+
+<a id='prev'><img border='0' src='/bweb/prev.png'></a>
+<a id='next'><img border='0' src='/bweb/next.png'></a>
  </div>
+<script type="text/javascript" language='JavaScript'>
+
+var url='<TMPL_VAR thisurl>';
+var urlprev=url;
+var urlnext=url;
+
+var reoff = new RegExp('offset=[0-9]+', "");
+var relim = new RegExp('limit=[0-9]+', "");
+
+var offset=0;
+var limit=1000;
+var nbline=0;
+<TMPL_IF offset>
+offset = <TMPL_VAR offset>;
+</TMPL_IF>
+<TMPL_IF limit>
+limit = <TMPL_VAR limit>;
+</TMPL_IF>
+<TMPL_IF nbline>
+nbline=<TMPL_VAR nbline>;
+</TMPL_IF>
+
+if (nbline == limit) {
+   var offset_next = offset + limit;
+   
+   if (url.match(reoff)) {
+       urlnext = urlnext.replace(reoff, 'offset=' + offset_next);
+   } else {
+       urlnext = urlnext + ';offset=' + offset_next;
+   }
+   
+   if (url.match(relim)) {
+       urlnext = urlnext.replace(relim, 'limit=' + limit);
+   } else {
+       urlnext = urlnext + ';limit=' + limit;
+   }
+   
+   document.getElementById('next').href = urlnext;
+
+} else {
+   document.getElementById('next').style.visibility="hidden";
+}
+
+if (offset > 0) {
+   var offset_prev = offset - limit;
+   if (offset_prev < 0) {
+        offset_prev=0;
+   }
+   if (url.match(reoff)) {
+       urlprev = urlprev.replace(reoff, 'offset=' + offset_prev);
+   } else {
+       urlprev = urlprev + ';offset=' + offset_prev ;
+   }
+   if (url.match(relim)) {
+       urlprev = urlprev.replace(relim, 'limit=' + limit);
+   } else {
+       urlprev = urlprev + ';limit=' + limit;
+   }
+
+   if (offset_prev >= 0) {
+       document.getElementById('prev').href = urlprev;
+   } else {
+       document.getElementById('prev').style.visibility="hidden";
+   }
+} else {
+   document.getElementById('prev').style.visibility="hidden";
+}   
+</script>
index 9e4f8ec56a371bcb417ba3452a6f9516c2946048..b5e9eb257b2b56b9bb4d171d703ab80b89eba39e 100644 (file)
@@ -42,7 +42,7 @@ var img;
 var chkbox;
 var d;
 
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
 d = percent_usage(<TMPL_VAR volusage>);
 
 img = document.createElement('IMG');
index a73d7b3ba10f7fc2a056d6457b23abf2998507bf..7e392008bd4213d7e541cd4880e9850ee4e46378 100644 (file)
@@ -40,7 +40,7 @@
 </table>
 <script type="text/javascript" language="JavaScript">
 
-var header = new Array("Pool","En ligne","Localisation","Statut", "Taille", "Expiration",
+var header = new Array("Pool","En ligne","Enabled","Localisation","Statut", "Taille", "Expiration",
                       "Rétention","Temps maxi d'utilisation", "Nb de job maxi" );
 
 var data = new Array();
@@ -52,6 +52,7 @@ img.src = '/bweb/inflag<TMPL_VAR online>.png';
 data.push( new Array(
 "<TMPL_VAR poolname>",
 img,
+human_enabled("<TMPL_VAR enabled>"),
 "<TMPL_VAR location>",
 "<TMPL_VAR volstatus>",
 human_size(<TMPL_VAR nb_bytes>),
index 3322739b6f69e701d819180ed51b8933d13d08ff..23379d44c0c000ea7d050f7d65b04d82888cc291 100644 (file)
@@ -24,7 +24,7 @@ var header = new Array("Nom de volume","Statut",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR NAME=volumename>';
index b08a98356517473877808e7784f13b540abe9812..3db60ef71fcece681b821f743b6c47180c2d5795 100644 (file)
@@ -11,6 +11,7 @@
     <td style='align: left;'>
     <input type="image" onclick='javascript:window.history.go(-2);' title='Précédent' src='/bweb/prev.png'>
     </td><td style='align: right;'>
+    <input type="hidden" name='enabled' value="yes">
     <input type="image" name='action' value='move_media'
      src='/bweb/intern.png'>
    </td></tr>
@@ -26,7 +27,7 @@ var header = new Array("Nom de volume","Statut",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.name = 'media';
index baca0f4604664670cf9219a41549200870183868..25223a38abfcc425ec2b4d4d946f6ce4acc838a1 100644 (file)
@@ -3,7 +3,7 @@
   <h1 class='newstitle'>Déplacer un média</h1>
  </div>
  <div class="bodydiv">
-   <form action='?' method='get'>
+   <form name='form1' action='?' method='get'>
     <table id='id<TMPL_VAR NAME=ID>'></table>
     <table border='0'>
     <tr><td> Nouvelle localisation : </td><td>
     <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
     </TMPL_LOOP>
 </select>
-    </td></tr><tr><td> Statut : </td><td>
-<select name='volstatus' class='formulaire'>
-    <option value=''>Ne pas modifier</option>
-    <option value='Append'>Append</option>
-    <option value='Archive'>Archive</option>
-    <option value='Disabled'>Disabled</option>
-    <option value='Cleaning'>Cleaning</option>
-    <option value='Error'>Error</option>
-    <option value='Full'>Full</option>
-    <option value='Purged'>Purged</option>
-    <option value='Read-Only'>Read-Only</option>
-    <option value='Recycle'>Recycle</option>
-    <option value='Used'>Used</option>
+    </td></tr><tr><td> Enabled: </td><td>
+<select name='enabled' class='formulaire'>
+    <option value='no'>non</option>
+    <option value='yes'>oui</option>
+    <option value='archived'>archive</option>
 </select>
     </td><tr><td> Utilisateur : </td><td>
 <input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
@@ -46,7 +38,7 @@ var header = new Array("Nom de volume", "Localisation", "S
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
@@ -82,4 +74,14 @@ nrsTable.setup(
  rows_per_page: rows_per_page
 }
 );
+
+<TMPL_IF enabled>
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
+</TMPL_IF>
 </script>
index acc484ca38520bbb2ef33de0413fac434735ebf6..48ac5de29ac0e0b0e0db8772c2d289050a50adb2 100644 (file)
@@ -21,7 +21,7 @@ var header = new Array("Nom de volume", "Localisation", "S
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
index 4b4e5a13c78536843de1d7053981bb700a9ea8e6..211fc5fe577ba5e9069a1dae359030917fab4164 100644 (file)
         </td>
     </tr>
 
+    <tr><td>Enabled :</td>
+        <td> <select name='enabled' class='formulaire'>
+           <option value='yes'>oui</option>
+           <option value='no'>non</option>
+           <option value='archived'>archive</option>
+           </select>
+        </td>
+    </tr>
+
     <tr><td> Localisation : </td>
         <td><select name='location' class='formulaire'>
       <option value=''></option>
@@ -153,5 +162,12 @@ for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
       ok=0;
    }
 }
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
 
 </script>
index a264ada3fd29232b8be25de8a1373f9a4e266ec8..45ec5d4183c0ce8c5952a92985d0ad2643c7aea0 100644 (file)
@@ -370,9 +370,9 @@ sub _get_volume
 
 sub purge_volume
 {
-    my ($self, @volume) = @_;
+    my ($self, $volume) = @_;
 
-    my $sel = $self->_get_volume(@volume);
+    my $sel = $self->_get_volume($volume);
     my $ret;
     if ($sel) {
        $ret = $self->send_cmd("purge $sel");
@@ -384,9 +384,9 @@ sub purge_volume
 
 sub prune_volume
 {
-    my ($self, @volume) = @_;
+    my ($self, $volume) = @_;
 
-    my $sel = $self->_get_volume(@volume);
+    my $sel = $self->_get_volume($volume);
     my $ret;
     if ($sel) {
        $ret = $self->send_cmd("prune $sel yes");
index e73ae947513471f5c9414408a49a0780def642cc..3e29c344385f2b1d0162dd78b6ae93052454cd2a 100644 (file)
@@ -6,7 +6,7 @@ use strict;
    Bweb - A Bacula web interface
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
 
    The main author of Bweb is Eric Bollengier.
    The main author of Bacula is Kern Sibbald, with contributions from
@@ -217,6 +217,8 @@ our %k_re = ( dbi      => qr/^(dbi:(Pg|mysql):(?:\w+=[\w\d\.-]+;?)+)$/i,
              log_dir     => qr!^(.+)?$!,
              stat_job_table => qr!^(\w*)$!,
              display_log_time => qr!^(on)?$!,
+             enable_security => qr/^(on)?$/,
+             enable_security_acl => qr/^(on)?$/,
              );
 
 =head1 FUNCTION
@@ -345,7 +347,11 @@ sub modify
     my ($self) = @_;
     
     $self->{error} = '';
+    # we need to reset checkbox first
     $self->{debug} = 0;
+    $self->{display_log_time} = 0;
+    $self->{enable_security} = 0;
+    $self->{enable_security_acl} = 0;
 
     foreach my $k (CGI::param())
     {
@@ -1049,8 +1055,10 @@ our %sql_func = (
              STARTTIME_PHOUR=> " date_part('hour', Job.StartTime) ",
              STARTTIME_PDAY => " date_part('day', Job.StartTime) ",
              STARTTIME_PMONTH => " date_part('month', Job.StartTime) ",
+             STARTTIME_PWEEK => " date_part('week', Job.StartTime) ",
              DB_SIZE => " SELECT pg_database_size(current_database()) ",
              CAT_POOL_TYPE => " MediaType || '_' || Pool.Name ",
+             CONCAT_SEP => "",
          },
          mysql => {
              UNIX_TIMESTAMP => 'UNIX_TIMESTAMP',
@@ -1065,11 +1073,13 @@ our %sql_func = (
              STARTTIME_PHOUR=> " DATE_FORMAT(StartTime, '%H') ",
              STARTTIME_PDAY => " DATE_FORMAT(StartTime, '%d') ",
              STARTTIME_PMONTH => " DATE_FORMAT(StartTime, '%m') ",
+             STARTTIME_PWEEK => " DATE_FORMAT(StartTime, '%v') ",
              # with mysql < 5, you have to play with the ugly SHOW command
              DB_SIZE => " SELECT 0 ",
              # works only with mysql 5
              # DB_SIZE => " SELECT sum(DATA_LENGTH) FROM INFORMATION_SCHEMA.TABLES ",
              CAT_POOL_TYPE => " CONCAT(MediaType,'_',Pool.Name) ",
+             CONCAT_SEP => " SEPARATOR '' ",
          },
         );
 
@@ -1134,6 +1144,23 @@ sub dbh_selectrow_hashref
     return $self->{dbh}->selectrow_hashref($query) ;
 }
 
+sub dbh_strcat
+{
+    my ($self, @what) = @_;
+    if ($self->{conf}->{connection_string} =~ /dbi:mysql/i) {
+       return 'CONCAT(' . join(',', @what) . ')' ;
+    } else {
+       return join(' || ', @what);
+    }
+}
+
+sub dbh_prepare
+{
+    my ($self, $query) = @_;
+    $self->debug($query, up => 1);
+    return $self->{dbh}->prepare($query);    
+}
+
 # display Mb/Gb/Kb
 sub human_size
 {
@@ -1176,6 +1203,20 @@ sub human_sec
     return "$val years";   
 }
 
+# display Enabled
+sub human_enabled
+{
+    my $val = shift || 0;
+
+    if ($val == 1 or $val eq "yes") {
+       return "yes";
+    } elsif ($val == 2 or $val eq "archived") {
+       return "archived";
+    } else {
+       return  "no";
+    }
+}
+
 # get Day, Hour, Year
 sub from_human_sec
 {
@@ -1221,14 +1262,14 @@ sub connect_db
 sub new
 {
     my ($class, %arg) = @_;
-    my $self = bless { 
+    my $self = bless (
        dbh => undef,           # connect_db();
        info => {
            dbi   => '', # DBI:Pg:database=bacula;host=127.0.0.1
            user  => 'bacula',
            password => 'test', 
        },
-    } ;
+    },$class) ;
 
     map { $self->{lc($_)} = $arg{$_} } keys %arg ;
 
@@ -1236,6 +1277,7 @@ sub new
        $self->{sql} = $sql_func{$1};
     }
 
+    $self->{loginname} = CGI::remote_user();
     $self->{debug} = $self->{info}->{debug};
     $Bweb::Gui::template_dir = $self->{info}->{template_dir};
 
@@ -1257,18 +1299,21 @@ sub display_end
 sub display_clients
 {
     my ($self) = @_;
+    my $where='';      # by default
 
-    my $where='';
-    my $arg = $self->get_form("client", "qre_client", "jclient_groups", "qnotingroup");
+    my $arg = $self->get_form("client", "qre_client", 
+                             "jclient_groups", "qnotingroup");
 
     if ($arg->{qre_client}) {
        $where = "WHERE Name $self->{sql}->{MATCH} $arg->{qre_client} ";
     } elsif ($arg->{client}) {
        $where = "WHERE Name = '$arg->{client}' ";
     } elsif ($arg->{jclient_groups}) {
-       $where = "JOIN client_group_member ON (Client.ClientId = client_group_member.clientid) 
-                  JOIN client_group USING (client_group_id)
-                  WHERE client_group_name IN ($arg->{jclient_groups})";
+       # $filter could already contains client_group_member 
+       $where = "
+ JOIN client_group_member USING (ClientId) 
+ JOIN client_group USING (client_group_id)
+ WHERE client_group_name IN ($arg->{jclient_groups}) ";
     } elsif ($arg->{qnotingroup}) {
        $where =   "
   WHERE NOT EXISTS
@@ -1276,7 +1321,6 @@ sub display_clients
      WHERE Client.ClientId = client_group_member.ClientId
    )
 ";
-   
     }
 
     my $query = "
@@ -1285,9 +1329,8 @@ SELECT Name   AS name,
        AutoPrune AS autoprune,
        FileRetention AS fileretention,
        JobRetention  AS jobretention
-FROM Client
-$where
-";
+FROM Client " . $self->get_client_filter() .
+$where ;
 
     my $all = $self->dbh_selectall_hashref($query, 'name') ;
 
@@ -1409,7 +1452,11 @@ sub get_form
                  type   => 1,
                 poolrecycle => 1,
                 replace => 1,
-                );
+                expired => 1,
+                enabled => 1,
+                 username => 1,
+                 rolename => 1,
+                 );
     my %opt_p = (              # option with path
                 fileset=> 1,
                 mtxcmd => 1,
@@ -1489,9 +1536,15 @@ sub get_form
     }
 
     if ($what{db_clients}) {
+       my $filter='';
+       if ($what{filter}) {
+           # get security filter only if asked
+           $filter = $self->get_client_filter();
+       }
+
        my $query = "
 SELECT Client.Name as clientname
-  FROM Client
+  FROM Client $filter
 ";
 
        my $clients = $self->dbh_selectall_hashref($query, 'clientname');
@@ -1500,9 +1553,15 @@ SELECT Client.Name as clientname
     }
 
     if ($what{db_client_groups}) {
+       my $filter='';
+       if ($what{filter}) {
+           # get security filter only if asked
+           $filter = $self->get_client_group_filter();
+       }
+
        my $query = "
 SELECT client_group_name AS name 
-  FROM client_group
+  FROM client_group $filter
 ";
 
        my $grps = $self->dbh_selectall_hashref($query, 'name');
@@ -1510,15 +1569,37 @@ SELECT client_group_name AS name
                                  values %$grps] ;
     }
 
+    if ($what{db_usernames}) {
+       my $query = "
+SELECT username 
+  FROM bweb_user
+";
+
+       my $users = $self->dbh_selectall_hashref($query, 'username');
+       $ret{db_usernames} = [sort {$a->{username} cmp $b->{username} } 
+                                 values %$users] ;
+    }
+
+    if ($what{db_roles}) {
+       my $query = "
+SELECT rolename 
+  FROM bweb_role
+";
+
+       my $r = $self->dbh_selectall_hashref($query, 'rolename');
+       $ret{db_roles} = [sort {$a->{rolename} cmp $b->{rolename} } 
+                                 values %$r] ;
+    }
+
     if ($what{db_mediatypes}) {
        my $query = "
 SELECT MediaType as mediatype
   FROM MediaType
 ";
 
-       my $medias = $self->dbh_selectall_hashref($query, 'mediatype');
+       my $media = $self->dbh_selectall_hashref($query, 'mediatype');
        $ret{db_mediatypes} = [sort {$a->{mediatype} cmp $b->{mediatype} } 
-                                 values %$medias] ;
+                                 values %$media] ;
     }
 
     if ($what{db_locations}) {
@@ -1553,9 +1634,13 @@ SELECT FileSet.FileSet AS fileset
     }
 
     if ($what{db_jobnames}) {
+       my $filter='';
+       if ($what{filter}) {
+           $filter = " JOIN Client USING (ClientId) " . $self->get_client_filter();
+       }
        my $query = "
 SELECT DISTINCT Job.Name AS jobname 
-  FROM Job
+  FROM Job $filter
 ";
 
        my $jobnames = $self->dbh_selectall_hashref($query, 'jobname');
@@ -1584,8 +1669,8 @@ sub display_graph
     my ($self) = @_;
 
     my $fields = $self->get_form(qw/age level status clients filesets 
-                                    graph gtype type
-                                   db_clients limit db_filesets width height
+                                    graph gtype type filter db_clients
+                                   limit db_filesets width height
                                    qclients qfilesets qjobnames db_jobnames/);
                                
 
@@ -1604,57 +1689,20 @@ sub display_graph
 
 }
 
-sub display_client_job
-{
-    my ($self, %arg) = @_ ;
-
-    $arg{order} = ' Job.JobId DESC ';
-    my ($limit, $label) = $self->get_limit(%arg);
-
-    my $clientname = $self->dbh_quote($arg{clientname});
-
-    my $query="
-SELECT DISTINCT Job.JobId       AS jobid,
-               Job.Name        AS jobname,
-                FileSet.FileSet AS fileset,
-                Level           AS level,
-                StartTime       AS starttime,
-                JobFiles        AS jobfiles, 
-                JobBytes        AS jobbytes,
-                JobStatus       AS jobstatus,
-               JobErrors       AS joberrors
-
- FROM Client,Job,FileSet
- WHERE Client.Name=$clientname
- AND Client.ClientId=Job.ClientId
- AND Job.FileSetId=FileSet.FileSetId
- $limit
-";
-
-    my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
-
-    $self->display({ clientname => $arg{clientname},
-                    Filter => $label,
-                    ID => $cur_id++,
-                    Jobs => [ values %$all ],
-                  },
-                  "display_client_job.tpl") ;
-}
-
 sub get_selected_media_location
 {
     my ($self) = @_ ;
 
-    my $medias = $self->get_form('jmedias');
+    my $media = $self->get_form('jmedias');
 
-    unless ($medias->{jmedias}) {
+    unless ($media->{jmedias}) {
        return undef;
     }
 
     my $query = "
 SELECT Media.VolumeName AS volumename, Location.Location AS location
 FROM Media LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
-WHERE Media.VolumeName IN ($medias->{jmedias})
+WHERE Media.VolumeName IN ($media->{jmedias})
 ";
 
     my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
@@ -1668,20 +1716,21 @@ WHERE Media.VolumeName IN ($medias->{jmedias})
 
 sub move_media
 {
-    my ($self) = @_ ;
+    my ($self, $in) = @_ ;
 
-    my $medias = $self->get_selected_media_location();
+    my $media = $self->get_selected_media_location();
 
-    unless ($medias) {
+    unless ($media) {
        return ;
     }
-    
+
     my $elt = $self->get_form('db_locations');
 
     $self->display({ ID => $cur_id++,
+                    enabled => human_enabled($in),
                     %$elt,     # db_locations
-                    medias => [ 
-            sort { $a->{volumename} cmp $b->{volumename} } values %$medias
+                    media => [ 
+            sort { $a->{volumename} cmp $b->{volumename} } values %$media
                               ],
                     },
                   "move_media.tpl");
@@ -1733,7 +1782,7 @@ LIMIT $number
     
     my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
 
-    $self->display({ Medias => [ values %$all ] },
+    $self->display({ Media => [ values %$all ] },
                   "help_extern_compute.tpl");
 }
 
@@ -1789,7 +1838,7 @@ LIMIT $number
     
     my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
 
-    $self->display({ Medias => [ values %$all ] },
+    $self->display({ Media => [ values %$all ] },
                   "help_intern_compute.tpl");
 
 }
@@ -1861,10 +1910,10 @@ sub get_param
     }
 
     if ($elt{mediatypes}) {
-       my @medias = grep { ! /^\s*$/ } CGI::param('mediatype');
-       if (@medias) {
-           $ret{mediatypes} = \@medias;
-           my $str = $self->dbh_join(@medias);
+       my @media = grep { ! /^\s*$/ } CGI::param('mediatype');
+       if (@media) {
+           $ret{mediatypes} = \@media;
+           my $str = $self->dbh_join(@media);
            $limit .= "AND Media.MediaType IN ($str) ";
        }
     }
@@ -1971,6 +2020,7 @@ sub get_param
 sub display_job
 {
     my ($self, %arg) = @_ ;
+    $self->can_do('r_view_job');
 
     $arg{order} = ' Job.JobId DESC ';
 
@@ -1983,14 +2033,14 @@ sub display_job
                                          'pools',
                                          'jobid',
                                          'status');
-
-    my $cgq = '';
+    my $cgq='';
     if (CGI::param('client_group')) {
-       $cgq = "
-LEFT JOIN client_group_member ON (Job.ClientId = client_group_member.ClientId)
-LEFT JOIN client_group USING (client_group_id)
+       $cgq .= "
+JOIN client_group_member USING (ClientId)
+JOIN client_group USING (client_group_id)
 ";
     }
+    my $filter = $self->get_client_filter();
 
     my $query="
 SELECT  Job.JobId       AS jobid,
@@ -2010,10 +2060,9 @@ SELECT  Job.JobId       AS jobid,
 
         JobErrors      AS joberrors
 
- FROM Client, 
+ FROM Client $filter $cgq
       Job LEFT JOIN Pool     ON (Job.PoolId    = Pool.PoolId)
           LEFT JOIN FileSet  ON (Job.FileSetId = FileSet.FileSetId)
-          $cgq
  WHERE Client.ClientId=Job.ClientId
    AND Job.JobStatus NOT IN ('R', 'C')
  $where
@@ -2037,9 +2086,13 @@ SELECT  Job.JobId       AS jobid,
 sub display_job_zoom
 {
     my ($self, $jobid) = @_ ;
+    $self->can_do('r_view_job');
 
     $jobid = $self->dbh_quote($jobid);
-    
+
+    # get security filter
+    my $filter = $self->get_client_filter();
+
     my $query="
 SELECT DISTINCT Job.JobId       AS jobid,
                 Client.Name     AS client,
@@ -2055,7 +2108,7 @@ SELECT DISTINCT Job.JobId       AS jobid,
                 $self->{sql}->{SEC_TO_TIME}(  $self->{sql}->{UNIX_TIMESTAMP}(EndTime)  
                                             - $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) AS duration
 
- FROM Client,
+ FROM Client $filter,
       Job LEFT JOIN FileSet ON (Job.FileSetId = FileSet.FileSetId)
           LEFT JOIN Pool    ON (Job.PoolId    = Pool.PoolId)
  WHERE Client.ClientId=Job.ClientId
@@ -2083,13 +2136,14 @@ WHERE Job.JobId = $jobid
 sub display_job_group
 {
     my ($self, %arg) = @_;
+    $self->can_do('r_view_job');
 
     my ($limit, $label) = $self->get_limit(groupby => 'client_group_name',  %arg);
 
     my ($where, undef) = $self->get_param('client_groups',
                                          'level',
                                          'pools');
-    
+    my $filter = $self->get_client_group_filter();
     my $query = 
 "
 SELECT client_group_name AS client_group_name,
@@ -2100,7 +2154,7 @@ SELECT client_group_name AS client_group_name,
        COALESCE(joberr.nbjobs,0) AS nbjoberr,
        COALESCE(jobok.duration, '0:0:0') AS duration
 
-FROM client_group LEFT JOIN (
+FROM client_group $filter LEFT JOIN (
     SELECT client_group_name AS client_group_name, COUNT(1) AS nbjobs, 
            SUM(JobFiles) AS jobfiles, SUM(JobBytes) AS jobbytes, 
            SUM(JobErrors) AS joberrors,
@@ -2148,7 +2202,7 @@ sub display_media
                                         'volstatus',
                                         'locations');
 
-    my $arg = $self->get_form('jmedias', 'qre_media');
+    my $arg = $self->get_form('jmedias', 'qre_media', 'expired');
 
     if ($arg->{jmedias}) {
        $where = "AND Media.VolumeName IN ($arg->{jmedias}) $where"; 
@@ -2156,6 +2210,13 @@ sub display_media
     if ($arg->{qre_media}) {
        $where = "AND Media.VolumeName $self->{sql}->{MATCH} $arg->{qre_media} $where"; 
     }
+    if ($arg->{expired}) {
+       $where = " 
+        AND VolStatus = 'Full'
+        AND (    $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+               + $self->{sql}->{TO_SEC}(Media.VolRetention)
+            ) < NOW()  " . $where ;
+    }
 
     my $query="
 SELECT Media.VolumeName  AS volumename, 
@@ -2190,12 +2251,12 @@ $limit
     $self->display({ ID => $cur_id++,
                     Pool => $elt{pool},
                     Location => $elt{location},
-                    Medias => [ values %$all ]
+                    Media => [ values %$all ],
                   },
                   "display_media.tpl");
 }
 
-sub display_medias
+sub display_allmedia
 {
     my ($self) = @_ ;
 
@@ -2211,14 +2272,15 @@ sub display_media_zoom
 {
     my ($self) = @_ ;
 
-    my $medias = $self->get_form('jmedias');
+    my $media = $self->get_form('jmedias');
     
-    unless ($medias->{jmedias}) {
+    unless ($media->{jmedias}) {
        return $self->error("Can't get media selection");
     }
     
     my $query="
 SELECT InChanger     AS online,
+       Media.Enabled AS enabled,
        VolBytes      AS nb_bytes,
        VolumeName    AS volumename,
        VolStatus     AS volstatus,
@@ -2244,7 +2306,7 @@ SELECT InChanger     AS online,
  FROM Pool,
       Media LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
  WHERE Pool.PoolId = Media.PoolId
- AND VolumeName IN ($medias->{jmedias})
+ AND VolumeName IN ($media->{jmedias})
 ";
 
     my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
@@ -2294,6 +2356,7 @@ SELECT LocationLog.Date    AS date,
 sub location_edit
 {
     my ($self) = @_ ;
+    $self->can_do('r_location_mgnt');
 
     my $loc = $self->get_form('qlocation');
     unless ($loc->{qlocation}) {
@@ -2312,12 +2375,12 @@ WHERE Location.Location = $loc->{qlocation}
 
     $self->display({ ID => $cur_id++,
                     %$row }, "location_edit.tpl") ;
-
 }
 
 sub location_save
 {
     my ($self) = @_ ;
+    $self->can_do('r_location_mgnt');
 
     my $arg = $self->get_form(qw/qlocation qnewlocation cost/) ;
     unless ($arg->{qlocation}) {
@@ -2348,6 +2411,8 @@ WHERE Location.Location = $arg->{qlocation}
 sub location_del
 {
     my ($self) = @_ ;
+    $self->can_do('r_location_mgnt');
+
     my $arg = $self->get_form(qw/qlocation/) ;
 
     unless ($arg->{qlocation}) {
@@ -2375,10 +2440,11 @@ DELETE FROM Location WHERE Location = $arg->{qlocation} LIMIT 1
     $self->location_display();
 }
 
-
 sub location_add
 {
     my ($self) = @_ ;
+    $self->can_do('r_location_mgnt');
+
     my $arg = $self->get_form(qw/qlocation cost/) ;
 
     unless ($arg->{qlocation}) {
@@ -2428,8 +2494,8 @@ sub update_location
 {
     my ($self) = @_ ;
 
-    my $medias = $self->get_selected_media_location();
-    unless ($medias) {
+    my $media = $self->get_selected_media_location();
+    unless ($media) {
        return ;
     }
 
@@ -2437,7 +2503,7 @@ sub update_location
 
     $self->display({ email  => $self->{info}->{email_media},
                     %$arg,
-                     medias => [ values %$medias ],
+                     media => [ values %$media ],
                   },
                   "update_location.tpl");
 }
@@ -2447,9 +2513,9 @@ sub update_location
 sub groups_edit
 {
     my ($self) = @_;
+    $self->can_do('r_group_mgnt');
 
     my $grp = $self->get_form(qw/qclient_group db_clients/);
-    $self->debug($grp);
 
     unless ($grp->{qclient_group}) {
        return $self->error("Can't get group");
@@ -2474,6 +2540,7 @@ WHERE client_group_name = $grp->{qclient_group}
 sub groups_save
 {
     my ($self) = @_;
+    $self->can_do('r_group_mgnt');
 
     my $arg = $self->get_form(qw/qclient_group jclients qnewgroup/);
     unless ($arg->{qclient_group}) {
@@ -2520,6 +2587,8 @@ UPDATE client_group
 sub groups_del
 {
     my ($self) = @_;
+    $self->can_do('r_group_mgnt');
+
     my $arg = $self->get_form(qw/qclient_group/);
 
     unless ($arg->{qclient_group}) {
@@ -2535,6 +2604,12 @@ DELETE FROM client_group_member
               FROM client_group 
              WHERE client_group_name = $arg->{qclient_group});
 
+DELETE FROM bweb_client_group_acl
+      WHERE client_group_id IN
+           (SELECT client_group_id 
+              FROM client_group 
+             WHERE client_group_name = $arg->{qclient_group});
+
 DELETE FROM client_group
       WHERE client_group_name = $arg->{qclient_group};
 ";
@@ -2549,6 +2624,8 @@ DELETE FROM client_group
 sub groups_add
 {
     my ($self) = @_;
+    $self->can_do('r_group_mgnt');
+
     my $arg = $self->get_form(qw/qclient_group/) ;
 
     unless ($arg->{qclient_group}) {
@@ -2583,6 +2660,348 @@ sub display_groups
                   "display_groups.tpl");
 }
 
+###########################################################
+
+sub get_roles
+{
+    my ($self) = @_;
+    if (not $self->{info}->{enable_security}) {
+        return 1;
+    }
+    # admin is a special user that can do everything
+    if ($self->{loginname} eq 'admin') {
+        return 1;
+    }
+    if (!$self->{loginname}) {
+       return 0;
+    }
+    # already fill
+    if (defined $self->{security}) {
+       return 1;
+    }
+    $self->{security} = {};
+    my $u = $self->dbh_quote($self->{loginname});
+           
+    my $query = "
+ SELECT use_acl, rolename
+  FROM bweb_user 
+       JOIN bweb_role_member USING (userid)
+       JOIN bweb_role USING (roleid)
+ WHERE username = $u
+";
+    my $rows = $self->dbh_selectall_arrayref($query);
+    # do cache with this role   
+    if (!$rows) {
+        return 0;
+    }
+    foreach my $r (@$rows) {
+       $self->{security}->{$r->[1]}=1;
+    }
+
+    $self->{security}->{use_acl} = $rows->[0]->[0];
+    return 1;
+}
+
+# TODO: avoir un mode qui coupe le programme avec une page d'erreur
+# we can also get all security and fill {security} hash
+sub can_do
+{
+    my ($self, $action) = @_;
+    # is security enabled in configuration ?
+    if (not $self->{info}->{enable_security}) {
+        return 1;
+    }
+    # admin is a special user that can do everything
+    if ($self->{loginname} eq 'admin') {
+        return 1;
+    }
+    # must be logged
+    if (!$self->{loginname}) {
+        $self->error("Can't do $action, your are not logged. " .
+                     "Check security with your administrator");
+        $self->display_end();
+        exit (0);
+    }
+    $self->get_roles();
+    if (!$self->{security}->{$action}) {
+        $self->error("$self->{loginname} sorry, but this action ($action) " .
+                    "is not permited. " .
+                     "Check security with your administrator");
+        $self->display_end();
+        exit (0);
+    }
+    return 1;
+}
+
+sub use_filter
+{
+    my ($self) = @_;
+
+    if (!$self->{info}->{enable_security} or 
+       !$self->{info}->{enable_security_acl})
+    {
+       return 0 ;
+    }
+    
+    if ($self->get_roles()) {
+       return $self->{security}->{use_acl};
+    } else {
+       return 0;
+    }
+}
+
+# JOIN Client USING (ClientId) " . $b->get_client_filter() . "
+sub get_client_filter
+{
+    my ($self) = @_;
+    if ($self->use_filter()) {
+       my $u = $self->dbh_quote($self->{loginname});
+       return "
+ JOIN (SELECT ClientId FROM client_group_member
+   JOIN client_group USING (client_group_id) 
+   JOIN bweb_client_group_acl USING (client_group_id) 
+   JOIN bweb_user USING (userid)
+   WHERE bweb_user.username = $u 
+ ) AS filter USING (ClientId)";
+    } else {
+       return '';
+    }
+}
+
+#JOIN client_group USING (client_group_id)" . $b->get_client_group_filter()
+sub get_client_group_filter
+{
+    my ($self) = @_;
+    if ($self->use_filter()) {
+       my $u = $self->dbh_quote($self->{loginname});
+       return "
+ JOIN (SELECT client_group_id 
+         FROM bweb_client_group_acl
+         JOIN bweb_user USING (userid)
+   WHERE bweb_user.username = $u 
+ ) AS filter USING (client_group_id)";
+    } else {
+       return '';
+    }
+}
+
+# role and username have to be quoted before
+# role and username can be a quoted list
+sub revoke
+{
+    my ($self, $role, $username) = @_;
+    $self->can_do("r_user_mgnt");
+    
+    my $nb = $self->dbh_do("
+ DELETE FROM bweb_role_member 
+       WHERE roleid = (SELECT roleid FROM bweb_role
+                        WHERE rolename IN ($role))
+         AND userid = (SELECT userid FROM bweb_user
+                        WHERE username IN ($username))");
+    return $nb;
+}
+
+# role and username have to be quoted before
+# role and username can be a quoted list
+sub grant
+{
+    my ($self, $role, $username) = @_;
+    $self->can_do("r_user_mgnt");
+
+    my $nb = $self->dbh_do("
+   INSERT INTO bweb_role_member (roleid, userid)
+     SELECT roleid, userid FROM bweb_role, bweb_user 
+      WHERE rolename IN ($role)
+        AND username IN ($username)
+     ");
+    return $nb;
+}
+
+# role and username have to be quoted before
+# role and username can be a quoted list
+sub grant_like
+{
+    my ($self, $copy, $user) = @_;
+    $self->can_do("r_user_mgnt");
+
+    my $nb = $self->dbh_do("
+  INSERT INTO bweb_role_member (roleid, userid) 
+   SELECT roleid, a.userid 
+     FROM bweb_user AS a, bweb_role_member 
+     JOIN bweb_user USING (userid)
+    WHERE bweb_user.username = $copy
+      AND a.username = $user");
+    return $nb;
+}
+
+# username can be a join quoted list of usernames
+sub revoke_all
+{
+    my ($self, $username) = @_;
+    $self->can_do("r_user_mgnt");
+
+    $self->dbh_do("
+   DELETE FROM bweb_role_member
+         WHERE userid IN (
+           SELECT userid 
+             FROM bweb_user 
+            WHERE username in ($username))");
+    $self->dbh_do("
+DELETE FROM bweb_client_group_acl 
+ WHERE userid IN (
+  SELECT userid 
+    FROM bweb_user 
+   WHERE username IN ($username))");
+    
+}
+
+sub users_del
+{
+    my ($self) = @_;
+    $self->can_do("r_user_mgnt");
+
+    my $arg = $self->get_form(qw/jusernames/);
+
+    unless ($arg->{jusernames}) {
+        return $self->error("Can't get user");
+    }
+
+    $self->{dbh}->begin_work();
+    {
+        $self->revoke_all($arg->{jusernames});
+        $self->dbh_do("
+DELETE FROM bweb_user WHERE username IN ($arg->{jusernames})");
+    }
+    $self->{dbh}->commit();
+    
+    $self->display_users();
+}
+
+sub users_add
+{
+    my ($self) = @_;
+    $self->can_do("r_user_mgnt");
+
+    # we don't quote username directly to check that it is conform
+    my $arg = $self->get_form(qw/username qpasswd qcomment jrolenames qcreate qcopy_username jclient_groups/) ;
+
+    if (not $arg->{qcreate}) {
+        $arg = $self->get_form(qw/db_roles db_usernames db_client_groups/);
+        $self->display($arg, "display_user.tpl");
+        return 1;
+    }
+
+    my $u = $self->dbh_quote($arg->{username});
+    
+    $arg->{use_acl}=(CGI::param('use_acl')?'true':'false');
+
+    if (!$arg->{qpasswd}) {
+        $arg->{qpasswd} = "''";
+    }
+    if (!$arg->{qcomment}) {
+        $arg->{qcomment} = "''";
+    }
+
+    # will fail if user already exists
+    $self->dbh_do("
+  UPDATE bweb_user 
+     SET passwd=$arg->{qpasswd}, comment=$arg->{qcomment}, 
+         use_acl=$arg->{use_acl}
+   WHERE username = $u")
+        or
+    $self->dbh_do("
+  INSERT INTO bweb_user (username, passwd, use_acl, comment) 
+        VALUES ($u, $arg->{qpasswd}, $arg->{use_acl}, $arg->{qcomment})");
+
+    $self->{dbh}->begin_work();
+    {
+        $self->revoke_all($u);
+
+        if ($arg->{qcopy_username}) {
+            $self->grant_like($arg->{qcopy_username}, $u);
+        } else {
+            $self->grant($arg->{jrolenames}, $u);
+        }
+
+       $self->dbh_do("
+INSERT INTO bweb_client_group_acl (client_group_id, userid)
+ SELECT client_group_id, userid 
+   FROM client_group, bweb_user
+  WHERE client_group_name IN ($arg->{jclient_groups})
+    AND username = $u
+");
+
+    }
+    $self->{dbh}->commit();
+
+    $self->display_users();
+}
+
+# TODO: we miss a matrix with all user/roles
+sub display_users
+{
+    my ($self) = @_;
+    $self->can_do("r_user_mgnt");
+
+    my $arg = $self->get_form(qw/db_usernames/) ;
+
+    if ($self->{dbh}->errstr) {
+        return $self->error("Can't use users with bweb, read INSTALL to enable them");
+    }
+
+    $self->display({ ID => $cur_id++,
+                     %$arg},
+                   "display_users.tpl");
+}
+
+sub display_user
+{
+    my ($self) = @_;
+    $self->can_do("r_user_mgnt");
+
+    my $arg = $self->get_form('username');
+    my $user = $self->dbh_quote($arg->{username});
+
+    my $userp = $self->dbh_selectrow_hashref("
+   SELECT username, passwd, comment, use_acl
+     FROM bweb_user
+    WHERE username = $user
+");
+
+    if (!$userp) {
+        return $self->error("Can't find $user in catalog");
+    }
+    $arg = $self->get_form(qw/db_usernames db_client_groups/);
+    my $arg2 = $self->get_form(qw/filter db_client_groups/);
+
+#  rolename  | userid
+#------------+--------
+# cancel_job |
+# restore    |
+# run_job    |      1
+
+    my $role = $self->dbh_selectall_hashref("
+SELECT rolename, temp.userid
+     FROM bweb_role
+     LEFT JOIN (SELECT roleid, userid
+                  FROM bweb_user JOIN bweb_role_member USING (userid)
+                 WHERE username = $user) AS temp USING (roleid)
+ORDER BY rolename
+", 'rolename');
+
+    $self->display({
+        db_usernames => $arg->{db_usernames},
+        username => $userp->{username},
+        comment => $userp->{comment},
+        passwd => $userp->{passwd},
+       use_acl => $userp->{use_acl},
+       db_client_groups => $arg->{db_client_groups},
+       client_group => $arg2->{db_client_groups},
+        db_roles => [ values %$role], 
+    }, "display_user.tpl");
+}
+
+
 ###########################################################
 
 sub get_media_max_size
@@ -2627,7 +3046,8 @@ SELECT Media.Slot         AS slot,
        Media.VolUseDuration AS voluseduration,
        Media.VolRetention AS volretention,
        Media.Comment      AS comment,
-       PoolRecycle.Name   AS poolrecycle
+       PoolRecycle.Name   AS poolrecycle,
+       Media.Enabled      AS enabled
 
 FROM Media INNER JOIN Pool AS PoolMedia ON (Media.PoolId = PoolMedia.PoolId)
            LEFT  JOIN Pool AS PoolRecycle ON (Media.RecyclePoolId = PoolRecycle.PoolId)
@@ -2639,6 +3059,7 @@ WHERE Media.VolumeName = $media->{qmedia}
     my $row = $self->dbh_selectrow_hashref($query);
     $row->{volretention} = human_sec($row->{volretention});
     $row->{voluseduration} = human_sec($row->{voluseduration});
+    $row->{enabled} = human_enabled($row->{enabled});
 
     my $elt = $self->get_form(qw/db_pools db_locations/);
 
@@ -2651,6 +3072,7 @@ WHERE Media.VolumeName = $media->{qmedia}
 sub save_location
 {
     my ($self) = @_ ;
+    $self->can_do('r_media_mgnt');
 
     my $arg = $self->get_form('jmedias', 'qnewlocation') ;
 
@@ -2680,9 +3102,10 @@ sub save_location
 sub location_change
 {
     my ($self) = @_ ;
+    $self->can_do('r_media_mgnt');
 
-    my $medias = $self->get_selected_media_location();
-    unless ($medias) {
+    my $media = $self->get_selected_media_location();
+    unless ($media) {
        return $self->error("Can't get media selection");
     }
     my $newloc = CGI::param('newlocation');
@@ -2691,20 +3114,25 @@ sub location_change
     my $comm = CGI::param('comment') || '';
     $comm = $self->dbh_quote("$user: $comm");
 
-    my $query;
+    my $arg = $self->get_form('enabled');
+    my $en = human_enabled($arg->{enabled});
+    my $b = $self->get_bconsole();
 
-    foreach my $media (keys %$medias) {
+    my $query;
+    foreach my $vol (keys %$media) {
        $query = "
 INSERT LocationLog (Date, Comment, MediaId, LocationId, NewVolStatus)
  VALUES(
-       NOW(), $comm, (SELECT MediaId FROM Media WHERE VolumeName = '$media'),
-       (SELECT LocationId FROM Location WHERE Location = '$medias->{$media}->{location}'),
-       (SELECT VolStatus FROM Media WHERE VolumeName = '$media')
+       NOW(), $comm, (SELECT MediaId FROM Media WHERE VolumeName = '$vol'),
+       (SELECT LocationId FROM Location WHERE Location = '$media->{$vol}->{location}'),
+       (SELECT VolStatus FROM Media WHERE VolumeName = '$vol')
       )
 ";
        $self->dbh_do($query);
        $self->debug($query);
+       $b->send_cmd("update volume=\"$vol\" enabled=$en");
     }
+    $b->close();
 
     my $q = new CGI;
     $q->param('action', 'update_location');
@@ -2713,8 +3141,8 @@ INSERT LocationLog (Date, Comment, MediaId, LocationId, NewVolStatus)
     $self->display({ email  => $self->{info}->{email_media},
                     url => $url,
                     newlocation => $newloc,
-                    # [ { volumename => 'vol1' }, { volumename => 'vol2'\81\81 },..]
-                    medias => [ values %$medias ],
+                    # [ { volumename => 'vol1' }, { volumename => 'vol2'},..]
+                    media => [ values %$media ],
                   },
                   "change_location.tpl");
 
@@ -2723,11 +3151,13 @@ INSERT LocationLog (Date, Comment, MediaId, LocationId, NewVolStatus)
 sub display_client_stats
 {
     my ($self, %arg) = @_ ;
+    $self->can_do('r_view_stats');
 
     my $client = $self->dbh_quote($arg{clientname});
+    # get security filter
+    my $filter = $self->get_client_filter();
 
     my ($limit, $label) = $self->get_limit(%arg);
-
     my $query = "
 SELECT 
     count(Job.JobId)     AS nb_jobs,
@@ -2735,7 +3165,7 @@ SELECT
     sum(Job.JobErrors)   AS nb_err,
     sum(Job.JobFiles)    AS nb_files,
     Client.Name          AS clientname
-FROM Job JOIN Client USING (ClientId)
+FROM Job JOIN Client USING (ClientId) $filter
 WHERE 
     Client.Name = $client
     $limit 
@@ -2885,14 +3315,17 @@ GROUP BY VolStatus
 sub display_running_job
 {
     my ($self) = @_;
+    $self->can_do('r_view_running_job');
 
     my $arg = $self->get_form('client', 'jobid');
 
     if (!$arg->{client} and $arg->{jobid}) {
+       # get security filter
+       my $filter = $self->get_client_filter();
 
        my $query = "
 SELECT Client.Name AS name
-FROM Job INNER JOIN Client USING (ClientId)
+FROM Job INNER JOIN Client USING (ClientId) $filter
 WHERE Job.JobId = $arg->{jobid}
 ";
 
@@ -2918,7 +3351,11 @@ WHERE Job.JobId = $arg->{jobid}
 sub display_running_jobs
 {
     my ($self, $display_action) = @_;
-    
+    $self->can_do('r_view_running_job');
+
+    # get security filter
+    my $filter = $self->get_client_filter();
+
     my $query = "
 SELECT Job.JobId AS jobid, 
        Job.Name  AS jobname,
@@ -2931,8 +3368,9 @@ $self->{sql}->{SEC_TO_TIME}(  $self->{sql}->{UNIX_TIMESTAMP}(NOW())
                             - $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
          AS duration,
        Client.Name AS clientname
-FROM Job INNER JOIN Client USING (ClientId) 
-WHERE JobStatus IN ('C','R','B','e','D','F','S','m','M','s','j','c','d','t','p')
+FROM Job INNER JOIN Client USING (ClientId) $filter
+WHERE 
+  JobStatus IN ('C','R','B','e','D','F','S','m','M','s','j','c','d','t','p')
 ";     
     my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
     
@@ -2946,6 +3384,8 @@ WHERE JobStatus IN ('C','R','B','e','D','F','S','m','M','s','j','c','d','t','p')
 sub eject_media
 {
     my ($self) = @_;
+    $self->can_do('r_media_mgnt');
+
     my %ret; 
     my $arg = $self->get_form('jmedias');
 
@@ -2975,7 +3415,7 @@ WHERE Media.VolumeName IN ($arg->{jmedias})
            $a->status();
            $a->{have_status} = 1;
        }
-
+       # TODO: set enabled
        print "eject $vol->{volumename} from $vol->{storage} : ";
        if ($a->send_to_io($vol->{slot})) {
            print "<img src='/bweb/T.png' alt='ok'><br/>";
@@ -3049,6 +3489,7 @@ sub ach_get
 sub ach_register
 {
     my ($self, $ach) = @_;
+    $self->can_do('r_configure');
 
     $self->{info}->{ach_list}->{$ach->{name}} = $ach;
 
@@ -3060,6 +3501,8 @@ sub ach_register
 sub ach_edit
 {
     my ($self) = @_;
+    $self->can_do('r_configure');
+
     my $arg = $self->get_form('ach');
     if (!$arg->{ach} 
        or !$self->{info}->{ach_list} 
@@ -3089,6 +3532,8 @@ sub ach_edit
 sub ach_del
 {
     my ($self) = @_;
+    $self->can_do('r_configure');
+
     my $arg = $self->get_form('ach');
 
     if (!$arg->{ach} 
@@ -3107,6 +3552,8 @@ sub ach_del
 sub ach_add
 {
     my ($self) = @_;
+    $self->can_do('r_configure');
+
     my $arg = $self->get_form('ach', 'mtxcmd', 'device', 'precmd');
 
     my $b = $self->get_bconsole();
@@ -3150,6 +3597,8 @@ sub ach_add
 sub delete
 {
     my ($self) = @_;
+    $self->can_do('r_delete_job');
+
     my $arg = $self->get_form('jobid');
 
     if ($arg->{jobid}) {
@@ -3167,11 +3616,12 @@ sub delete
 sub do_update_media
 {
     my ($self) = @_ ;
+    $self->can_do('r_media_mgnt');
 
     my $arg = $self->get_form(qw/media volstatus inchanger pool
                                 slot volretention voluseduration 
                                 maxvoljobs maxvolfiles maxvolbytes
-                                qcomment poolrecycle
+                                qcomment poolrecycle enabled
                              /);
 
     unless ($arg->{media}) {
@@ -3193,6 +3643,10 @@ sub do_update_media
        $update .= " slot=0 inchanger=no ";
     }
 
+    if ($arg->{enabled}) {
+        $update .= " enabled=$arg->{enabled} ";
+    }
+
     if ($arg->{pool}) {
        $update .= " pool=$arg->{pool} " ;
     }
@@ -3257,6 +3711,7 @@ UPDATE Media
 sub update_slots
 {
     my ($self) = @_;
+    $self->can_do('r_autochanger_mgnt');
 
     my $ach = CGI::param('ach') ;
     $ach = $self->ach_get($ach);
@@ -3273,6 +3728,7 @@ sub update_slots
 sub get_job_log
 {
     my ($self) = @_;
+    $self->can_do('r_view_log');
 
     my $arg = $self->get_form('jobid', 'limit', 'offset');
     unless ($arg->{jobid}) {
@@ -3282,12 +3738,12 @@ sub get_job_log
     if ($arg->{limit} == 100) {
         $arg->{limit} = 1000;
     }
-
-    my $t = CGI::param('time') || $self->{info}->{display_log_time} || '';
+    # get security filter
+    my $filter = $self->get_client_filter();
 
     my $query = "
 SELECT Job.Name as name, Client.Name as clientname
- FROM  Job INNER JOIN Client ON (Job.ClientId = Client.ClientId)
+ FROM  Job INNER JOIN Client USING (ClientId) $filter
  WHERE JobId = $arg->{jobid}
 ";
 
@@ -3297,32 +3753,45 @@ SELECT Job.Name as name, Client.Name as clientname
        return $self->error("Can't find $arg->{jobid} in catalog");
     }
 
+    # display only Error and Warning messages
+    $filter = '';
+    if (CGI::param('error')) {
+       $filter = " AND LogText $self->{sql}->{MATCH} 'Error|Warning' ";
+    }
+
+    my $logtext;
+    if (CGI::param('time') || $self->{info}->{display_log_time}) {
+       $logtext = 'LogText';
+    } else {
+       $logtext = $self->dbh_strcat('Time', ' ', 'LogText')
+    }
+
     $query = "
-SELECT Time AS time, LogText AS log 
-  FROM  Log 
- WHERE Log.JobId = $arg->{jobid} 
-    OR (Log.JobId = 0 AND Time >= (SELECT StartTime FROM Job WHERE JobId=$arg->{jobid}) 
-                      AND Time <= (SELECT COALESCE(EndTime,NOW()) FROM Job WHERE JobId=$arg->{jobid})
-       )
+SELECT count(1) AS nbline, JobId AS jobid, 
+       GROUP_CONCAT($logtext $self->{sql}->{CONCAT_SEP}) AS logtxt
+  FROM  (
+    SELECT JobId, Time, LogText
+    FROM Log 
+   WHERE ( Log.JobId = $arg->{jobid} 
+      OR (Log.JobId = 0 
+          AND Time >= (SELECT StartTime FROM Job WHERE JobId=$arg->{jobid}) 
+          AND Time <= (SELECT COALESCE(EndTime,NOW()) FROM Job WHERE JobId=$arg->{jobid})
+       ) ) $filter
  ORDER BY LogId
  LIMIT $arg->{limit}
  OFFSET $arg->{offset}
+ ) AS temp
+ GROUP BY JobId
+
 ";
 
-    my $log = $self->dbh_selectall_arrayref($query);
+    my $log = $self->dbh_selectrow_hashref($query);
     unless ($log) {
        return $self->error("Can't get log for jobid $arg->{jobid}");
     }
 
-    my $logtxt;
-    if ($t) {
-       # log contains \n
-       $logtxt = join("", map { ($_->[0] . ' ' . $_->[1]) } @$log ) ; 
-    } else {
-       $logtxt = join("", map { $_->[1] } @$log ) ; 
-    }
-    
-    $self->display({ lines=> $logtxt,
+    $self->display({ lines=> $log->{logtxt},
+                    nbline => $log->{nbline},
                     jobid => $arg->{jobid},
                     name  => $row->{name},
                     client => $row->{clientname},
@@ -3331,10 +3800,10 @@ SELECT Time AS time, LogText AS log
                 }, 'display_log.tpl');
 }
 
-
 sub label_barcodes
 {
     my ($self) = @_ ;
+    $self->can_do('r_autochanger_mgnt');
 
     my $arg = $self->get_form('ach', 'slots', 'drive');
 
@@ -3386,6 +3855,7 @@ sub label_barcodes
 sub purge
 {
     my ($self) = @_;
+    $self->can_do('r_purge');
 
     my @volume = CGI::param('media');
 
@@ -3395,17 +3865,20 @@ sub purge
 
     my $b = new Bconsole(pref => $self->{info}, timeout => 60);
 
-    $self->display({
-       content => $b->purge_volume(@volume),
-       title => "Purge media",
-       name => "purge volume=" . join(' volume=', @volume),
-    }, "command.tpl"); 
+    foreach my $v (@volume) {
+       $self->display({
+           content => $b->purge_volume($v),
+           title => "Purge media",
+           name => "purge volume=$v",
+       }, "command.tpl");
+    }  
     $b->close();
 }
 
 sub prune
 {
     my ($self) = @_;
+    $self->can_do('r_prune');
 
     my @volume = CGI::param('media');
     unless (@volume) {
@@ -3414,18 +3887,20 @@ sub prune
 
     my $b = new Bconsole(pref => $self->{info}, timeout => 60);
 
-    $self->display({
-       content => $b->prune_volume(@volume),
-       title => "Prune media",
-       name => "prune volume=" . join(' volume=', @volume),
-    }, "command.tpl"); 
-
+    foreach my $v (@volume) {
+       $self->display({
+           content => $b->prune_volume($v),
+           title => "Prune volume",
+           name => "prune volume=$v",
+       }, "command.tpl");
+    }
     $b->close();
 }
 
 sub cancel_job
 {
     my ($self) = @_;
+    $self->can_do('r_cancel_job');
 
     my $arg = $self->get_form('jobid');
     unless ($arg->{jobid}) {
@@ -3476,6 +3951,7 @@ sub director_show_sched
 sub enable_disable_job
 {
     my ($self, $what) = @_ ;
+    $self->can_do('r_run_job');
 
     my $name = CGI::param('job') || '';
     unless ($name =~ /^[\w\d\.\-\s]+$/) {
@@ -3507,6 +3983,8 @@ sub get_bconsole
 sub run_job_select
 {
     my ($self) = @_;
+    $self->can_do('r_run_job');
+
     my $b = $self->get_bconsole();
 
     my $joblist = [ map { { name => $_ } } $b->list_job() ];
@@ -3542,6 +4020,8 @@ sub run_parse_job
 sub run_job_mod
 {
     my ($self) = @_;
+    $self->can_do('r_run_job');
+
     my $b = $self->get_bconsole();
     
     my $job = CGI::param('job') || '';
@@ -3573,6 +4053,8 @@ sub run_job_mod
 sub run_job
 {
     my ($self) = @_;
+    $self->can_do('r_run_job');
+
     my $b = $self->get_bconsole();
     
     my $jobs   = [ map {{ name => $_ }} $b->list_job() ];
@@ -3585,6 +4067,8 @@ sub run_job
 sub run_job_now
 {
     my ($self) = @_;
+    $self->can_do('r_run_job');
+
     my $b = $self->get_bconsole();
     
     # TODO: check input (don't use pool, level)
index 9d62ed198512d9ad2b3564e2f1bb5876802fdd90..3170cae44979e1d098a7ae87b66e43fb934cb55c 100644 (file)
@@ -1,3 +1,74 @@
+
+-- --------------------------------------------------
+-- Upgrade from 2.2
+-- --------------------------------------------------
+
+CREATE FUNCTION concat (text, text) RETURNS text AS '
+DECLARE
+result text;
+BEGIN
+IF $1 is not null THEN
+result := $1 || $2;
+END IF;
+
+RETURN result;
+END;
+' LANGUAGE plpgsql;
+
+CREATE AGGREGATE group_concat(
+sfunc = concat,
+basetype = text,
+stype = text,
+initcond = ''
+);
+
+BEGIN;
+CREATE TABLE bweb_user
+(
+       userid       serial not null,
+       username     text not null,
+       use_acl      boolean default false,
+        comment      text default '',
+       passwd       text default '',
+       primary key (userid)
+);
+CREATE UNIQUE INDEX bweb_user_idx on bweb_user (username);
+
+CREATE TABLE bweb_role
+(
+       roleid       serial not null,
+       rolename     text not null,
+--     comment      text default '',
+       primary key (roleid)
+);
+CREATE UNIQUE INDEX bweb_role_idx on bweb_role (rolename);
+
+INSERT INTO bweb_role (rolename) VALUES ('r_user_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_delete_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_prune');
+INSERT INTO bweb_role (rolename) VALUES ('r_purge');
+INSERT INTO bweb_role (rolename) VALUES ('r_group_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_location_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_cancel_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_run_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_configure');
+INSERT INTO bweb_role (rolename) VALUES ('r_client_status');
+INSERT INTO bweb_role (rolename) VALUES ('r_view_job');
+
+CREATE TABLE  bweb_role_member
+(
+       roleid       integer not null,
+       userid       integer not null,
+       primary key (roleid, userid)
+);
+
+CREATE TABLE  bweb_client_group_acl
+(
+       client_group_id       integer not null,
+       userid                integer not null,
+       primary key (client_group_id, userid)
+);
+COMMIT;
 -- --------------------------------------------------
 -- Upgrade from 2.0
 -- --------------------------------------------------
diff --git a/gui/bweb/script/tpl_extract_msg.pl b/gui/bweb/script/tpl_extract_msg.pl
new file mode 100755 (executable)
index 0000000..666b0e3
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/perl -w
+use strict;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 INFORMATIONS
+
+    This script is used to extract strings from tpl files
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+package TmplParser;
+use base "HTML::Parser";
+use HTML::Parser;
+use Locale::PO;
+my $in_script;
+
+my %dict;
+sub print_it
+{
+    foreach my $w (@_) {
+       next if ($w eq '&nbsp;');
+       next if ($w !~ /\w/);
+       next if ($w =~ />/);
+
+       next if (exists $dict{$w});
+       $dict{$w}=1;
+
+       # we add " at the begining and the end of the string
+       $w =~ s/(^|$)/"/gm; # "
+       print "msgid ", $w, "\n";
+        print 'msgstr ""', "\n\n";
+    }
+}
+
+sub text {
+    my ($self, $text) = @_;
+    
+    # between <script>..</script> we take only "words"
+    if ($in_script) {
+       my @words = ($text =~ /"([\w\s]+)"/gs);
+       print_it(@words);
+       return;
+    }
+
+    # just print out the original text
+#    $text =~ s/<\/?TMPL[^>]+>//gs;
+
+    # strip extra spaces
+    $text =~ s/(^\s+)|(\s+$)//gs;
+
+    # skip some special cases
+    return if ($text eq 'selected');
+    print_it($text);
+}
+
+sub start {
+    my ($self, $tag, $attr, $attrseq, $origtext) = @_;
+
+    # On note qu'on se trouve dans un script
+    # pour prendre que les chaines entre ""
+    if ($tag eq 'script') {
+       $in_script = 1;
+    }
+
+    #return unless ($tag =~ /^(a|input|img)$/);
+
+    # liste des attributs a traduire
+    if (defined $attr->{'title'}) {
+       print_it($attr->{'title'});
+    }
+
+    if (defined $attr->{'alt'}) {
+       print_it($attr->{'alt'});
+    }
+}
+
+sub end {
+    if ($in_script) {
+       $in_script=0;
+    }
+}
+
+package main;
+
+my $p = new TmplParser;
+for (my $f = shift ; $f and -f $f ; $f = shift) {
+    #$TmplParser::nb=0;
+    print "#============ $f ==========\n";
+    $p->parse_file($f);
+}
+
diff --git a/gui/bweb/script/upgrade-2.2_3.0_postgresql.sql b/gui/bweb/script/upgrade-2.2_3.0_postgresql.sql
new file mode 100644 (file)
index 0000000..f9eccb7
--- /dev/null
@@ -0,0 +1,70 @@
+-- --------------------------------------------------
+-- Upgrade from 2.2
+-- --------------------------------------------------
+
+CREATE FUNCTION concat (text, text) RETURNS text AS '
+DECLARE
+result text;
+BEGIN
+IF $1 is not null THEN
+result := $1 || $2;
+END IF;
+
+RETURN result;
+END;
+' LANGUAGE plpgsql;
+
+CREATE AGGREGATE group_concat(
+sfunc = concat,
+basetype = text,
+stype = text,
+initcond = ''
+);
+
+BEGIN;
+CREATE TABLE bweb_user
+(
+       userid       serial not null,
+       username     text not null,
+       use_acl      boolean default false,
+        comment      text default '',
+       passwd       text default '',
+       primary key (userid)
+);
+CREATE UNIQUE INDEX bweb_user_idx on bweb_user (username);
+
+CREATE TABLE bweb_role
+(
+       roleid       serial not null,
+       rolename     text not null,
+--     comment      text default '',
+       primary key (roleid)
+);
+CREATE UNIQUE INDEX bweb_role_idx on bweb_role (rolename);
+
+INSERT INTO bweb_role (rolename) VALUES ('r_user_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_delete_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_prune');
+INSERT INTO bweb_role (rolename) VALUES ('r_purge');
+INSERT INTO bweb_role (rolename) VALUES ('r_group_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_location_mgnt');
+INSERT INTO bweb_role (rolename) VALUES ('r_cancel_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_run_job');
+INSERT INTO bweb_role (rolename) VALUES ('r_configure');
+INSERT INTO bweb_role (rolename) VALUES ('r_client_status');
+INSERT INTO bweb_role (rolename) VALUES ('r_view_job');
+
+CREATE TABLE  bweb_role_member
+(
+       roleid       integer not null,
+       userid       integer not null,
+       primary key (roleid, userid)
+);
+
+CREATE TABLE  bweb_client_group_acl
+(
+       client_group_id       integer not null,
+       userid                integer not null,
+       primary key (client_group_id, userid)
+);
+COMMIT;
index 346325433ebc3acc4b32b20d4dc727f40f553848..349c8fc1051424c2d8daa827d4f55fbdeb0f4285 100644 (file)
@@ -26,7 +26,7 @@ if (navigator.appName == 'Konqueror') {
        <li><a href="bweb.pl?action=groups">Groups</a> </li>
      </ul>
  </li>
- <li>Jobs
+ <li style="padding: 0.25em 2em;">Jobs
    <ul> 
      <li><a href="bweb.pl?action=run_job">Defined Jobs</a>
      <li><a href="bweb.pl?action=job_group">Jobs by group</a>
@@ -55,11 +55,17 @@ if (navigator.appName == 'Konqueror') {
  </li>
 </TMPL_IF> 
  <li><a href="bweb.pl?action=graph"> Statistics </a></li>
- <li> <a href="bweb.pl?action=view_conf"> Configuration </a> </li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuration </a> 
+<TMPL_IF enable_security>
+  <ul> <li> <a href="bweb.pl?action=view_conf"> Configuration </a> 
+       <li> <a href="bweb.pl?action=users"> Manage users </a>
+  </ul>
+</TMPL_IF>
+</li>
  <li> <a href="bweb.pl?action=about"> About </a> </li>
  <li style="padding: 0.25em 2em;float: right;">&nbsp;Logged as <TMPL_VAR NAME=loginname> </li>
  <li style="float: right;white-space: nowrap;">
-<input type="image" class="button" title="search media" onclick="search_media();" src="/bweb/tape.png"><input type="image" title="search client" onclick="search_client();" src="/bweb/client.png">&nbsp;<input class='formulaire' style="margin: 0 2px 0 2px; padding: 0 0 0 0;" id='searchbox' type='text' size='8' value="search..." onclick="this.value='';" title="search media or client"></li>
+<input type="image" class="button" title="Search media" onclick="search_media();" src="/bweb/tape.png"><input type="image" title="Search client" onclick="search_client();" src="/bweb/client.png">&nbsp;<input class='formulaire' style="margin: 0 2px 0 2px; padding: 0 0 0 0;" id='searchbox' type='text' size='8' value="search..." onclick="this.value='';" title="Search media or client"></li>
 </ul>
 
 <form name="search" action="bweb.pl?" method='GET'>
index d7f96519cefdc55c1fb119317e79e169be46e1aa..e804e060f58e5e32eb37fe936a1e1da7716a1094 100644 (file)
@@ -20,7 +20,7 @@ Hi,
 
 Could you move these media to <TMPL_VAR newlocation>
 Media :
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
  - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
 </TMPL_LOOP>
 
index c918cf29885afad17cc10ab0b76d6598c24ae707..e470d372b483337cd7567bb4a8414e6d84282852 100644 (file)
      <tr><td>display_log_time :</td> 
          <td> <input class="formulaire" title="display log timestamp" type='checkbox' name='display_log_time' <TMPL_IF display_log_time> checked='checked' value='on' </TMPL_IF> > 
          </td></tr>
+     <tr><td>security :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security' title='Use user managment in bweb. Read INSTALL first' <TMPL_IF enable_security> checked='checked' value='on' </TMPL_IF> > 
+     <tr><td>security acl:</td> 
+         <td> <input class="formulaire" type='checkbox' name='enable_security_acl' title='Use user acl in bweb. Read INSTALL first' <TMPL_IF enable_security_acl> checked='checked' value='on' </TMPL_IF> > 
      <tr><td>debug :</td> 
          <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
          </td></tr>
index 5056458da267066bd9b71c9ad0b1ffc10ed21e56..ea3ccfff25b024e670cd73cc839ccb853d8d2a8f 100644 (file)
@@ -18,6 +18,8 @@
     <tr><td title="You can choose the Job table that you want to use to get statistics">stat_job_table :</td> <td> <TMPL_IF stat_job_table><TMPL_VAR stat_job_table><TMPL_ELSE>Job</TMPL_IF> </td></tr>
     <tr><td title="/path/to/bconsole -n -c /path/to/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
     <tr><td title="display timestamp in job log">display_log_time :</td> <td> <TMPL_VAR display_log_time> </td></tr>
+    <tr><td title="user managment">security :</td> <td> <TMPL_VAR enable_security> </td></tr>
+    <tr><td title="user filter">security acl :</td> <td> <TMPL_VAR enable_security_acl> </td></tr>
     <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
     <TMPL_IF achs>
     <tr>  <td><b>Autochanger</b></td>  <td/></tr>
index 33199f279fa5322d83791d06838ba78443fd9727..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,65 +0,0 @@
-<br/>
- <div class='titlediv'>
-  <h1 class='newstitle'> Last jobs for <TMPL_VAR clientname> (<TMPL_VAR Filter>)
-  </h1>
- </div>
- <div class='bodydiv'>
-
-   <table id='id<TMPL_VAR ID>'></table>
-
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
-    <img src="/bweb/chart.png" alt="backup size" title="backup size evolution"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
-    <img src="/bweb/chart.png" alt="backup duration" title="backup time evolution"/>
-    </a>
-<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
-    <img src="/bweb/chart.png" alt="backup rate" title="backup rate evolution"/>
-    </a>                               
- </div>
-
-
-<script type="text/javascript" language="JavaScript">
-var header = new Array("JobId", "Job Name", "File Set", "Level", "Start Time", 
-                  "Job Files", "Job Bytes", "Errors");
-
-var data = new Array();
-
-<TMPL_LOOP Jobs>
-data.push( new Array(
-"<TMPL_VAR JobId>",
-"<TMPL_VAR JobName>",    
-"<TMPL_VAR FileSet>",
-"<TMPL_VAR Level>",
-"<TMPL_VAR StartTime>",
-"<TMPL_VAR JobFiles>",   
-human_size(<TMPL_VAR JobBytes>),
-"<TMPL_VAR JobErrors>"   
- )
-);
-</TMPL_LOOP>
-
-nrsTable.setup(
-{
- table_name:     "id<TMPL_VAR ID>",
- table_header: header,
- table_data: data,
- up_icon: up_icon,
- down_icon: down_icon,
- prev_icon: prev_icon,
- next_icon: next_icon,
- rew_icon:  rew_icon,
- fwd_icon:  fwd_icon,
-// natural_compare: true,
- even_cell_color: even_cell_color,
- odd_cell_color: odd_cell_color, 
- header_color: header_color,
- page_nav: true,
- rows_per_page: rows_per_page,
- disable_sorting: new Array(5,6)
-}
-);
-
-// get newest job first
-nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
-</script>
index 857796b8cf23eb4bc0b062a9e678efa36ef7cc9c..3840ee7a4cf2d709f7405dfad0484076c8514f9b 100644 (file)
      document.getElementById('client_' + <TMPL_VAR name>).selected = true;
   </TMPL_LOOP>
 
+  <TMPL_LOOP qclient_groups>
+     document.getElementById('group_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
   <TMPL_IF status>
      document.getElementById('status_<TMPL_VAR status>').selected=true;
   </TMPL_IF>
index e4ce0c951b4ea4dc0a37bab4de949a32b0341f50..6944073b4d9c941dfdf8792a022be031523ef199 100644 (file)
       <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
        class='formulaire' size='8'>
   </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Expired media</h2>
+    <input type='checkbox' name='expired' <TMPL_IF expired> checked </TMPL_IF> 
+       class='formulaire'>
+  </td>
+</tr>
 </tr>
  <tr>
   <td valign='bottom'> 
index a9b30f386a47226aca979b164202724b48a68bf9..78f15058927a6cc05aba9309eac0bd274ca135c5 100644 (file)
   </label>
  </form>
  </td>
+<TMPL_IF joberrors>
+ <td>
+    <a href="<TMPL_VAR thisurl>;error=1"
+         title="View only errors">
+    <img src='/bweb/doc.png' alt="view errors"></a> View only errors
+  </td>
+</TMPL_IF>
  </table>
 </div>
 
index 251a7b094aee665fb92a179e9b5aabfad4f244d1..28ec41acdf7f261ebceb142a9a4318644fa55a64 100644 (file)
@@ -6,4 +6,75 @@
   <pre id='log'>
 <TMPL_VAR lines>
   </pre>
+
+<a id='prev'><img border='0' src='/bweb/prev.png'></a>
+<a id='next'><img border='0' src='/bweb/next.png'></a>
  </div>
+<script type="text/javascript" language='JavaScript'>
+
+var url='<TMPL_VAR thisurl>';
+var urlprev=url;
+var urlnext=url;
+
+var reoff = new RegExp('offset=[0-9]+', "");
+var relim = new RegExp('limit=[0-9]+', "");
+
+var offset=0;
+var limit=1000;
+var nbline=0;
+<TMPL_IF offset>
+offset = <TMPL_VAR offset>;
+</TMPL_IF>
+<TMPL_IF limit>
+limit = <TMPL_VAR limit>;
+</TMPL_IF>
+<TMPL_IF nbline>
+nbline=<TMPL_VAR nbline>;
+</TMPL_IF>
+
+if (nbline == limit) {
+   var offset_next = offset + limit;
+   
+   if (url.match(reoff)) {
+       urlnext = urlnext.replace(reoff, 'offset=' + offset_next);
+   } else {
+       urlnext = urlnext + ';offset=' + offset_next;
+   }
+   
+   if (url.match(relim)) {
+       urlnext = urlnext.replace(relim, 'limit=' + limit);
+   } else {
+       urlnext = urlnext + ';limit=' + limit;
+   }
+   
+   document.getElementById('next').href = urlnext;
+
+} else {
+   document.getElementById('next').style.visibility="hidden";
+}
+
+if (offset > 0) {
+   var offset_prev = offset - limit;
+   if (offset_prev < 0) {
+        offset_prev=0;
+   }
+   if (url.match(reoff)) {
+       urlprev = urlprev.replace(reoff, 'offset=' + offset_prev);
+   } else {
+       urlprev = urlprev + ';offset=' + offset_prev ;
+   }
+   if (url.match(relim)) {
+       urlprev = urlprev.replace(relim, 'limit=' + limit);
+   } else {
+       urlprev = urlprev + ';limit=' + limit;
+   }
+
+   if (offset_prev >= 0) {
+       document.getElementById('prev').href = urlprev;
+   } else {
+       document.getElementById('prev').style.visibility="hidden";
+   }
+} else {
+   document.getElementById('prev').style.visibility="hidden";
+}   
+</script>
index e4a029b44fec3a6195fcdcd89408435abf47dbd0..cad256d73bc78c846428da04a119ac14e0a12ff5 100644 (file)
@@ -42,7 +42,7 @@ var img;
 var chkbox;
 var d;
 
-<TMPL_LOOP Medias>
+<TMPL_LOOP media>
 d = percent_usage(<TMPL_VAR volusage>);
 
 img = document.createElement('IMG');
index 6dcadbad3569a5628e159b36a3406eb075c2c2d8..6f8a53a5cb1d30d4c8d8833adf50edfa9d51f2c3 100644 (file)
@@ -40,7 +40,7 @@
 </table>
 <script type="text/javascript" language="JavaScript">
 
-var header = new Array("Pool","Online","Location","Vol Status", "Vol Bytes", "Expire",
+var header = new Array("Pool","Online","Enabled", "Location","Vol Status", "Vol Bytes", "Expire",
                       "Retention","Max use duration", "Max jobs" );
 
 var data = new Array();
@@ -52,6 +52,7 @@ img.src = '/bweb/inflag<TMPL_VAR online>.png';
 data.push( new Array(
 "<TMPL_VAR poolname>",
 img,
+human_enabled("<TMPL_VAR enabled>"),
 "<TMPL_VAR location>",
 "<TMPL_VAR volstatus>",
 human_size(<TMPL_VAR nb_bytes>),
diff --git a/gui/bweb/tpl/display_user.tpl b/gui/bweb/tpl/display_user.tpl
new file mode 100644 (file)
index 0000000..5c8d273
--- /dev/null
@@ -0,0 +1,108 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> User: <TMPL_VAR username></h1>
+</div>
+<div class='bodydiv'>
+
+<form name="form1" action="?">
+<input type="hidden" value="1" name="create">
+ <table>
+ <tr>
+  <td>Username:</td> <td> <input class="formulaire" type="text" name="username" value="<TMPL_VAR username>"> </td>
+<!-- </tr><tr>
+  <td>Password:</td> <td> <input class="formulaire" type="password" name="passwd" value="<TMPL_VAR passwd>"> </td>
+-->
+ </tr><tr>
+  <td>Comment:</td> <td> <input class="formulaire" type="text" name="comment" value="<TMPL_VAR comment>"> </td>
+ </tr><tr>
+<td> Profile:</td><td>
+ <select name="profile" id='profile' class="formulaire">
+  <option onclick='set_role("")'></option>
+  <option onclick='set_role("administrator")'>Administrator</option>
+  <option onclick='set_role("customer")'>Customer</option>
+ </select>
+</td><td>Or like an existing user: </td><td>
+ <select name="copy_username" class="formulaire">
+  <option onclick="disable_sel(false)"></option>
+ <TMPL_LOOP db_usernames>
+  <option title="<TMPL_VAR comment>" onclick="disable_sel(true)" value="<TMPL_VAR username>"><TMPL_VAR username></option>
+ </TMPL_LOOP>
+ </select>
+</td>
+ </tr><tr>
+ </tr><tr>
+<td> Roles:</td><td>
+ <select name="rolename" id='rolename' multiple class="formulaire" size=15>
+ <TMPL_LOOP db_roles>
+  <option title="<TMPL_VAR comment>" value="<TMPL_VAR rolename>" <TMPL_IF userid>selected</TMPL_IF> ><TMPL_VAR rolename></option>
+ </TMPL_LOOP>
+ </select>
+ </td>
+</tr><tr>
+<td> Use groups filter:</td><td>
+<input class="formulaire" onclick="disable_group(this.checked == false)" type="checkbox" name="use_acl" <TMPL_IF use_acl> checked </TMPL_IF> > </td>
+</tr><tr>
+<td> Groups:</td><td>
+ <select name="client_group" id='client_group' multiple class="formulaire" size=15>
+<TMPL_LOOP db_client_groups>
+        <option id='group_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+ </select>
+ </td>
+</tr>
+</table>
+    <input type="image" name='action' value='user_save'
+     src='/bweb/save.png'>
+</form>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+
+<TMPL_LOOP client_group>
+    document.getElementById('group_<TMPL_VAR name>').selected = true;
+</TMPL_LOOP>
+
+<TMPL_UNLESS use_acl>
+disable_group(true); 
+</TMPL_UNLESS>
+
+function disable_sel(val) 
+{
+       document.form1.profile.disabled = val;
+       document.form1.rolename.disabled = val;
+}
+function disable_group(val) 
+{
+       document.form1.client_group.disabled = val;
+}
+function set_role(val)
+{
+   if (val == "administrator") {
+       for (var i=0; i < document.form1.rolename.length; ++i) {
+             document.form1.rolename[i].selected = true;
+       }
+   } else if (val == "production") {
+       for (var i=0; i < document.form1.rolename.length; ++i) {
+          if (document.form1.rolename[i].value != 'r_configure' &&
+               document.form1.rolename[i].value != 'r_user_mgnt' &&
+               document.form1.rolename[i].value != 'r_group_mgnt'
+               )
+           {
+             document.form1.rolename[i].selected = true;
+           }
+        }
+   } else if (val == "customer") {
+       for (var i=0; i < document.form1.rolename.length; ++i) {
+          if (document.form1.rolename[i].value == 'r_view_stats'   ||
+               document.form1.rolename[i].value == 'r_view_history' ||
+               document.form1.rolename[i].value == 'r_view_log'
+               )
+           {
+             document.form1.rolename[i].selected = true;
+          } else {
+             document.form1.rolename[i].selected = false;
+          }
+       }
+   }
+
+}
+</script>
diff --git a/gui/bweb/tpl/display_users.tpl b/gui/bweb/tpl/display_users.tpl
new file mode 100644 (file)
index 0000000..7a477a9
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Users</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" name='action' value='user_add' title='Add' src='/bweb/add.png'>&nbsp;
+    <input type="image" name='action' value='user_del' 
+     onclick="return confirm('Do you want to delete this user ?');" 
+     title='Supprimer' src='/bweb/remove.png'>&nbsp;
+    <input type="image" name='action' value='user_edit' title='Modify' src='/bweb/edit.png'>&nbsp;
+
+    <input type="image" name='action' value='client' title='View clients'
+     src='/bweb/zoom.png'>&nbsp;
+    <input type="image" name='action' value='job' title='View jobs'
+     src='/bweb/zoom.png'>&nbsp;
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Username","Selection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP db_usernames>
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name  = 'username';
+chkbox.value = '<TMPL_VAR username>';
+
+data.push( new Array(
+"<TMPL_VAR username>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
+
+
index 816353d8f90a4b7abed24bad084d43ed93e287c2..906e6c332e716380f2e4ee8688e6274ed27f3efa 100644 (file)
@@ -24,7 +24,7 @@ var header = new Array("Volume Name","Vol Status",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR NAME=volumename>';
index 0f10329d55d18ae210b1aa608171f7dde039d4e4..cd4aa6db943d4bedea485f41b2f02c07e632f3a0 100644 (file)
@@ -10,6 +10,7 @@
     <td style='align: left;'>
     <input type="image" onclick='javascript:window.history.go(-2);' title='Back' src='/bweb/prev.png'>
     </td><td style='align: right;'>
+    <input type="hidden" name='enabled' value="yes">
     <input type="image" name='action' value='move_media'
      src='/bweb/intern.png'>
    </td></tr>
@@ -25,7 +26,7 @@ var header = new Array("Volume Name","Vol Status",
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=Medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.name = 'media';
index 80520a13a5374e620a65db1870fd6e04bc08ec6d..3c5c66cd61234c8e11769f32b293dba856ee519b 100644 (file)
@@ -3,7 +3,7 @@
   <h1 class='newstitle'>Move media</h1>
  </div>
  <div class="bodydiv">
-   <form action='?' method='get'>
+   <form name='form1' action='?' method='get'>
     <table id='id<TMPL_VAR NAME=ID>'></table>
     <table border='0'>
     <tr><td> New location: </td><td>
     <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
     </TMPL_LOOP>
 </select>
-    </td></tr><tr><td> Status: </td><td>
-<select name='volstatus' class='formulaire'>
-    <option value=''>Don't update</option>
-    <option value='Append'>Append</option>
-    <option value='Archive'>Archive</option>
-    <option value='Disabled'>Disabled</option>
-    <option value='Cleaning'>Cleaning</option>
-    <option value='Error'>Error</option>
-    <option value='Full'>Full</option>
-    <option value='Purged'>Purged</option>
-    <option value='Read-Only'>Read-Only</option>
-    <option value='Recycle'>Recycle</option>
-    <option value='Used'>Used</option>
+    </td></tr><tr><td> Enabled: </td><td>
+<select name='enabled' class='formulaire'>
+    <option value='no'>no</option>
+    <option value='yes'>yes</option>
+    <option value='archived'>archived</option>
 </select>
     </td><tr><td> User: </td><td>
 <input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
@@ -46,7 +38,7 @@ var header = new Array("Volume Name", "Location", "Select");
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
@@ -82,4 +74,13 @@ nrsTable.setup(
  rows_per_page: rows_per_page
 }
 );
+<TMPL_IF enabled>
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
+</TMPL_IF>
 </script>
index 75adcbaaaf10d13a3f331ba7a6180a7e10c7959a..93fc9eabf367d9c6d5fad09eacff35cb3eff0d2a 100644 (file)
@@ -21,7 +21,7 @@ var header = new Array("Volume Name", "Location", "Select");
 var data = new Array();
 var chkbox;
 
-<TMPL_LOOP NAME=medias>
+<TMPL_LOOP NAME=media>
 chkbox = document.createElement('INPUT');
 chkbox.type  = 'checkbox';
 chkbox.value = '<TMPL_VAR name=volumename>';
index 2c9a0c14ee04518bc7478fcb6def58e6fe93ffa6..f09db42d7a249cfa4188138d65bdbe594b1769d6 100644 (file)
         </td>
     </tr>
 
+    <tr><td>Enabled:</td>
+        <td> <select name='enabled' class='formulaire'>
+           <option value='yes'>yes</option>
+           <option value='no'>no</option>
+           <option value='archived'>archived</option>
+           </select>
+        </td>
+    </tr>
+
     <tr><td> Location : </td>
         <td><select name='location' class='formulaire'>
         <option value=''></option>
@@ -156,5 +165,12 @@ for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
       ok=0;
    }
 }
+ok=1;
+for (var i=0; ok && i < document.form1.enabled.length; ++i) {
+   if (document.form1.enabled[i].value == '<TMPL_VAR enabled>') {
+      document.form1.enabled[i].selected = true;
+      ok=0;
+   }
+}
 
 </script>
index 1c0284a38640c63ce9a5d0c80415f6fd62eb831e..381d083309dedfb084a229ef0c30de2076f6df0e 100644 (file)
@@ -23,7 +23,8 @@ if [ "$1" = "configure" ] ; then
  echo
  echo "If you are using postgresql, you have to load /usr/share/bweb/bweb-postgresql.sql in your database"
  
- echo "postgres@localhost:~$ psql bacula < /usr/share/bweb/bweb-postgresql.sql"
+ echo "postgres@localhost:~$ createlang plpgsql -Upostgres -d bacula"
+ echo "postgres@localhost:~$ psql -U bacula bacula < /usr/share/bweb/bweb-postgresql.sql"
  echo 
  echo "If you are using mysql, you have to load /usr/share/bweb/bweb-mysql.sql in your database"
  echo "root@localhost:~$ mysql bacula < /usr/share/bweb/bweb-mysql.sql"
@@ -43,6 +44,6 @@ fi
 
 if [ "$1" = "upgrade" ] ; then
  echo "If you are using postgresql, you have to load /usr/share/bweb/upgrade-2.0_2.2_postgresql.sql in your database"
- echo "postgres@localhost:~$ psql bacula < /usr/share/bweb/upgrade-2.0_2.2_postgresql.sql"
+ echo "postgres@localhost:~$ psql -U bacula bacula < /usr/share/bweb/upgrade-2.0_2.2_postgresql.sql"
  echo
 fi
index 7ef970909050761b7c816498ff59551eab790ec7..238e7c25e18075db4f1878b91a2a349af4205234 100644 (file)
@@ -1,3 +1,11 @@
+bweb (2.2.6-1) stable; urgency=low
+  * Replace VolStatus by Enabled in volume location
+  * Add Enabled in volume update and zoom
+  * Add Prev/Next on job log output
+  * Add a error filter to Job zoom view
+
+ -- Eric Bollengier <eric@eb.homelinux.org>  Tue,  30 Oct 2007 22:15:47 +0000
+
 bweb (2.2.1-1) stable; urgency=low
   
   * WARNING: 2.2.1-1 version don't support bacula 2.0.X anymore
index 0d387f04d85c5fa5bea405cc0bcad809ecd9f247..2c1b6c7d57abc1625af597f6b5c1a4de66fd9202 100644 (file)
@@ -17,13 +17,12 @@ Section: base
 Architecture: all
 Depends: libtime-modules-perl, bweb-common, libgd-graph-perl, libdbd-pg-perl|libdbd-mysql-perl,libhtml-template-perl
 Description: Bacula restore interface
-  Bweb is a bacula web interface
+  Bweb is a Bacula web interface
 
 Package: bweb-common
 Section: base
 Architecture: all
 Depends: libtime-modules-perl, libexpect-perl
 Description: Bacula restore interface
-  Bweb is a bacula web interface
-
+  Bweb is a Bacula web interface