ffzg/recall_notices.pl: added --interval and --dedup
[koha.git] / C4 / Auth.pm
index ddcaf1a..c3ba5ba 100644 (file)
@@ -19,6 +19,8 @@ package C4::Auth;
 
 use strict;
 use warnings;
+use Carp qw/croak/;
+
 use Digest::MD5 qw(md5_base64);
 use JSON qw/encode_json/;
 use URI::Escape;
@@ -316,6 +318,7 @@ sub get_template_and_user {
             $template->param( CAN_user_coursereserves   => 1 );
             $template->param( CAN_user_clubs            => 1 );
             $template->param( CAN_user_ill              => 1 );
+            $template->param( CAN_user_stockrotation    => 1 );
 
             foreach my $module ( keys %$all_perms ) {
                 foreach my $subperm ( keys %{ $all_perms->{$module} } ) {
@@ -532,8 +535,8 @@ sub get_template_and_user {
         my $opac_limit_override = $ENV{'OPAC_LIMIT_OVERRIDE'};
         my $opac_name           = '';
         if (
-            ( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:(\w+)/ ) ||
-            ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:(\w+)/ ) ||
+            ( $opac_limit_override && $opac_search_limit && $opac_search_limit =~ /branch:([\w-]+)/ ) ||
+            ( $in->{'query'}->param('limit') && $in->{'query'}->param('limit') =~ /branch:([\w-]+)/ ) ||
             ( $in->{'query'}->param('multibranchlimit') && $in->{'query'}->param('multibranchlimit') =~ /multibranchlimit-(\w+)/ )
           ) {
             $opac_name = $1;    # opac_search_limit is a branch, so we use it.
@@ -1603,7 +1606,11 @@ sub check_api_auth {
   ($status, $sessionId) = check_api_auth($cookie, $userflags);
 
 Given a CGISESSID cookie set during a previous login to Koha, determine
-if the user has the privileges specified by C<$userflags>.
+if the user has the privileges specified by C<$userflags>. C<$userflags>
+is passed unaltered into C<haspermission> and as such accepts all options
+avaiable to that routine with the one caveat that C<check_api_auth> will
+also allow 'undef' to be passed and in such a case the permissions check
+will be skipped altogether.
 
 C<check_cookie_auth> is meant for authenticating special services
 such as tools/upload-file.pl that are invoked by other pages that
@@ -1698,7 +1705,7 @@ sub check_cookie_auth {
             return ( "expired", undef );
         } else {
             $session->param( 'lasttime', time() );
-            my $flags = haspermission( $userid, $flagsrequired );
+            my $flags = defined($flagsrequired) ? haspermission( $userid, $flagsrequired ) : 1;
             if ($flags) {
                 return ( "ok", $sessionID );
             } else {
@@ -2021,40 +2028,74 @@ sub get_all_subpermissions {
 
 =head2 haspermission
 
+  $flagsrequired = '*';                                 # Any permission at all
+  $flagsrequired = 'a_flag';                            # a_flag must be satisfied (all subpermissions)
+  $flagsrequired = [ 'a_flag', 'b_flag' ];              # a_flag OR b_flag must be satisfied
+  $flagsrequired = { 'a_flag => 1, 'b_flag' => 1 };     # a_flag AND b_flag must be satisfied
+  $flagsrequired = { 'a_flag' => 'sub_a' };             # sub_a of a_flag must be satisfied
+  $flagsrequired = { 'a_flag' => [ 'sub_a, 'sub_b' ] }; # sub_a OR sub_b of a_flag must be satisfied
+
   $flags = ($userid, $flagsrequired);
 
 C<$userid> the userid of the member
-C<$flags> is a hashref of required flags like C<$borrower-&lt;{authflags}> 
+C<$flags> is a query structure similar to that used by SQL::Abstract that
+denotes the combination of flags required. It is a required parameter.
+
+The main logic of this method is that things in arrays are OR'ed, and things
+in hashes are AND'ed. The `*` character can be used, at any depth, to denote `ANY`
 
 Returns member's flags or 0 if a permission is not met.
 
 =cut
 
+sub _dispatch {
+    my ($required, $flags) = @_;
+
+    my $ref = ref($required);
+    if ($ref eq '') {
+        if ($required eq '*') {
+            return 0 unless ( $flags or ref( $flags ) );
+        } else {
+            return 0 unless ( $flags and (!ref( $flags ) || $flags->{$required} ));
+        }
+    } elsif ($ref eq 'HASH') {
+        foreach my $key (keys %{$required}) {
+            my $require = $required->{$key};
+            my $rflags  = $flags->{$key};
+            return 0 unless _dispatch($require, $rflags);
+        }
+    } elsif ($ref eq 'ARRAY') {
+        my $satisfied = 0;
+        foreach my $require ( @{$required} ) {
+            my $rflags =
+              ( ref($flags) && !ref($require) && ( $require ne '*' ) )
+              ? $flags->{$require}
+              : $flags;
+            $satisfied++ if _dispatch( $require, $rflags );
+        }
+        return 0 unless $satisfied;
+    } else {
+        croak "Unexpected structure found: $ref";
+    }
+
+    return $flags;
+};
+
 sub haspermission {
     my ( $userid, $flagsrequired ) = @_;
+
+
+    #Koha::Exceptions::WrongParameter->throw('$flagsrequired should not be undef')
+    #  unless defined($flagsrequired);
+
     my $sth = C4::Context->dbh->prepare("SELECT flags FROM borrowers WHERE userid=?");
     $sth->execute($userid);
     my $row = $sth->fetchrow();
     my $flags = getuserflags( $row, $userid );
 
+    return $flags unless defined($flagsrequired);
     return $flags if $flags->{superlibrarian};
-
-    foreach my $module ( keys %$flagsrequired ) {
-        my $subperm = $flagsrequired->{$module};
-        if ( $subperm eq '*' ) {
-            return 0 unless ( $flags->{$module} == 1 or ref( $flags->{$module} ) );
-        } else {
-            return 0 unless (
-                ( defined $flags->{$module} and
-                    $flags->{$module} == 1 )
-                or
-                ( ref( $flags->{$module} ) and
-                    exists $flags->{$module}->{$subperm} and
-                    $flags->{$module}->{$subperm} == 1 )
-            );
-        }
-    }
-    return $flags;
+    return _dispatch($flagsrequired, $flags);
 
     #FIXME - This fcn should return the failed permission so a suitable error msg can be delivered.
 }