View | Details | Raw Unified | Return to bug 14540
Collapse All | Expand All

(-)a/C4/Auth.pm (-38 / +69 lines)
Lines 24-29 use File::Spec; Link Here
24
use JSON qw/encode_json/;
24
use JSON qw/encode_json/;
25
use URI::Escape;
25
use URI::Escape;
26
use CGI::Session;
26
use CGI::Session;
27
use Scalar::Util qw(blessed);
28
use Try::Tiny;
27
29
28
require Exporter;
30
require Exporter;
29
use C4::Context;
31
use C4::Context;
Lines 195-201 sub get_template_and_user { Link Here
195
197
196
            $template->param(
198
            $template->param(
197
                loginprompt => 1,
199
                loginprompt => 1,
198
                script_name => get_script_name(),
200
                script_name => Koha::AuthUtils::get_script_name(),
199
            );
201
            );
200
            print $in->{query}->header(
202
            print $in->{query}->header(
201
                {   type              => 'text/html',
203
                {   type              => 'text/html',
Lines 265-271 sub get_template_and_user { Link Here
265
        # We are going to use the $flags returned by checkauth
267
        # We are going to use the $flags returned by checkauth
266
        # to create the template's parameters that will indicate
268
        # to create the template's parameters that will indicate
267
        # which menus the user can access.
269
        # which menus the user can access.
268
        if ( $flags && $flags->{superlibrarian} == 1 ) {
270
        if ( $flags && $flags->{superlibrarian} ) {
269
            $template->param( CAN_user_circulate        => 1 );
271
            $template->param( CAN_user_circulate        => 1 );
270
            $template->param( CAN_user_catalogue        => 1 );
272
            $template->param( CAN_user_catalogue        => 1 );
271
            $template->param( CAN_user_parameters       => 1 );
273
            $template->param( CAN_user_parameters       => 1 );
Lines 294-304 sub get_template_and_user { Link Here
294
296
295
        if ($flags) {
297
        if ($flags) {
296
            foreach my $module ( keys %$all_perms ) {
298
            foreach my $module ( keys %$all_perms ) {
297
                if ( defined($flags->{$module}) && $flags->{$module} == 1 ) {
299
                if ( ref( $flags->{$module} ) ) {
298
                    foreach my $subperm ( keys %{ $all_perms->{$module} } ) {
299
                        $template->param( "CAN_user_${module}_${subperm}" => 1 );
300
                    }
301
                } elsif ( ref( $flags->{$module} ) ) {
302
                    foreach my $subperm ( keys %{ $flags->{$module} } ) {
300
                    foreach my $subperm ( keys %{ $flags->{$module} } ) {
303
                        $template->param( "CAN_user_${module}_${subperm}" => 1 );
301
                        $template->param( "CAN_user_${module}_${subperm}" => 1 );
304
                    }
302
                    }
Lines 1022-1027 sub checkauth { Link Here
1022
            # $return: 1 = valid user, 2 = superlibrarian
1020
            # $return: 1 = valid user, 2 = superlibrarian
1023
            if ($return) {
1021
            if ($return) {
1024
1022
1023
                $userid = $q_userid if $return == 2;
1024
1025
                #_session_log(sprintf "%20s from %16s logged in  at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},(strftime '%c', localtime));
1025
                #_session_log(sprintf "%20s from %16s logged in  at %30s.\n", $userid,$ENV{'REMOTE_ADDR'},(strftime '%c', localtime));
1026
                if ( $flags = haspermission( $userid, $flagsrequired ) ) {
1026
                if ( $flags = haspermission( $userid, $flagsrequired ) ) {
1027
                    $loggedin = 1;
1027
                    $loggedin = 1;
Lines 1035-1041 sub checkauth { Link Here
1035
1035
1036
                if ( $return == 1 ) {
1036
                if ( $return == 1 ) {
1037
                    my $select = "
1037
                    my $select = "
1038
                    SELECT borrowernumber, firstname, surname, flags, borrowers.branchcode,
1038
                    SELECT borrowernumber, firstname, surname, borrowers.branchcode,
1039
                    branches.branchname    as branchname,
1039
                    branches.branchname    as branchname,
1040
                    branches.branchprinter as branchprinter,
1040
                    branches.branchprinter as branchprinter,
1041
                    email
1041
                    email
Lines 1058-1064 sub checkauth { Link Here
1058
                        }
1058
                        }
1059
                    }
1059
                    }
1060
                    if ( $sth->rows ) {
1060
                    if ( $sth->rows ) {
1061
                        ( $borrowernumber, $firstname, $surname, $userflags,
1061
                        ( $borrowernumber, $firstname, $surname,
1062
                            $branchcode, $branchname, $branchprinter, $emailaddress ) = $sth->fetchrow;
1062
                            $branchcode, $branchname, $branchprinter, $emailaddress ) = $sth->fetchrow;
1063
                        $debug and print STDERR "AUTH_3 results: " .
1063
                        $debug and print STDERR "AUTH_3 results: " .
1064
                          "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
1064
                          "$cardnumber,$borrowernumber,$userid,$firstname,$surname,$userflags,$branchcode,$emailaddress\n";
Lines 1218-1224 sub checkauth { Link Here
1218
        opaclayoutstylesheet                  => C4::Context->preference("opaclayoutstylesheet"),
1218
        opaclayoutstylesheet                  => C4::Context->preference("opaclayoutstylesheet"),
1219
        login                                 => 1,
1219
        login                                 => 1,
1220
        INPUTS                                => \@inputs,
1220
        INPUTS                                => \@inputs,
1221
        script_name                           => get_script_name(),
1221
        script_name                           => Koha::AuthUtils::get_script_name(),
1222
        casAuthentication                     => C4::Context->preference("casAuthentication"),
1222
        casAuthentication                     => C4::Context->preference("casAuthentication"),
1223
        shibbolethAuthentication              => $shib,
1223
        shibbolethAuthentication              => $shib,
1224
        SessionRestrictionByIP                => C4::Context->preference("SessionRestrictionByIP"),
1224
        SessionRestrictionByIP                => C4::Context->preference("SessionRestrictionByIP"),
Lines 1815-1849 sub checkpw_internal { Link Here
1815
1815
1816
    my $sth =
1816
    my $sth =
1817
      $dbh->prepare(
1817
      $dbh->prepare(
1818
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname,flags from borrowers join branches on borrowers.branchcode=branches.branchcode where userid=?"
1818
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname from borrowers join branches on borrowers.branchcode=branches.branchcode where userid=?"
1819
      );
1819
      );
1820
    $sth->execute($userid);
1820
    $sth->execute($userid);
1821
    if ( $sth->rows ) {
1821
    if ( $sth->rows ) {
1822
        my ( $stored_hash, $cardnumber, $borrowernumber, $userid, $firstname,
1822
        my ( $stored_hash, $cardnumber, $borrowernumber, $userid, $firstname,
1823
            $surname, $branchcode, $branchname, $flags )
1823
            $surname, $branchcode, $branchname )
1824
          = $sth->fetchrow;
1824
          = $sth->fetchrow;
1825
1825
1826
        if ( checkpw_hash( $password, $stored_hash ) ) {
1826
        if ( checkpw_hash( $password, $stored_hash ) ) {
1827
1827
1828
            C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1828
            C4::Context->set_userenv( "$borrowernumber", $userid, $cardnumber,
1829
                $firstname, $surname, $branchcode, $branchname, $flags ) unless $no_set_userenv;
1829
                $firstname, $surname, $branchcode, $branchname ) unless $no_set_userenv;
1830
            return 1, $cardnumber, $userid;
1830
            return 1, $cardnumber, $userid;
1831
        }
1831
        }
1832
    }
1832
    }
1833
    $sth =
1833
    $sth =
1834
      $dbh->prepare(
1834
      $dbh->prepare(
1835
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname,flags from borrowers join branches on borrowers.branchcode=branches.branchcode where cardnumber=?"
1835
        "select password,cardnumber,borrowernumber,userid,firstname,surname,borrowers.branchcode,branches.branchname from borrowers join branches on borrowers.branchcode=branches.branchcode where cardnumber=?"
1836
      );
1836
      );
1837
    $sth->execute($userid);
1837
    $sth->execute($userid);
1838
    if ( $sth->rows ) {
1838
    if ( $sth->rows ) {
1839
        my ( $stored_hash, $cardnumber, $borrowernumber, $userid, $firstname,
1839
        my ( $stored_hash, $cardnumber, $borrowernumber, $userid, $firstname,
1840
            $surname, $branchcode, $branchname, $flags )
1840
            $surname, $branchcode, $branchname )
1841
          = $sth->fetchrow;
1841
          = $sth->fetchrow;
1842
1842
1843
        if ( checkpw_hash( $password, $stored_hash ) ) {
1843
        if ( checkpw_hash( $password, $stored_hash ) ) {
1844
1844
1845
            C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1845
            C4::Context->set_userenv( $borrowernumber, $userid, $cardnumber,
1846
                $firstname, $surname, $branchcode, $branchname, $flags ) unless $no_set_userenv;
1846
                $firstname, $surname, $branchcode, $branchname ) unless $no_set_userenv;
1847
            return 1, $cardnumber, $userid;
1847
            return 1, $cardnumber, $userid;
1848
        }
1848
        }
1849
    }
1849
    }
Lines 1867-1873 sub checkpw_hash { Link Here
1867
    # check what encryption algorithm was implemented: Bcrypt - if the hash starts with '$2' it is Bcrypt else md5
1867
    # check what encryption algorithm was implemented: Bcrypt - if the hash starts with '$2' it is Bcrypt else md5
1868
    my $hash;
1868
    my $hash;
1869
    if ( substr( $stored_hash, 0, 2 ) eq '$2' ) {
1869
    if ( substr( $stored_hash, 0, 2 ) eq '$2' ) {
1870
        $hash = hash_password( $password, $stored_hash );
1870
        $hash = Koha::AuthUtils::hash_password( $password, $stored_hash );
1871
    } else {
1871
    } else {
1872
        $hash = md5_base64($password);
1872
        $hash = md5_base64($password);
1873
    }
1873
    }
Lines 1875-1880 sub checkpw_hash { Link Here
1875
}
1875
}
1876
1876
1877
=head2 getuserflags
1877
=head2 getuserflags
1878
@DEPRECATED, USE THE Koha::Auth::PermissionManager
1878
1879
1879
    my $authflags = getuserflags($flags, $userid, [$dbh]);
1880
    my $authflags = getuserflags($flags, $userid, [$dbh]);
1880
1881
Lines 1887-1892 C<$authflags> is a hashref of permissions Link Here
1887
=cut
1888
=cut
1888
1889
1889
sub getuserflags {
1890
sub getuserflags {
1891
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
1890
    my $flags  = shift;
1892
    my $flags  = shift;
1891
    my $userid = shift;
1893
    my $userid = shift;
1892
    my $dbh    = @_ ? shift : C4::Context->dbh;
1894
    my $dbh    = @_ ? shift : C4::Context->dbh;
Lines 1898-1903 sub getuserflags { Link Here
1898
        no warnings 'numeric';
1900
        no warnings 'numeric';
1899
        $flags += 0;
1901
        $flags += 0;
1900
    }
1902
    }
1903
    return get_user_subpermissions($userid);
1904
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
1901
    my $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1905
    my $sth = $dbh->prepare("SELECT bit, flag, defaulton FROM userflags");
1902
    $sth->execute;
1906
    $sth->execute;
1903
1907
Lines 1921-1927 sub getuserflags { Link Here
1921
}
1925
}
1922
1926
1923
=head2 get_user_subpermissions
1927
=head2 get_user_subpermissions
1924
1928
@DEPRECATED, USE THE Koha::Auth::PermissionManager
1925
  $user_perm_hashref = get_user_subpermissions($userid);
1929
  $user_perm_hashref = get_user_subpermissions($userid);
1926
1930
1927
Given the userid (note, not the borrowernumber) of a staff user,
1931
Given the userid (note, not the borrowernumber) of a staff user,
Lines 1946-1966 necessary to check borrowers.flags. Link Here
1946
=cut
1950
=cut
1947
1951
1948
sub get_user_subpermissions {
1952
sub get_user_subpermissions {
1953
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
1949
    my $userid = shift;
1954
    my $userid = shift;
1950
1955
    return {} unless $userid;
1951
    my $dbh = C4::Context->dbh;
1952
    my $sth = $dbh->prepare( "SELECT flag, user_permissions.code
1953
                             FROM user_permissions
1954
                             JOIN permissions USING (module_bit, code)
1955
                             JOIN userflags ON (module_bit = bit)
1956
                             JOIN borrowers USING (borrowernumber)
1957
                             WHERE userid = ?" );
1958
    $sth->execute($userid);
1959
1956
1960
    my $user_perms = {};
1957
    my $user_perms = {};
1961
    while ( my $perm = $sth->fetchrow_hashref ) {
1958
    try {
1962
        $user_perms->{ $perm->{'flag'} }->{ $perm->{'code'} } = 1;
1959
        use Koha::Auth::PermissionManager;
1963
    }
1960
        my $permissionManager = Koha::Auth::PermissionManager->new();
1961
        my $borrowerPermissions = $permissionManager->getBorrowerPermissions($userid); #Prefetch all related tables.
1962
        foreach my $perm ( @$borrowerPermissions ) {
1963
            $user_perms->{ $perm->getPermissionModule->module }->{ $perm->getPermission->code } = 1;
1964
        }
1965
    } catch {
1966
        if (blessed($_) && $_->isa('Koha::Exception::UnknownObject')) {
1967
            return $user_perms;
1968
        }
1969
        elsif (blessed($_)) {
1970
            $_->rethrow();
1971
        }
1972
        else {
1973
            die $_;
1974
        }
1975
    };
1976
1964
    return $user_perms;
1977
    return $user_perms;
1965
}
1978
}
1966
1979
Lines 1977-1982 of the subpermission. Link Here
1977
=cut
1990
=cut
1978
1991
1979
sub get_all_subpermissions {
1992
sub get_all_subpermissions {
1993
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
1994
    use Koha::Auth::PermissionManager;
1995
    my $permissionManager = Koha::Auth::PermissionManager->new();
1996
    my $all_permissions = $permissionManager->listKohaPermissionsAsHASH();
1997
    foreach my $module ( keys %$all_permissions ) {
1998
        my $permissionModule = $all_permissions->{$module};
1999
        foreach my $code (keys %{$permissionModule->{permissions}}) {
2000
            my $permission = $permissionModule->{permissions}->{$code};
2001
            $all_permissions->{$module}->{$code} = $permission->{'description'};
2002
        }
2003
    }
2004
    return $all_permissions;
2005
2006
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
1980
    my $dbh = C4::Context->dbh;
2007
    my $dbh = C4::Context->dbh;
1981
    my $sth = $dbh->prepare( "SELECT flag, code
2008
    my $sth = $dbh->prepare( "SELECT flag, code
1982
                             FROM permissions
2009
                             FROM permissions
Lines 1991-1997 sub get_all_subpermissions { Link Here
1991
}
2018
}
1992
2019
1993
=head2 haspermission
2020
=head2 haspermission
1994
2021
@DEPRECATED, USE THE Koha::Auth::PermissionManager
1995
  $flags = ($userid, $flagsrequired);
2022
  $flags = ($userid, $flagsrequired);
1996
2023
1997
C<$userid> the userid of the member
2024
C<$userid> the userid of the member
Lines 2002-2018 Returns member's flags or 0 if a permission is not met. Link Here
2002
=cut
2029
=cut
2003
2030
2004
sub haspermission {
2031
sub haspermission {
2032
    #@DEPRECATED, USE THE Koha::Auth::PermissionManager
2005
    my ( $userid, $flagsrequired ) = @_;
2033
    my ( $userid, $flagsrequired ) = @_;
2006
    my $sth = C4::Context->dbh->prepare("SELECT flags FROM borrowers WHERE userid=?");
2034
2007
    $sth->execute($userid);
2035
    my $flags = getuserflags( undef, $userid );
2008
    my $row = $sth->fetchrow();
2036
    #Sanitate 1 to * because we no longer have 1's from the koha.borrowers.flags.
2009
    my $flags = getuserflags( $row, $userid );
2037
    foreach my $module (%$flagsrequired) {
2010
    if ( $userid eq C4::Context->config('user') ) {
2038
        $flagsrequired->{$module} = '*' if $flagsrequired->{$module} && $flagsrequired->{$module} eq '1';
2039
    }
2040
2041
    if ( defined $userid && $userid eq C4::Context->config('user') ) {
2011
2042
2012
        # Super User Account from /etc/koha.conf
2043
        # Super User Account from /etc/koha.conf
2013
        $flags->{'superlibrarian'} = 1;
2044
        $flags->{'superlibrarian'} = 1;
2014
    }
2045
    }
2015
    elsif ( $userid eq 'demo' && C4::Context->config('demo') ) {
2046
    elsif ( defined $userid && $userid eq 'demo' && C4::Context->config('demo') ) {
2016
2047
2017
        # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
2048
        # Demo user that can do "anything" (demo=1 in /etc/koha.conf)
2018
        $flags->{'superlibrarian'} = 1;
2049
        $flags->{'superlibrarian'} = 1;
Lines 2023-2029 sub haspermission { Link Here
2023
    foreach my $module ( keys %$flagsrequired ) {
2054
    foreach my $module ( keys %$flagsrequired ) {
2024
        my $subperm = $flagsrequired->{$module};
2055
        my $subperm = $flagsrequired->{$module};
2025
        if ( $subperm eq '*' ) {
2056
        if ( $subperm eq '*' ) {
2026
            return 0 unless ( $flags->{$module} == 1 or ref( $flags->{$module} ) );
2057
            return 0 unless ( ref( $flags->{$module} ) );
2027
        } else {
2058
        } else {
2028
            return 0 unless (
2059
            return 0 unless (
2029
                ( defined $flags->{$module} and
2060
                ( defined $flags->{$module} and
(-)a/Koha/Auth/BorrowerPermission.pm (+221 lines)
Line 0 Link Here
1
package Koha::Auth::BorrowerPermission;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
23
use Koha::Auth::BorrowerPermissions;
24
use Koha::Auth::PermissionModules;
25
use Koha::Auth::Permissions;
26
use Koha::Patrons;
27
28
use Koha::Exception::BadParameter;
29
30
use base qw(Koha::Object);
31
32
sub _type {
33
    return 'BorrowerPermission';
34
}
35
sub object_class {
36
    return 'Koha::Auth::BorrowerPermission';
37
}
38
39
=head NAME
40
41
Koha::Auth::BorrowerPermission
42
43
=head SYNOPSIS
44
45
Object representation of a Permission given to a Borrower.
46
47
=head new
48
49
    my $borrowerPermission = Koha::Auth::BorrowerPermission->new({
50
                                borrowernumber => 12,
51
                                permission_module_id => 2,
52
                                permission => $Koha::Auth::Permission,
53
    });
54
    my $borrowerPermission = Koha::Auth::BorrowerPermission->new({
55
                                borrower => $Koha::Patron,
56
                                permissionModule => $Koha::Auth::PermissionModule,
57
                                permission_id => 22,
58
    });
59
60
Remember to ->store() the returned object to persist it in the DB.
61
@PARAM1 HASHRef of constructor parameters:
62
            MANDATORY keys:
63
                borrower or borrowernumber
64
                permissionModule or permission_module_id
65
                permission or permission_id
66
            Values can be either Koha::Object derivatives or their respective DB primary keys
67
@RETURNS Koha::Auth::BorrowerPermission
68
=cut
69
70
sub new {
71
    my ($class, $params) = @_;
72
73
    _validateParams($params);
74
75
    #Check for duplicates, and update existing permission if available.
76
    my $self = Koha::Auth::BorrowerPermissions->find({borrowernumber => $params->{borrower}->borrowernumber,
77
                                                      permission_module_id => $params->{permissionModule}->permission_module_id,
78
                                                      permission_id => $params->{permission}->permission_id,
79
                                                    });
80
    $self = $class->SUPER::new() unless $self;
81
    $self->{params} = $params;
82
    $self->set({borrowernumber => $self->getBorrower()->borrowernumber,
83
                permission_id => $self->getPermission()->permission_id,
84
                permission_module_id => $self->getPermissionModule()->permission_module_id
85
                });
86
    return $self;
87
}
88
89
=head getBorrower
90
91
    my $borrower = $borrowerPermission->getBorrower();
92
93
@RETURNS Koha::Patron
94
=cut
95
96
sub getBorrower {
97
    my ($self) = @_;
98
99
    unless ($self->{params}->{borrower}) {
100
        my $dbix_borrower = $self->_result()->borrower;
101
        my $borrower = Koha::Patron->_new_from_dbic($dbix_borrower);
102
        $self->{params}->{borrower} = $borrower;
103
    }
104
    return $self->{params}->{borrower};
105
}
106
107
=head setBorrower
108
109
    my $borrowerPermission = $borrowerPermission->setBorrower( $borrower );
110
111
Set the Borrower.
112
When setting the DB is automatically updated as well.
113
@PARAM1 Koha::Patron, set the given Borrower to this BorrowerPermission.
114
@RETURNS Koha::Auth::BorrowerPermission,
115
=cut
116
117
sub setBorrower {
118
    my ($self, $borrower) = @_;
119
120
    unless (blessed($borrower) && $borrower->isa('Koha::Patron')) {
121
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."->setPermissionModule():> Given parameter '\\$borrower' is not a Koha::Patron-object!");
122
    }
123
    $self->{params}->{borrower} = $borrower;
124
    $self->set({borrowernumber => $borrower->borrowernumber()});
125
    $self->store();
126
}
127
128
=head getPermissionModule
129
130
    my $permissionModule = $borrowerPermission->getPermissionModule();
131
132
@RETURNS Koha::Auth::PermissionModule
133
=cut
134
135
sub getPermissionModule {
136
    my ($self) = @_;
137
138
    unless ($self->{params}->{permissionModule}) {
139
        my $dbix_object = $self->_result()->permission_module;
140
        my $object = Koha::Auth::PermissionModule->_new_from_dbic($dbix_object);
141
        $self->{params}->{permissionModule} = $object;
142
    }
143
    return $self->{params}->{permissionModule};
144
}
145
146
=head setPermissionModule
147
148
    my $borrowerPermission = $borrowerPermission->setPermissionModule( $permissionModule );
149
150
Set the PermissionModule.
151
When setting the DB is automatically updated as well.
152
@PARAM1 Koha::Auth::PermissionModule, set the given PermissionModule as
153
                                      the PermissionModule of this BorrowePermission.
154
@RETURNS Koha::Auth::BorrowerPermission,
155
=cut
156
157
sub setPermissionModule {
158
    my ($self, $permissionModule) = @_;
159
160
    unless (blessed($permissionModule) && $permissionModule->isa('Koha::Auth::PermissionModule')) {
161
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."->setPermissionModule():> Given parameter '\$permissionModule' is not a Koha::Auth::PermissionModule-object!");
162
    }
163
    $self->{params}->{permissionModule} = $permissionModule;
164
    $self->set({permission_module_id => $permissionModule->permission_module_id()});
165
    $self->store();
166
}
167
168
=head getPermission
169
170
    my $permission = $borrowerPermission->getPermission();
171
172
@RETURNS Koha::Auth::Permission
173
=cut
174
175
sub getPermission {
176
    my ($self) = @_;
177
178
    unless ($self->{params}->{permission}) {
179
        my $dbix_object = $self->_result()->permission;
180
        my $object = Koha::Auth::Permission->_new_from_dbic($dbix_object);
181
        $self->{params}->{permission} = $object;
182
    }
183
    return $self->{params}->{permission};
184
}
185
186
=head setPermission
187
188
    my $borrowerPermission = $borrowerPermission->setPermission( $permission );
189
190
Set the Permission.
191
When setting the DB is automatically updated as well.
192
@PARAM1 Koha::Auth::Permission, set the given Permission to this BorrowerPermission.
193
@RETURNS Koha::Auth::BorrowerPermission,
194
=cut
195
196
sub setPermission {
197
    my ($self, $permission) = @_;
198
199
    unless (blessed($permission) && $permission->isa('Koha::Auth::Permission')) {
200
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."->setPermission():> Given parameter '\$permission' is not a Koha::Auth::Permission-object!");
201
    }
202
    $self->{params}->{permission} = $permission;
203
    $self->set({permission_id => $permission->permission_id()});
204
    $self->store();
205
}
206
207
=head _validateParams
208
209
Validates the given constructor parameters and fetches the Koha::Objects when needed.
210
211
=cut
212
213
sub _validateParams {
214
    my ($params) = @_;
215
216
    $params->{permissionModule} = Koha::Auth::PermissionModules->cast( $params->{permission_module_id} || $params->{permissionModule} );
217
    $params->{permission} = Koha::Auth::Permissions->cast( $params->{permission_id} || $params->{permission} );
218
    $params->{borrower} = Koha::Patrons->cast(  $params->{borrowernumber} || $params->{borrower}  );
219
}
220
221
1;
(-)a/Koha/Auth/BorrowerPermissions.pm (+38 lines)
Line 0 Link Here
1
package Koha::Auth::BorrowerPermissions;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
23
use Koha::Auth::BorrowerPermission;
24
25
use base qw(Koha::Objects);
26
27
sub _type {
28
    return 'BorrowerPermission';
29
}
30
sub object_class {
31
    return 'Koha::Auth::BorrowerPermission';
32
}
33
34
sub _get_castable_unique_columns {
35
    return ['borrower_permission_id'];
36
}
37
38
1;
(-)a/Koha/Auth/Permission.pm (+60 lines)
Line 0 Link Here
1
package Koha::Auth::Permission;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Koha::Auth::Permissions;
23
24
use Koha::Exception::BadParameter;
25
26
use base qw(Koha::Object);
27
28
sub _type {
29
    return 'Permission';
30
}
31
sub object_class {
32
    return 'Koha::Auth::Permission';
33
}
34
35
sub new {
36
    my ($class, $params) = @_;
37
38
    _validateParams($params);
39
40
    my $self = Koha::Auth::Permissions->find({code => $params->{code}, module => $params->{module}});
41
    $self = $class->SUPER::new() unless $self;
42
    $self->set($params);
43
    return $self;
44
}
45
46
sub _validateParams {
47
    my ($params) = @_;
48
49
    unless ($params->{description} && length $params->{description} > 0) {
50
        Koha::Exception::BadParameter->throw(error => "Koha::Auth::Permission->new():> Parameter 'description' isn't defined or is empty.");
51
    }
52
    unless ($params->{module} && length $params->{module} > 0) {
53
        Koha::Exception::BadParameter->throw(error => "Koha::Auth::Permission->new():> Parameter 'module' isn't defined or is empty.");
54
    }
55
    unless ($params->{code} && length $params->{code} > 0) {
56
        Koha::Exception::BadParameter->throw(error => "Koha::Auth::Permission->new():> Parameter 'code' isn't defined or is empty.");
57
    }
58
}
59
60
1;
(-)a/Koha/Auth/PermissionManager.pm (+529 lines)
Line 0 Link Here
1
package Koha::Auth::PermissionManager;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
use Try::Tiny;
23
24
use Koha::Database;
25
use Koha::Auth::Permission;
26
use Koha::Auth::PermissionModule;
27
use Koha::Auth::BorrowerPermission;
28
use Koha::Auth::BorrowerPermissions;
29
30
use Koha::Exception::BadParameter;
31
use Koha::Exception::NoPermission;
32
use Koha::Exception::UnknownProgramState;
33
34
=head NAME Koha::Auth::PermissionManager
35
36
=head SYNOPSIS
37
38
PermissionManager is a gateway to all Koha's permission operations. You shouldn't
39
need to touch individual Koha::Auth::Permission* -objects.
40
41
=head USAGE
42
43
See t::db_dependent::Koha::Auth::PermissionManager.t
44
45
=head new
46
47
    my $permissionManager = Koha::Auth::PermissionManager->new();
48
49
Instantiates a new PemissionManager.
50
51
In the future this Manager can easily be improved with Koha::Cache.
52
53
=cut
54
55
sub new {
56
    my ($class, $self) = @_;
57
    $self = {} unless $self;
58
    bless($self, $class);
59
    return $self;
60
}
61
62
=head addPermission
63
64
    $permissionManager->addPermission({ code => "end_remaining_hostilities",
65
                                        description => "All your base are belong to us",
66
    });
67
68
INSERTs or UPDATEs a Koha::Auth::Permission to the Koha DB.
69
Very handy when introducing new features that need new permissions.
70
71
@PARAM1 Koha::Auth::Permission
72
        or
73
        HASHRef of all the koha.permissions-table columns set.
74
@THROWS Koha::Exception::BadParameter
75
=cut
76
77
sub addPermission {
78
    my ($self, $permission) = @_;
79
    if (blessed($permission) && not($permission->isa('Koha::Auth::Permission'))) {
80
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."::addPermission():> Given permission is not a Koha::Auth::Permission-object.");
81
    }
82
    elsif (ref($permission) eq 'HASH') {
83
        $permission = Koha::Auth::Permission->new($permission);
84
    }
85
    unless (blessed($permission)) {
86
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."::addPermission():> Given permission '$permission' is not of a recognized format.");
87
    }
88
89
    $permission->store();
90
}
91
92
=head getPermission
93
94
    my $permission = $permissionManager->getPermission('edit_items'); #koha.permissions.code
95
    my $permission = $permissionManager->getPermission(12);           #koha.permissions.permission_id
96
    my $permission = $permissionManager->getPermission($dbix_Permission); #Koha::Schema::Result::Permission
97
98
@RETURNS Koha::Auth::Permission-object
99
@THROWS Koha::Exception::BadParameter
100
=cut
101
102
sub getPermission {
103
    my ($self, $permissionId) = @_;
104
105
    try {
106
        return Koha::Auth::Permissions->cast($permissionId);
107
    } catch {
108
        if (blessed($_) && $_->isa('Koha::Exception::UnknownObject')) {
109
            #We catch this type of exception, and simply return nothing, since there was no such Permission
110
        }
111
        else {
112
            die $_;
113
        }
114
    };
115
}
116
117
=head delPermission
118
119
    $permissionManager->delPermission('edit_items'); #koha.permissions.code
120
    $permissionManager->delPermission(12);           #koha.permissions.permission_id
121
    $permissionManager->delPermission($dbix_Permission); #Koha::Schema::Result::Permission
122
    $permissionManager->delPermission($permission); #Koha::Auth::Permission
123
124
@THROWS Koha::Exception::UnknownObject if no given object in DB to delete.
125
=cut
126
127
sub delPermission {
128
    my ($self, $permissionId) = @_;
129
130
    my $permission = Koha::Auth::Permissions->cast($permissionId);
131
    $permission->delete();
132
}
133
134
=head addPermissionModule
135
136
    $permissionManager->addPermissionModule({   module => "scotland",
137
                                                description => "William Wallace is my hero!",
138
    });
139
140
INSERTs or UPDATEs a Koha::Auth::PermissionModule to the Koha DB.
141
Very handy when introducing new features that need new permissions.
142
143
@PARAM1 Koha::Auth::PermissionModule
144
        or
145
        HASHRef of all the koha.permission_modules-table columns set.
146
@THROWS Koha::Exception::BadParameter
147
=cut
148
149
sub addPermissionModule {
150
    my ($self, $permissionModule) = @_;
151
    if (blessed($permissionModule) && not($permissionModule->isa('Koha::Auth::PermissionModule'))) {
152
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."::addPermission():> Given permissionModule is not a Koha::Auth::PermissionModule-object.");
153
    }
154
    elsif (ref($permissionModule) eq 'HASH') {
155
        $permissionModule = Koha::Auth::PermissionModule->new($permissionModule);
156
    }
157
    unless (blessed($permissionModule)) {
158
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."::addPermission():> Given permissionModule '$permissionModule' is not of a recognized format.");
159
    }
160
161
    $permissionModule->store();
162
}
163
164
=head getPermissionModule
165
166
    my $permission = $permissionManager->getPermissionModule('cataloguing'); #koha.permission_modules.module
167
    my $permission = $permissionManager->getPermission(12);           #koha.permission_modules.permission_module_id
168
    my $permission = $permissionManager->getPermission($dbix_Permission); #Koha::Schema::Result::PermissionModule
169
170
@RETURNS Koha::Auth::PermissionModule-object
171
@THROWS Koha::Exception::BadParameter
172
=cut
173
174
sub getPermissionModule {
175
    my ($self, $permissionModuleId) = @_;
176
177
    try {
178
        return Koha::Auth::PermissionModules->cast($permissionModuleId);
179
    } catch {
180
        if (blessed($_) && $_->isa('Koha::Exception::UnknownObject')) {
181
            #We catch this type of exception, and simply return nothing, since there was no such PermissionModule
182
        }
183
        else {
184
            die $_;
185
        }
186
    };
187
}
188
189
=head delPermissionModule
190
191
    $permissionManager->delPermissionModule('cataloguing'); #koha.permission_modules.module
192
    $permissionManager->delPermissionModule(12);           #koha.permission_modules.permission_module_id
193
    $permissionManager->delPermissionModule($dbix_Permission); #Koha::Schema::Result::PermissionModule
194
    $permissionManager->delPermissionModule($permissionModule); #Koha::Auth::PermissionModule
195
196
@THROWS Koha::Exception::UnknownObject if no given object in DB to delete.
197
@THROWS Koha::Exception::BadParameter
198
=cut
199
200
sub delPermissionModule {
201
    my ($self, $permissionModuleId) = @_;
202
203
    my $permissionModule = Koha::Auth::PermissionModules->cast($permissionModuleId);
204
    $permissionModule->delete();
205
}
206
207
=head getKohaPermissions
208
209
    my $kohaPermissions = $permissionManager->getKohaPermissions();
210
211
Gets all the PermissionModules and their related Permissions in one huge DB query.
212
@RETURNS ARRAYRef of Koha::Auth::PermissionModule-objects with related objects prefetched.
213
=cut
214
215
sub getKohaPermissions {
216
    my ($self) = @_;
217
218
    my $schema = Koha::Database->new()->schema();
219
    my @permissionModules = $schema->resultset('PermissionModule')->search(
220
                                                            {},
221
                                                            {   join => ['permissions'],
222
                                                                prefetch => ['permissions'],
223
                                                                order_by => ['me.module', 'permissions.code'],
224
                                                            }
225
                                                        );
226
    #Cast DBIx to Koha::Object.
227
    for (my $i=0 ; $i<scalar(@permissionModules) ; $i++) {
228
        $permissionModules[$i] = Koha::Auth::PermissionModules->cast( $permissionModules[$i] );
229
    }
230
    return \@permissionModules;
231
}
232
233
=head listKohaPermissionsAsHASH
234
235
@RETURNS HASHRef, a HASH-representation of all the permissions and permission modules
236
in Koha. Eg:
237
                 {
238
                    acquisitions => {
239
                        description => "Yada yada",
240
                        module => 'acquisitions',
241
                        permission_module_id => 21,
242
                        permissions => {
243
                            budget_add_del => {
244
                                description => "More yada yada",
245
                                code => 'budget_add_del',
246
                                permission_id => 12,
247
                            }
248
                            budget_manage => {
249
                                description => "Yaawn yadayawn",
250
                                ...
251
                            }
252
                            ...
253
                        }
254
                    },
255
                    borrowers => {
256
                        ...
257
                    },
258
                    ...
259
                 }
260
=cut
261
262
sub listKohaPermissionsAsHASH {
263
    my ($self) = @_;
264
    my $permissionModules = $self->getKohaPermissions();
265
    my $hash = {};
266
267
    foreach my $permissionModule (sort {$a->module cmp $b->module} @$permissionModules) {
268
        my $module = $permissionModule->module;
269
270
        $hash->{$module} = $permissionModule->_result->{'_column_data'};
271
        $hash->{$module}->{permissions} = {};
272
273
        my $permissions = $permissionModule->getPermissions;
274
        foreach my $permission (sort {$a->code cmp $b->code} @$permissions) {
275
            my $code = $permission->code;
276
277
            $hash->{$module}->{permissions}->{$code} = $permission->_result->{'_column_data'};
278
        }
279
    }
280
    return $hash;
281
}
282
283
=head getBorrowerPermissions
284
285
    my $borrowerPermissions = $permissionManager->getBorrowerPermissions($borrower);     #Koha::Patron
286
    my $borrowerPermissions = $permissionManager->getBorrowerPermissions($dbix_borrower);#Koha::Schema::Resultset::Borrower
287
    my $borrowerPermissions = $permissionManager->getBorrowerPermissions(1012);          #koha.borrowers.borrowernumber
288
    my $borrowerPermissions = $permissionManager->getBorrowerPermissions('167A0012311'); #koha.borrowers.cardnumber
289
    my $borrowerPermissions = $permissionManager->getBorrowerPermissions('bill69');      #koha.borrowers.userid
290
291
@RETURNS ARRAYRef of Koha::Auth::BorrowerPermission-objects
292
@THROWS Koha::Exception::UnknownObject, if the given $borrower cannot be casted to Koha::Patron
293
@THROWS Koha::Exception::BadParameter
294
=cut
295
296
sub getBorrowerPermissions {
297
    my ($self, $borrower) = @_;
298
    $borrower = Koha::Patrons->cast($borrower);
299
300
    if ($borrower->isSuperuser()) {
301
        return [Koha::Auth::BorrowerPermission->new({borrower => $borrower, permission => 'superlibrarian', permissionModule => 'superlibrarian'})];
302
    }
303
304
    my $schema = Koha::Database->new()->schema();
305
306
    my @borrowerPermissions = $schema->resultset('BorrowerPermission')->search({borrowernumber => $borrower->borrowernumber},
307
                                                                               {join => ['permission','permission_module'],
308
                                                                                prefetch => ['permission','permission_module'],
309
                                                                                order_by => ['permission_module.module', 'permission.code']});
310
    for (my $i=0 ; $i<scalar(@borrowerPermissions) ; $i++) {
311
        $borrowerPermissions[$i] = Koha::Auth::BorrowerPermissions->cast($borrowerPermissions[$i]);
312
    }
313
    return \@borrowerPermissions;
314
}
315
316
=head grantPermissions
317
318
    $permissionManager->grantPermissions($borrower, {borrowers => 'view_borrowers',
319
                                                     reserveforothers => ['place_holds'],
320
                                                     tools => ['edit_news', 'edit_notices'],
321
                                                     acquisition => {
322
                                                       budger_add_del => 1,
323
                                                       budget_modify => 1,
324
                                                     },
325
                                                    }
326
                                        );
327
328
Adds a group of permissions to one user.
329
@THROWS Koha::Exception::UnknownObject, if the given $borrower cannot be casted to Koha::Patron
330
@THROWS Koha::Exception::BadParameter
331
=cut
332
333
sub grantPermissions {
334
    my ($self, $borrower, $permissionsGroup) = @_;
335
336
    while (my ($module, $permissions) = each(%$permissionsGroup)) {
337
        if (ref($permissions) eq 'ARRAY') {
338
            foreach my $permission (@$permissions) {
339
                $self->grantPermission($borrower, $module, $permission);
340
            }
341
        }
342
        elsif (ref($permissions) eq 'HASH') {
343
            foreach my $permission (keys(%$permissions)) {
344
                $self->grantPermission($borrower, $module, $permission);
345
            }
346
        }
347
        else {
348
            $self->grantPermission($borrower, $module, $permissions);
349
        }
350
    }
351
}
352
353
=head grantPermission
354
355
    my $borrowerPermission = $permissionManager->grantPermission($borrower, $permissionModule, $permission);
356
357
@PARAM1 Koha::Patron or
358
        Scalar koha.borrowers.borrowernumber or
359
        Scalar koha.borrowers.cardnumber or
360
        Scalar koha.borrowers.userid or
361
@PARAM2 Koha::Auth::PermissionModule-object
362
        Scalar koha.permission_modules.module or
363
        Scalar koha.permission_modules.permission_module_id
364
@PARAM3 Koha::Auth::Permission-object or
365
        Scalar koha.permissions.code or
366
        Scalar koha.permissions.permission_id
367
@RETURNS Koha::Auth::BorrowerPermissions
368
@THROWS Koha::Exception::UnknownObject, if the given parameters cannot be casted to Koha::Object-subclasses
369
@THROWS Koha::Exception::BadParameter
370
=cut
371
372
sub grantPermission {
373
    my ($self, $borrower, $permissionModule, $permission) = @_;
374
375
    my $borrowerPermission = Koha::Auth::BorrowerPermission->new({borrower => $borrower, permissionModule => $permissionModule, permission => $permission});
376
    $borrowerPermission->store();
377
    return $borrowerPermission;
378
}
379
380
=head
381
382
    $permissionManager->revokePermission($borrower, $permissionModule, $permission);
383
384
Revokes a Permission from a Borrower
385
same parameters as grantPermission()
386
387
@THROWS Koha::Exception::UnknownObject, if the given parameters cannot be casted to Koha::Object-subclasses
388
@THROWS Koha::Exception::BadParameter
389
=cut
390
391
sub revokePermission {
392
    my ($self, $borrower, $permissionModule, $permission) = @_;
393
394
    my $borrowerPermission = Koha::Auth::BorrowerPermission->new({borrower => $borrower, permissionModule => $permissionModule, permission => $permission});
395
    $borrowerPermission->delete();
396
    return $borrowerPermission;
397
}
398
399
=head revokeAllPermissions
400
401
    $permissionManager->revokeAllPermissions($borrower);
402
403
@THROWS Koha::Exception::UnknownObject, if the given $borrower cannot be casted to Koha::Patron
404
@THROWS Koha::Exception::BadParameter
405
=cut
406
407
sub revokeAllPermissions {
408
    my ($self, $borrower) = @_;
409
    $borrower = Koha::Patrons->cast($borrower);
410
411
    my $schema = Koha::Database->new()->schema();
412
    $schema->resultset('BorrowerPermission')->search({borrowernumber => $borrower->borrowernumber})->delete_all();
413
}
414
415
=head hasPermissions
416
417
See if the given Borrower has all of the given permissions
418
@PARAM1 Koha::Patron, or any of the koha.borrowers-table's unique identifiers.
419
@PARAM2 HASHRef of needed permissions,
420
    {
421
        borrowers => 'view_borrowers',
422
        reserveforothers => ['place_holds'],
423
        tools => ['edit_news', 'edit_notices'],
424
        acquisition => {
425
            budger_add_del => 1,
426
            budget_modify => 1,
427
        },
428
        coursereserves => '*', #Means any Permission under this PermissionModule
429
   }
430
@RETURNS see hasPermission()
431
@THROWS Koha::Exception::NoPermission, from hasPermission() if permission is missing.
432
=cut
433
434
sub hasPermissions {
435
    my ($self, $borrower, $requiredPermissions) = @_;
436
437
    foreach my $module (keys(%$requiredPermissions)) {
438
        my $permissions = $requiredPermissions->{$module};
439
        if (ref($permissions) eq 'ARRAY') {
440
            foreach my $permission (@$permissions) {
441
                $self->hasPermission($borrower, $module, $permission);
442
            }
443
        }
444
        elsif (ref($permissions) eq 'HASH') {
445
            foreach my $permission (keys(%$permissions)) {
446
                $self->hasPermission($borrower, $module, $permission);
447
            }
448
        }
449
        else {
450
            $self->hasPermission($borrower, $module, $permissions);
451
        }
452
    }
453
    return 1;
454
}
455
456
=head hasPermission
457
458
See if the given Borrower has the given permission
459
@PARAM1 Koha::Patron, or any of the koha.borrowers-table's unique identifiers.
460
@PARAM2 Koha::Auth::PermissionModule or koha.permission_modules.module or koha.permission_modules.permission_module_id
461
@PARAM3 Koha::Auth::Permission or koha.permissions.code or koha.permissions.permission_id or
462
                               '*' if we just need any permission for the given PermissionModule.
463
@RETURNS Integer, 1 if permission check succeeded.
464
                  2 if user is a superlibrarian.
465
                  Catch Exceptions if permission check fails.
466
@THROWS Koha::Exception::NoPermission, if Borrower is missing the permission.
467
                                       Exception tells which permission is missing.
468
@THROWS Koha::Exception::UnknownObject, if the given parameters cannot be casted to Koha::Object-subclasses
469
@THROWS Koha::Exception::BadParameter
470
=cut
471
472
sub hasPermission {
473
    my ($self, $borrower, $permissionModule, $permission) = @_;
474
475
    $borrower = Koha::Patrons->cast($borrower);
476
    $permissionModule = Koha::Auth::PermissionModules->cast($permissionModule);
477
    $permission = Koha::Auth::Permissions->cast($permission) unless $permission eq '*';
478
479
    my $error;
480
    if ($permission eq '*') {
481
        my $borrowerPermission = Koha::Auth::BorrowerPermissions->search({borrowernumber => $borrower->borrowernumber,
482
                                                 permission_module_id => $permissionModule->permission_module_id,
483
                                                })->next();
484
        return 1 if ($borrowerPermission);
485
        $error = "Borrower '".$borrower->borrowernumber."' lacks any permission under permission module '".$permissionModule->module."'.";
486
    }
487
    else {
488
        my $borrowerPermission = Koha::Auth::BorrowerPermissions->search({borrowernumber => $borrower->borrowernumber,
489
                                                 permission_module_id => $permissionModule->permission_module_id,
490
                                                 permission_id => $permission->permission_id,
491
                                                })->next();
492
        return 1 if ($borrowerPermission);
493
        $error = "Borrower '".$borrower->borrowernumber."' lacks permission module '".$permissionModule->module."' and permission '".$permission->code."'.";
494
    }
495
496
    return 2 if not($permissionModule->module eq 'superlibrarian') && $self->_isSuperuser($borrower);
497
    return 2 if not($permissionModule->module eq 'superlibrarian') && $self->_isSuperlibrarian($borrower);
498
    Koha::Exception::NoPermission->throw(error => $error);
499
}
500
501
sub _isSuperuser {
502
    my ($self, $borrower) = @_;
503
    $borrower = Koha::Patrons->cast($borrower);
504
505
    if ( $borrower->userid && $borrower->userid eq C4::Context->config('user') ) {
506
        return 1;
507
    }
508
    elsif ( $borrower->userid && $borrower->userid eq 'demo' && C4::Context->config('demo') ) {
509
        return 1;
510
    }
511
    return 0;
512
}
513
514
sub _isSuperlibrarian {
515
    my ($self, $borrower) = @_;
516
517
    try {
518
        return $self->hasPermission($borrower, 'superlibrarian', 'superlibrarian');
519
    } catch {
520
        if (blessed($_) && $_->isa('Koha::Exception::NoPermission')) {
521
            return 0;
522
        }
523
        else {
524
            die $_;
525
        }
526
    };
527
}
528
529
1;
(-)a/Koha/Auth/PermissionModule.pm (+78 lines)
Line 0 Link Here
1
package Koha::Auth::PermissionModule;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Koha::Auth::PermissionModules;
23
24
use Koha::Exception::BadParameter;
25
26
use base qw(Koha::Object);
27
28
sub _type {
29
    return 'PermissionModule';
30
}
31
sub object_class {
32
    return 'Koha::Auth::PermissionModule';
33
}
34
35
sub new {
36
    my ($class, $params) = @_;
37
38
    _validateParams($params);
39
40
    my $self = Koha::Auth::PermissionModules->find({module => $params->{module}});
41
    $self = $class->SUPER::new() unless $self;
42
    $self->set($params);
43
    return $self;
44
}
45
46
sub _validateParams {
47
    my ($params) = @_;
48
49
    unless ($params->{description} && length $params->{description} > 0) {
50
        Koha::Exception::BadParameter->throw(error => "Koha::Auth::Permission->new():> Parameter 'description' isn't defined or is empty.");
51
    }
52
    unless ($params->{module} && length $params->{module} > 0) {
53
        Koha::Exception::BadParameter->throw(error => "Koha::Auth::Permission->new():> Parameter 'module' isn't defined or is empty.");
54
    }
55
}
56
57
=head getPermissions
58
59
    my $permissions = $permissionModule->getPermissions();
60
61
@RETURNS List of Koha::Auth::Permission-objects
62
=cut
63
64
sub getPermissions {
65
    my ($self) = @_;
66
67
    unless ($self->{params}->{permissions}) {
68
        $self->{params}->{permissions} = [];
69
        my @dbix_objects = $self->_result()->permissions;
70
        foreach my $dbix_object (@dbix_objects) {
71
            my $object = Koha::Auth::Permission->_new_from_dbic($dbix_object);
72
            push @{$self->{params}->{permissions}}, $object;
73
        }
74
    }
75
    return $self->{params}->{permissions};
76
}
77
78
1;
(-)a/Koha/Auth/PermissionModules.pm (+38 lines)
Line 0 Link Here
1
package Koha::Auth::PermissionModules;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
23
use Koha::Auth::PermissionModule;
24
25
use base qw(Koha::Objects);
26
27
sub _type {
28
    return 'PermissionModule';
29
}
30
sub object_class {
31
    return 'Koha::Auth::PermissionModule';
32
}
33
34
sub _get_castable_unique_columns {
35
    return ['permission_module_id', 'module'];
36
}
37
38
1;
(-)a/Koha/Auth/Permissions.pm (+42 lines)
Line 0 Link Here
1
package Koha::Auth::Permissions;
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
23
use Koha::Auth::Permission;
24
25
use Koha::Exception::BadParameter;
26
use Koha::Exception::UnknownObject;
27
28
use base qw(Koha::Objects);
29
30
sub _type {
31
    return 'Permission';
32
}
33
34
sub object_class {
35
    return 'Koha::Auth::Permission';
36
}
37
38
sub _get_castable_unique_columns {
39
    return ['permission_id', 'code'];
40
}
41
42
1;
(-)a/Koha/AuthUtils.pm (-1 / +63 lines)
Lines 25-30 use List::MoreUtils qw/ any /; Link Here
25
25
26
use Koha::Patron;
26
use Koha::Patron;
27
27
28
use Koha::Exception::LoginFailed;
29
28
use base 'Exporter';
30
use base 'Exporter';
29
31
30
our @EXPORT_OK   = qw(hash_password get_script_name);
32
our @EXPORT_OK   = qw(hash_password get_script_name);
Lines 154-159 sub get_script_name { Link Here
154
    }
156
    }
155
}
157
}
156
158
159
=head checkHash
160
161
    my $passwordOk = Koha::AuthUtils::checkHash($password1, $password2)
162
163
Checks if a clear-text String/password matches the given hash when
164
MD5 or Bcrypt hashing algorith is applied to it.
165
166
Bcrypt is applied if @PARAM2 starts with '$2'
167
MD5 otherwise
168
169
@PARAM1 String, clear text passsword or any other String
170
@PARAM2 String, hashed text password or any other String.
171
@RETURN Boolean, 1 if given parameters match
172
               , 0 if not
173
=cut
174
175
sub checkHash {
176
    my ( $password, $stored_hash ) = @_;
177
178
    $password = Encode::encode( 'UTF-8', $password )
179
            if Encode::is_utf8($password);
180
181
    return if $stored_hash eq '!';
182
183
    my $hash;
184
    if ( substr( $stored_hash, 0, 2 ) eq '$2' ) {
185
        $hash = hash_password( $password, $stored_hash );
186
    } else {
187
        #@DEPRECATED Digest::MD5, don't use it or you will get hurt.
188
        require Digest::MD5;
189
        $hash = Digest::MD5::md5_base64($password);
190
    }
191
    return $hash eq $stored_hash;
192
}
193
194
=head checkKohaSuperuser
195
196
    my $patron = Koha::AuthUtils::checkKohaSuperuser($userid, $password);
197
198
Check if the userid and password match the ones in the $KOHA_CONF
199
@PARAM1 String, user identifier, either the koha.borrowers.userid, or koha.borrowers.cardnumber
200
@PARAM2 String, clear text password from the authenticating user
201
@RETURNS Koha::Patron branded as superuser with ->isSuperuser()
202
         or undef if user logging in is not a superuser.
203
@THROWS Koha::Exception::LoginFailed if user identifier matches, but password doesn't
204
=cut
205
206
sub checkKohaSuperuser {
207
    my ($userid, $password) = @_;
208
209
    if ( $userid && $userid eq C4::Context->config('user') ) {
210
        if ( $password && $password eq C4::Context->config('pass') ) {
211
            return _createTemporarySuperuser();
212
        }
213
        else {
214
            Koha::Exception::LoginFailed->throw(error => "Password authentication failed");
215
        }
216
    }
217
}
218
219
157
=head checkKohaSuperuserFromUserid
220
=head checkKohaSuperuserFromUserid
158
See checkKohaSuperuser(), with only the "user identifier"-@PARAM.
221
See checkKohaSuperuser(), with only the "user identifier"-@PARAM.
159
@THROWS nothing.
222
@THROWS nothing.
Lines 184-190 sub _createTemporarySuperuser { Link Here
184
                       firstname  => $superuserName,
247
                       firstname  => $superuserName,
185
                       surname    => $superuserName,
248
                       surname    => $superuserName,
186
                       branchcode => 'NO_LIBRARY_SET',
249
                       branchcode => 'NO_LIBRARY_SET',
187
                       flags      => 1,
188
                       email      => C4::Context->preference('KohaAdminEmailAddress')
250
                       email      => C4::Context->preference('KohaAdminEmailAddress')
189
                    });
251
                    });
190
    return $patron;
252
    return $patron;
(-)a/Koha/Patron.pm (+26 lines)
Lines 638-643 sub _type { Link Here
638
    return 'Borrower';
638
    return 'Borrower';
639
}
639
}
640
640
641
=head isSuperuser
642
643
    $borrower->isSuperuser(1); #Set this borrower to be a superuser
644
    if ($borrower->isSuperuser()) {
645
        #All your base are belong to us
646
    }
647
648
Should be used from the authentication modules to mark this $borrower-object to
649
have unlimited access to all Koha-features.
650
This $borrower-object is the Koha DB user.
651
@PARAM1 Integer, 1 means this borrower is the super/DB user.
652
                "0" disables the previously set superuserness.
653
=cut
654
655
sub isSuperuser {
656
    my ($self, $Iam) = @_;
657
658
    if (defined $Iam && $Iam == 1) {
659
        $self->{superuser} = 1;
660
    }
661
    elsif (defined $Iam && $Iam eq "0") { #Dealing with zero is special in Perl
662
        $self->{superuser} = undef;
663
    }
664
    return (exists($self->{superuser}) && $self->{superuser}) ? 1 : undef;
665
}
666
641
=head1 AUTHOR
667
=head1 AUTHOR
642
668
643
Kyle M Hall <kyle@bywatersolutions.com>
669
Kyle M Hall <kyle@bywatersolutions.com>
(-)a/Koha/Schema/Result/Borrower.pm (-24 / +30 lines)
Lines 52-59 __PACKAGE__->table("borrowers"); Link Here
52
52
53
=head2 othernames
53
=head2 othernames
54
54
55
  data_type: 'mediumtext'
55
  data_type: 'varchar'
56
  is_nullable: 1
56
  is_nullable: 1
57
  size: 50
57
58
58
=head2 initials
59
=head2 initials
59
60
Lines 297-307 __PACKAGE__->table("borrowers"); Link Here
297
  is_nullable: 1
298
  is_nullable: 1
298
  size: 60
299
  size: 60
299
300
300
=head2 flags
301
302
  data_type: 'integer'
303
  is_nullable: 1
304
305
=head2 userid
301
=head2 userid
306
302
307
  data_type: 'varchar'
303
  data_type: 'varchar'
Lines 446-452 __PACKAGE__->add_columns( Link Here
446
  "title",
442
  "title",
447
  { data_type => "mediumtext", is_nullable => 1 },
443
  { data_type => "mediumtext", is_nullable => 1 },
448
  "othernames",
444
  "othernames",
449
  { data_type => "mediumtext", is_nullable => 1 },
445
  { data_type => "varchar", is_nullable => 1, size => 50 },
450
  "initials",
446
  "initials",
451
  { data_type => "text", is_nullable => 1 },
447
  { data_type => "text", is_nullable => 1 },
452
  "streetnumber",
448
  "streetnumber",
Lines 563-570 __PACKAGE__->add_columns( Link Here
563
  { data_type => "varchar", is_nullable => 1, size => 1 },
559
  { data_type => "varchar", is_nullable => 1, size => 1 },
564
  "password",
560
  "password",
565
  { data_type => "varchar", is_nullable => 1, size => 60 },
561
  { data_type => "varchar", is_nullable => 1, size => 60 },
566
  "flags",
567
  { data_type => "integer", is_nullable => 1 },
568
  "userid",
562
  "userid",
569
  { data_type => "varchar", is_nullable => 1, size => 75 },
563
  { data_type => "varchar", is_nullable => 1, size => 75 },
570
  "opacnote",
564
  "opacnote",
Lines 651-656 __PACKAGE__->set_primary_key("borrowernumber"); Link Here
651
645
652
__PACKAGE__->add_unique_constraint("cardnumber", ["cardnumber"]);
646
__PACKAGE__->add_unique_constraint("cardnumber", ["cardnumber"]);
653
647
648
=head2 C<othernames_4>
649
650
=over 4
651
652
=item * L</othernames>
653
654
=back
655
656
=cut
657
658
__PACKAGE__->add_unique_constraint("othernames_4", ["othernames"]);
659
654
=head2 C<userid>
660
=head2 C<userid>
655
661
656
=over 4
662
=over 4
Lines 830-835 __PACKAGE__->has_many( Link Here
830
  { cascade_copy => 0, cascade_delete => 0 },
836
  { cascade_copy => 0, cascade_delete => 0 },
831
);
837
);
832
838
839
=head2 borrower_permissions
840
841
Type: has_many
842
843
Related object: L<Koha::Schema::Result::BorrowerPermission>
844
845
=cut
846
847
__PACKAGE__->has_many(
848
  "borrower_permissions",
849
  "Koha::Schema::Result::BorrowerPermission",
850
  { "foreign.borrowernumber" => "self.borrowernumber" },
851
  { cascade_copy => 0, cascade_delete => 0 },
852
);
853
833
=head2 branchcode
854
=head2 branchcode
834
855
835
Type: belongs_to
856
Type: belongs_to
Lines 1255-1275 __PACKAGE__->has_many( Link Here
1255
  { cascade_copy => 0, cascade_delete => 0 },
1276
  { cascade_copy => 0, cascade_delete => 0 },
1256
);
1277
);
1257
1278
1258
=head2 user_permissions
1259
1260
Type: has_many
1261
1262
Related object: L<Koha::Schema::Result::UserPermission>
1263
1264
=cut
1265
1266
__PACKAGE__->has_many(
1267
  "user_permissions",
1268
  "Koha::Schema::Result::UserPermission",
1269
  { "foreign.borrowernumber" => "self.borrowernumber" },
1270
  { cascade_copy => 0, cascade_delete => 0 },
1271
);
1272
1273
=head2 virtualshelfcontents
1279
=head2 virtualshelfcontents
1274
1280
1275
Type: has_many
1281
Type: has_many
(-)a/Koha/Schema/Result/BorrowerPermission.pm (+149 lines)
Line 0 Link Here
1
use utf8;
2
package Koha::Schema::Result::BorrowerPermission;
3
4
# Created by DBIx::Class::Schema::Loader
5
# DO NOT MODIFY THE FIRST PART OF THIS FILE
6
7
=head1 NAME
8
9
Koha::Schema::Result::BorrowerPermission
10
11
=cut
12
13
use strict;
14
use warnings;
15
16
use base 'DBIx::Class::Core';
17
18
=head1 TABLE: C<borrower_permissions>
19
20
=cut
21
22
__PACKAGE__->table("borrower_permissions");
23
24
=head1 ACCESSORS
25
26
=head2 borrower_permission_id
27
28
  data_type: 'integer'
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 borrowernumber
33
34
  data_type: 'integer'
35
  is_foreign_key: 1
36
  is_nullable: 0
37
38
=head2 permission_module_id
39
40
  data_type: 'integer'
41
  is_foreign_key: 1
42
  is_nullable: 0
43
44
=head2 permission_id
45
46
  data_type: 'integer'
47
  is_foreign_key: 1
48
  is_nullable: 0
49
50
=cut
51
52
__PACKAGE__->add_columns(
53
  "borrower_permission_id",
54
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
55
  "borrowernumber",
56
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
57
  "permission_module_id",
58
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
59
  "permission_id",
60
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
61
);
62
63
=head1 PRIMARY KEY
64
65
=over 4
66
67
=item * L</borrower_permission_id>
68
69
=back
70
71
=cut
72
73
__PACKAGE__->set_primary_key("borrower_permission_id");
74
75
=head1 UNIQUE CONSTRAINTS
76
77
=head2 C<borrowernumber>
78
79
=over 4
80
81
=item * L</borrowernumber>
82
83
=item * L</permission_module_id>
84
85
=item * L</permission_id>
86
87
=back
88
89
=cut
90
91
__PACKAGE__->add_unique_constraint(
92
  "borrowernumber",
93
  ["borrowernumber", "permission_module_id", "permission_id"],
94
);
95
96
=head1 RELATIONS
97
98
=head2 borrowernumber
99
100
Type: belongs_to
101
102
Related object: L<Koha::Schema::Result::Borrower>
103
104
=cut
105
106
__PACKAGE__->belongs_to(
107
  "borrowernumber",
108
  "Koha::Schema::Result::Borrower",
109
  { borrowernumber => "borrowernumber" },
110
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
111
);
112
113
=head2 permission
114
115
Type: belongs_to
116
117
Related object: L<Koha::Schema::Result::Permission>
118
119
=cut
120
121
__PACKAGE__->belongs_to(
122
  "permission",
123
  "Koha::Schema::Result::Permission",
124
  { permission_id => "permission_id" },
125
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
126
);
127
128
=head2 permission_module
129
130
Type: belongs_to
131
132
Related object: L<Koha::Schema::Result::PermissionModule>
133
134
=cut
135
136
__PACKAGE__->belongs_to(
137
  "permission_module",
138
  "Koha::Schema::Result::PermissionModule",
139
  { permission_module_id => "permission_module_id" },
140
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
141
);
142
143
144
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2015-08-03 18:53:48
145
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oeu9FDU0R/YXazuSik1yfA
146
147
148
# You can replace this text with custom code or comments, and it will be preserved on regeneration
149
1;
(-)a/Koha/Schema/Result/Deletedborrower.pm (-7 lines)
Lines 295-305 __PACKAGE__->table("deletedborrowers"); Link Here
295
  is_nullable: 1
295
  is_nullable: 1
296
  size: 60
296
  size: 60
297
297
298
=head2 flags
299
300
  data_type: 'integer'
301
  is_nullable: 1
302
303
=head2 userid
298
=head2 userid
304
299
305
  data_type: 'varchar'
300
  data_type: 'varchar'
Lines 548-555 __PACKAGE__->add_columns( Link Here
548
  { data_type => "varchar", is_nullable => 1, size => 1 },
543
  { data_type => "varchar", is_nullable => 1, size => 1 },
549
  "password",
544
  "password",
550
  { data_type => "varchar", is_nullable => 1, size => 60 },
545
  { data_type => "varchar", is_nullable => 1, size => 60 },
551
  "flags",
552
  { data_type => "integer", is_nullable => 1 },
553
  "userid",
546
  "userid",
554
  { data_type => "varchar", is_nullable => 1, size => 75 },
547
  { data_type => "varchar", is_nullable => 1, size => 75 },
555
  "opacnote",
548
  "opacnote",
(-)a/Koha/Schema/Result/Permission.pm (-32 / +43 lines)
Lines 23-39 __PACKAGE__->table("permissions"); Link Here
23
23
24
=head1 ACCESSORS
24
=head1 ACCESSORS
25
25
26
=head2 module_bit
26
=head2 permission_id
27
27
28
  data_type: 'integer'
28
  data_type: 'integer'
29
  default_value: 0
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 module
33
34
  data_type: 'varchar'
30
  is_foreign_key: 1
35
  is_foreign_key: 1
31
  is_nullable: 0
36
  is_nullable: 0
37
  size: 32
32
38
33
=head2 code
39
=head2 code
34
40
35
  data_type: 'varchar'
41
  data_type: 'varchar'
36
  default_value: (empty string)
37
  is_nullable: 0
42
  is_nullable: 0
38
  size: 64
43
  size: 64
39
44
Lines 46-60 __PACKAGE__->table("permissions"); Link Here
46
=cut
51
=cut
47
52
48
__PACKAGE__->add_columns(
53
__PACKAGE__->add_columns(
49
  "module_bit",
54
  "permission_id",
50
  {
55
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
51
    data_type      => "integer",
56
  "module",
52
    default_value  => 0,
57
  { data_type => "varchar", is_foreign_key => 1, is_nullable => 0, size => 32 },
53
    is_foreign_key => 1,
54
    is_nullable    => 0,
55
  },
56
  "code",
58
  "code",
57
  { data_type => "varchar", default_value => "", is_nullable => 0, size => 64 },
59
  { data_type => "varchar", is_nullable => 0, size => 64 },
58
  "description",
60
  "description",
59
  { data_type => "varchar", is_nullable => 1, size => 255 },
61
  { data_type => "varchar", is_nullable => 1, size => 255 },
60
);
62
);
Lines 63-69 __PACKAGE__->add_columns( Link Here
63
65
64
=over 4
66
=over 4
65
67
66
=item * L</module_bit>
68
=item * L</permission_id>
69
70
=back
71
72
=cut
73
74
__PACKAGE__->set_primary_key("permission_id");
75
76
=head1 UNIQUE CONSTRAINTS
77
78
=head2 C<code>
79
80
=over 4
67
81
68
=item * L</code>
82
=item * L</code>
69
83
Lines 71-111 __PACKAGE__->add_columns( Link Here
71
85
72
=cut
86
=cut
73
87
74
__PACKAGE__->set_primary_key("module_bit", "code");
88
__PACKAGE__->add_unique_constraint("code", ["code"]);
75
89
76
=head1 RELATIONS
90
=head1 RELATIONS
77
91
78
=head2 module_bit
92
=head2 borrower_permissions
79
93
80
Type: belongs_to
94
Type: has_many
81
95
82
Related object: L<Koha::Schema::Result::Userflag>
96
Related object: L<Koha::Schema::Result::BorrowerPermission>
83
97
84
=cut
98
=cut
85
99
86
__PACKAGE__->belongs_to(
100
__PACKAGE__->has_many(
87
  "module_bit",
101
  "borrower_permissions",
88
  "Koha::Schema::Result::Userflag",
102
  "Koha::Schema::Result::BorrowerPermission",
89
  { bit => "module_bit" },
103
  { "foreign.permission_id" => "self.permission_id" },
90
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
104
  { cascade_copy => 0, cascade_delete => 0 },
91
);
105
);
92
106
93
=head2 user_permissions
107
=head2 module
94
108
95
Type: has_many
109
Type: belongs_to
96
110
97
Related object: L<Koha::Schema::Result::UserPermission>
111
Related object: L<Koha::Schema::Result::PermissionModule>
98
112
99
=cut
113
=cut
100
114
101
__PACKAGE__->has_many(
115
__PACKAGE__->belongs_to(
102
  "user_permissions",
116
  "module",
103
  "Koha::Schema::Result::UserPermission",
117
  "Koha::Schema::Result::PermissionModule",
104
  {
118
  { module => "module" },
105
    "foreign.code"       => "self.code",
119
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
106
    "foreign.module_bit" => "self.module_bit",
107
  },
108
  { cascade_copy => 0, cascade_delete => 0 },
109
);
120
);
110
121
111
122
(-)a/Koha/Schema/Result/PermissionModule.pm (+119 lines)
Line 0 Link Here
1
use utf8;
2
package Koha::Schema::Result::PermissionModule;
3
4
# Created by DBIx::Class::Schema::Loader
5
# DO NOT MODIFY THE FIRST PART OF THIS FILE
6
7
=head1 NAME
8
9
Koha::Schema::Result::PermissionModule
10
11
=cut
12
13
use strict;
14
use warnings;
15
16
use base 'DBIx::Class::Core';
17
18
=head1 TABLE: C<permission_modules>
19
20
=cut
21
22
__PACKAGE__->table("permission_modules");
23
24
=head1 ACCESSORS
25
26
=head2 permission_module_id
27
28
  data_type: 'integer'
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 module
33
34
  data_type: 'varchar'
35
  is_nullable: 0
36
  size: 32
37
38
=head2 description
39
40
  data_type: 'varchar'
41
  is_nullable: 1
42
  size: 255
43
44
=cut
45
46
__PACKAGE__->add_columns(
47
  "permission_module_id",
48
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
49
  "module",
50
  { data_type => "varchar", is_nullable => 0, size => 32 },
51
  "description",
52
  { data_type => "varchar", is_nullable => 1, size => 255 },
53
);
54
55
=head1 PRIMARY KEY
56
57
=over 4
58
59
=item * L</permission_module_id>
60
61
=back
62
63
=cut
64
65
__PACKAGE__->set_primary_key("permission_module_id");
66
67
=head1 UNIQUE CONSTRAINTS
68
69
=head2 C<module>
70
71
=over 4
72
73
=item * L</module>
74
75
=back
76
77
=cut
78
79
__PACKAGE__->add_unique_constraint("module", ["module"]);
80
81
=head1 RELATIONS
82
83
=head2 borrower_permissions
84
85
Type: has_many
86
87
Related object: L<Koha::Schema::Result::BorrowerPermission>
88
89
=cut
90
91
__PACKAGE__->has_many(
92
  "borrower_permissions",
93
  "Koha::Schema::Result::BorrowerPermission",
94
  { "foreign.permission_module_id" => "self.permission_module_id" },
95
  { cascade_copy => 0, cascade_delete => 0 },
96
);
97
98
=head2 permissions
99
100
Type: has_many
101
102
Related object: L<Koha::Schema::Result::Permission>
103
104
=cut
105
106
__PACKAGE__->has_many(
107
  "permissions",
108
  "Koha::Schema::Result::Permission",
109
  { "foreign.module" => "self.module" },
110
  { cascade_copy => 0, cascade_delete => 0 },
111
);
112
113
114
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2015-08-03 18:53:48
115
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0p9fkT+XinNSQXJa/egQPw
116
117
118
# You can replace this text with custom code or comments, and it will be preserved on regeneration
119
1;
(-)a/installer/data/mysql/atomicupdate/Bug-14540-2-Delete_deletedborrowers-flags.perl (+5 lines)
Line 0 Link Here
1
use C4::Context;
2
my $dbh = C4::Context->dbh();
3
4
$dbh->do("ALTER TABLE deletedborrowers DROP COLUMN flags");
5
print "Upgrade done (Bug 14540-2 - Drop deletedborrowers.flags column.)\n";
(-)a/installer/data/mysql/atomicupdate/Bug14540-PermissionManager.perl (+151 lines)
Line 0 Link Here
1
$DBversion = 'XXX';  # will be replaced by the RM
2
if( CheckVersion( $DBversion ) ) {
3
    $dbh->do("CREATE TABLE permission_modules (
4
                permission_module_id int(11) NOT NULL auto_increment,
5
                module varchar(32) NOT NULL,
6
                description varchar(255) DEFAULT NULL,
7
                PRIMARY KEY  (permission_module_id),
8
                UNIQUE KEY (module)
9
              ) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
10
    $dbh->do("INSERT INTO permission_modules (permission_module_id, module, description) SELECT bit, flag, flagdesc FROM userflags WHERE bit != 0;"); #superlibrarian causes primary key conflict
11
    $dbh->do("INSERT INTO permission_modules (permission_module_id, module, description) SELECT 22, flag, flagdesc FROM userflags WHERE bit = 0;");   #So add him by himself.
12
13
    $dbh->do("ALTER TABLE permissions RENAME TO permissions_old");
14
    $dbh->do("CREATE TABLE permissions (
15
                permission_id int(11) NOT NULL auto_increment,
16
                module varchar(32) NOT NULL,
17
                code varchar(64) NOT NULL,
18
                description varchar(255) DEFAULT NULL,
19
                PRIMARY KEY  (permission_id),
20
                UNIQUE KEY (code),
21
                CONSTRAINT permissions_to_modules_ibfk1 FOREIGN KEY (module) REFERENCES permission_modules (module)
22
                  ON DELETE CASCADE ON UPDATE CASCADE
23
              ) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
24
    $dbh->do("INSERT INTO permissions (module, code, description)
25
                SELECT userflags.flag, code, description FROM permissions_old
26
                  LEFT JOIN userflags ON permissions_old.module_bit = userflags.bit;");
27
28
    $dbh->do("CREATE TABLE borrower_permissions (
29
                borrower_permission_id int(11) NOT NULL auto_increment,
30
                borrowernumber int(11) NOT NULL,
31
                permission_module_id int(11) NOT NULL,
32
                permission_id int(11) NOT NULL,
33
                PRIMARY KEY  (borrower_permission_id),
34
                UNIQUE KEY (borrowernumber, permission_module_id, permission_id),
35
                CONSTRAINT borrower_permissions_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber)
36
                  ON DELETE CASCADE ON UPDATE CASCADE,
37
                CONSTRAINT borrower_permissions_ibfk_2 FOREIGN KEY (permission_id) REFERENCES permissions (permission_id)
38
                  ON DELETE CASCADE ON UPDATE CASCADE,
39
                CONSTRAINT borrower_permissions_ibfk_3 FOREIGN KEY (permission_module_id) REFERENCES permission_modules (permission_module_id)
40
                  ON DELETE CASCADE ON UPDATE CASCADE
41
              ) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
42
    $dbh->do("INSERT INTO borrower_permissions (borrowernumber, permission_module_id, permission_id)
43
                SELECT user_permissions.borrowernumber, user_permissions.module_bit, permissions.permission_id
44
                FROM user_permissions
45
                LEFT JOIN permissions ON user_permissions.code = permissions.code
46
                LEFT JOIN borrowers ON borrowers.borrowernumber = user_permissions.borrowernumber
47
                WHERE borrowers.borrowernumber IS NOT NULL;"); #It is possible to have user_permissions dangling around not pointing to anything, so make sure we dont try to move nonexisting borrower permissions.
48
49
    ##Add subpermissions to the stand-alone modules (modules with no subpermissions)
50
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('superlibrarian', 'superlibrarian', 'Access to all librarian functions.');");
51
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('catalogue', 'staff_login', 'Allow staff login.');");
52
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('borrowers', 'view_borrowers', 'Show borrower details and search for borrowers.');");
53
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('permissions', 'set_permissions', 'Set user permissions.');");
54
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('management', 'management', 'Set library management parameters (deprecated).');");
55
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('editauthorities', 'edit_authorities', 'Edit authorities.');");
56
    $dbh->do("INSERT INTO permissions (module, code, description) VALUES ('staffaccess', 'staff_access_permissions', 'Allow staff members to modify permissions for other staff members.');");
57
58
    ##Create borrower_permissions to replace singular userflags from borrowers.flags.
59
    my $sthSelectSubPermissions = $dbh->prepare("SELECT * FROM permissions p LEFT JOIN permission_modules pm ON p.module = pm.module WHERE pm.permission_module_id = ?");
60
    my $sthSelectBorrowerPermission = $dbh->prepare("SELECT * FROM borrower_permissions WHERE permission_id = ? AND borrowernumber = ?");
61
    my $sthInsertBorrowerPermission = $dbh->prepare("INSERT INTO borrower_permissions (borrowernumber, permission_module_id, permission_id) VALUES (?,?,?)");
62
    sub grantAllSubpermissions {
63
        my ($borrowernumber, $module_id, $dbh) = @_;
64
65
        $sthSelectSubPermissions->execute($module_id);
66
        my $subPermissions = $sthSelectSubPermissions->fetchall_arrayref({});
67
        foreach my $sp (@$subPermissions) {
68
            $sthSelectBorrowerPermission->execute($sp->{permission_id}, $borrowernumber);
69
            my $alreadyPermission = $sthSelectBorrowerPermission->fetchrow_hashref();
70
            unless ($alreadyPermission) {
71
                $sthInsertBorrowerPermission->execute($borrowernumber, $sp->{permission_module_id}, $sp->{permission_id});
72
            }
73
        }
74
    }
75
76
    my $sthSelectAllBorrowers = $dbh->prepare("SELECT * FROM borrowers;");
77
    $sthSelectAllBorrowers->execute();
78
    my $borrowers = $sthSelectAllBorrowers->fetchall_arrayref({});
79
    foreach my $b (@$borrowers) {
80
        next unless $b->{flags};
81
        if ( ( $b->{flags} & ( 2**0 ) ) ) {
82
            grantAllSubpermissions($b->{borrowernumber}, 21, $dbh); #superlibrarian
83
        }
84
        if ( ( $b->{flags} & ( 2**1 ) ) ) {
85
            grantAllSubpermissions($b->{borrowernumber}, 1, $dbh); #circulate
86
        }
87
        if ( ( $b->{flags} & ( 2**2 ) ) ) {
88
            grantAllSubpermissions($b->{borrowernumber}, 2, $dbh); #catalogue
89
        }
90
        if ( ( $b->{flags} & ( 2**3 ) ) ) {
91
            grantAllSubpermissions($b->{borrowernumber}, 3, $dbh); #parameters, should be deprecated already
92
        }
93
        if ( ( $b->{flags} & ( 2**4 ) ) ) {
94
            grantAllSubpermissions($b->{borrowernumber}, 4, $dbh); #borrowers
95
        }
96
        if ( ( $b->{flags} & ( 2**5 ) ) ) {
97
            grantAllSubpermissions($b->{borrowernumber}, 5, $dbh); #permissions
98
        }
99
        if ( ( $b->{flags} & ( 2**6 ) ) ) {
100
            grantAllSubpermissions($b->{borrowernumber}, 6, $dbh); #reserveforothers
101
        }
102
#        if ( ( $b->{flags} & ( 2**7 ) ) ) {
103
#            grantAllSubpermissions($b->{borrowernumber}, 7, $dbh); #borrow, should be deprecated already
104
#        }
105
        if ( ( $b->{flags} & ( 2**9 ) ) ) {
106
            grantAllSubpermissions($b->{borrowernumber}, 9, $dbh); #editcatalogue
107
        }
108
        if ( ( $b->{flags} & ( 2**10 ) ) ) {
109
            grantAllSubpermissions($b->{borrowernumber}, 10, $dbh); #updatecharges
110
        }
111
        if ( ( $b->{flags} & ( 2**11 ) ) ) {
112
            grantAllSubpermissions($b->{borrowernumber}, 11, $dbh); #acquisition
113
        }
114
        if ( ( $b->{flags} & ( 2**12 ) ) ) {
115
            grantAllSubpermissions($b->{borrowernumber}, 12, $dbh); #management
116
        }
117
        if ( ( $b->{flags} & ( 2**13 ) ) ) {
118
            grantAllSubpermissions($b->{borrowernumber}, 13, $dbh); #tools
119
        }
120
        if ( ( $b->{flags} & ( 2**14 ) ) ) {
121
            grantAllSubpermissions($b->{borrowernumber}, 14, $dbh); #editauthorities
122
        }
123
        if ( ( $b->{flags} & ( 2**15 ) ) ) {
124
            grantAllSubpermissions($b->{borrowernumber}, 15, $dbh); #serials
125
        }
126
        if ( ( $b->{flags} & ( 2**16 ) ) ) {
127
            grantAllSubpermissions($b->{borrowernumber}, 16, $dbh); #reports
128
        }
129
        if ( ( $b->{flags} & ( 2**17 ) ) ) {
130
            grantAllSubpermissions($b->{borrowernumber}, 17, $dbh); #staffaccess
131
        }
132
        if ( ( $b->{flags} & ( 2**18 ) ) ) {
133
            grantAllSubpermissions($b->{borrowernumber}, 18, $dbh); #coursereserves
134
        }
135
        if ( ( $b->{flags} & ( 2**19 ) ) ) {
136
            grantAllSubpermissions($b->{borrowernumber}, 19, $dbh); #plugins
137
        }
138
    }
139
140
    ##Cleanup redundant tables.
141
    $dbh->do("DELETE FROM userflags"); #Cascades to other tables.
142
    $dbh->do("DROP TABLE user_permissions");
143
    $dbh->do("DROP TABLE permissions_old");
144
    $dbh->do("DROP TABLE userflags");
145
    $dbh->do("ALTER TABLE borrowers DROP COLUMN flags");
146
    $dbh->do("DELETE FROM permission_modules WHERE module = 'borrow'");
147
148
    # Always end with this (adjust the bug info)
149
    SetVersion( $DBversion );
150
    print "Upgrade to $DBversion done (Bug 14540 - Move member-flags.pl to PermissionsManager to better manage permissions for testing.)\n";
151
}
(-)a/installer/data/mysql/en/optional/sample_patrons.sql (-51 / +51 lines)
Lines 1-51 Link Here
1
INSERT INTO `borrowers` (`borrowernumber`, `cardnumber`, `surname`, `firstname`, `title`, `othernames`, `initials`, `streetnumber`, `streettype`, `address`, `address2`, `city`, `zipcode`, `email`, `phone`, `mobile`, `fax`, `emailpro`, `phonepro`, `B_streetnumber`, `B_streettype`, `B_address`, `B_city`, `B_zipcode`, `B_email`, `B_phone`, `dateofbirth`, `branchcode`, `categorycode`, `dateenrolled`, `dateexpiry`, `gonenoaddress`, `lost`, `debarred`, `contactname`, `contactfirstname`, `contacttitle`, `guarantorid`, `borrowernotes`, `relationship`, `sex`, `userid`, `opacnote`, `contactnote`, `password`, `flags`, `sort1`, `sort2`) VALUES
1
INSERT INTO `borrowers` (`borrowernumber`, `cardnumber`, `surname`, `firstname`, `title`, `othernames`, `initials`, `streetnumber`, `streettype`, `address`, `address2`, `city`, `zipcode`, `email`, `phone`, `mobile`, `fax`, `emailpro`, `phonepro`, `B_streetnumber`, `B_streettype`, `B_address`, `B_city`, `B_zipcode`, `B_email`, `B_phone`, `dateofbirth`, `branchcode`, `categorycode`, `dateenrolled`, `dateexpiry`, `gonenoaddress`, `lost`, `debarred`, `contactname`, `contactfirstname`, `contacttitle`, `guarantorid`, `borrowernotes`, `relationship`, `sex`, `userid`, `opacnote`, `contactnote`, `password`, `sort1`, `sort2`) VALUES
2
(1,'1','Admin','Koha',NULL,NULL,'',NULL,NULL,'',NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','S',NULL,'2099-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
2
(1,'1','Admin','Koha',NULL,NULL,'',NULL,NULL,'',NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','S',NULL,'2099-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
3
(2,'23529000152273','Welch','Marcus',NULL,NULL,'',NULL,NULL,'5601 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'FRL','ST','1985-10-24','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000152273',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.43609457503641','0.38613959717205'),
3
(2,'23529000152273','Welch','Marcus',NULL,NULL,'',NULL,NULL,'5601 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'FRL','ST','1985-10-24','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000152273',NULL,NULL,'42b29d0771f3b7ef','0.43609457503641','0.38613959717205'),
4
(3,'23529000445172','Daniels','Tanya',NULL,NULL,'',NULL,NULL,'2035 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1966-10-14','MPL','PT','1990-08-22','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000445172',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.62241429148467','0.95365269664084'),
4
(3,'23529000445172','Daniels','Tanya',NULL,NULL,'',NULL,NULL,'2035 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1966-10-14','MPL','PT','1990-08-22','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000445172',NULL,NULL,'42b29d0771f3b7ef','0.62241429148467','0.95365269664084'),
5
(4,'23529000105040','Dillon','Eva',NULL,NULL,'',NULL,NULL,'8916 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-04-03','MPL','PT','1987-07-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000105040',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.90102063948384','0.64414513823031'),
5
(4,'23529000105040','Dillon','Eva',NULL,NULL,'',NULL,NULL,'8916 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-04-03','MPL','PT','1987-07-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000105040',NULL,NULL,'42b29d0771f3b7ef','0.90102063948384','0.64414513823031'),
6
(5,'23529001000463','Acosta','Edna',NULL,NULL,'',NULL,NULL,'7896 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1980-04-24','MPL','PT','1990-11-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529001000463',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.72642678648832','0.6644830635418'),
6
(5,'23529001000463','Acosta','Edna',NULL,NULL,'',NULL,NULL,'7896 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1980-04-24','MPL','PT','1990-11-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529001000463',NULL,NULL,'42b29d0771f3b7ef','0.72642678648832','0.6644830635418'),
7
(6,'23529000591678','Glass','Virgil',NULL,NULL,'',NULL,NULL,'6250 Library Rd.',NULL,'Santa Cruz, CA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1974-06-19','SPL','T','1985-02-13','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,102,NULL,NULL,'M','23529000591678',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.1431349889777','0.72222578499673'),
7
(6,'23529000591678','Glass','Virgil',NULL,NULL,'',NULL,NULL,'6250 Library Rd.',NULL,'Santa Cruz, CA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1974-06-19','SPL','T','1985-02-13','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,102,NULL,NULL,'M','23529000591678',NULL,NULL,'42b29d0771f3b7ef','0.1431349889777','0.72222578499673'),
8
(7,'23529000080862','Middleton','Bobbie',NULL,NULL,'',NULL,NULL,'4619 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-07-24','SPL','J','1991-03-13','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,104,NULL,NULL,'M','23529000080862',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.18172398878422','0.74194261966454'),
8
(7,'23529000080862','Middleton','Bobbie',NULL,NULL,'',NULL,NULL,'4619 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-07-24','SPL','J','1991-03-13','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,104,NULL,NULL,'M','23529000080862',NULL,NULL,'42b29d0771f3b7ef','0.18172398878422','0.74194261966454'),
9
(8,'23529000358268','Rivera','Olga',NULL,NULL,'',NULL,NULL,'6058 Library Rd.',NULL,'Mayfield Heights, OH','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1979-12-22','PVL','T','1986-04-17','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,112,NULL,NULL,'F','23529000358268',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.16454116270369','0.59687798525847'),
9
(8,'23529000358268','Rivera','Olga',NULL,NULL,'',NULL,NULL,'6058 Library Rd.',NULL,'Mayfield Heights, OH','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1979-12-22','PVL','T','1986-04-17','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,112,NULL,NULL,'F','23529000358268',NULL,NULL,'42b29d0771f3b7ef','0.16454116270369','0.59687798525847'),
10
(9,'23529000429697','Waters','Annie',NULL,NULL,'',NULL,NULL,'5444 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1932-10-27','FRL','ST','1984-05-07','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000429697',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.49076646891494','0.66319841953292'),
10
(9,'23529000429697','Waters','Annie',NULL,NULL,'',NULL,NULL,'5444 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1932-10-27','FRL','ST','1984-05-07','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000429697',NULL,NULL,'42b29d0771f3b7ef','0.49076646891494','0.66319841953292'),
11
(10,'23529000068917','Herring','Frances',NULL,NULL,'',NULL,NULL,'4024 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-02-13','SPL','PT','1993-03-12','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000068917',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.84369272165344','0.22886838040209'),
11
(10,'23529000068917','Herring','Frances',NULL,NULL,'',NULL,NULL,'4024 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-02-13','SPL','PT','1993-03-12','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000068917',NULL,NULL,'42b29d0771f3b7ef','0.84369272165344','0.22886838040209'),
12
(11,'23529000065863','Hawkins','Sam',NULL,NULL,'',NULL,NULL,'665 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1924-03-26','SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000065863',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.61326376778378','0.37971372844625'),
12
(11,'23529000065863','Hawkins','Sam',NULL,NULL,'',NULL,NULL,'665 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1924-03-26','SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000065863',NULL,NULL,'42b29d0771f3b7ef','0.61326376778378','0.37971372844625'),
13
(12,'23529000878885','Mcknight','Marie',NULL,NULL,'',NULL,NULL,'4241 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','YA','1990-08-06','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000878885',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.058777369613552','0.15474569346266'),
13
(12,'23529000878885','Mcknight','Marie',NULL,NULL,'',NULL,NULL,'4241 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','YA','1990-08-06','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000878885',NULL,NULL,'42b29d0771f3b7ef','0.058777369613552','0.15474569346266'),
14
(13,'23529000132291','Edwards','Roy',NULL,NULL,'',NULL,NULL,'9929 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1928-09-09','MPL','PT','1992-03-10','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000132291',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.59739638920631','0.5227448963772'),
14
(13,'23529000132291','Edwards','Roy',NULL,NULL,'',NULL,NULL,'9929 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1928-09-09','MPL','PT','1992-03-10','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000132291',NULL,NULL,'42b29d0771f3b7ef','0.59739638920631','0.5227448963772'),
15
(14,'23529000035726','Mccullough','Phillip',NULL,NULL,'',NULL,NULL,'410 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1943-11-23','SPL','PT','1986-01-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000035726',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.82153534500071','0.53944206660561'),
15
(14,'23529000035726','Mccullough','Phillip',NULL,NULL,'',NULL,NULL,'410 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1943-11-23','SPL','PT','1986-01-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000035726',NULL,NULL,'42b29d0771f3b7ef','0.82153534500071','0.53944206660561'),
16
(15,'23529001203323','Peterson','Gordon',NULL,NULL,'',NULL,NULL,'6285 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1963-10-01','SPL','J','1984-09-11','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,131,NULL,NULL,'F','23529001203323',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.23260432875958','0.54469547471469'),
16
(15,'23529001203323','Peterson','Gordon',NULL,NULL,'',NULL,NULL,'6285 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1963-10-01','SPL','J','1984-09-11','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,131,NULL,NULL,'F','23529001203323',NULL,NULL,'42b29d0771f3b7ef','0.23260432875958','0.54469547471469'),
17
(16,'23529000991266','Walker','Andrea',NULL,NULL,'',NULL,NULL,'4992 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1956-08-05','FRL','IL','1993-06-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000991266',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.025664418028355','0.49423569673135'),
17
(16,'23529000991266','Walker','Andrea',NULL,NULL,'',NULL,NULL,'4992 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1956-08-05','FRL','IL','1993-06-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000991266',NULL,NULL,'42b29d0771f3b7ef','0.025664418028355','0.49423569673135'),
18
(17,'23529000711078','King','Casey',NULL,NULL,'',NULL,NULL,'3438 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-09-23','SPL','S','1992-05-18','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000711078',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.39418526030535','0.48821924206635'),
18
(17,'23529000711078','King','Casey',NULL,NULL,'',NULL,NULL,'3438 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1953-09-23','SPL','S','1992-05-18','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000711078',NULL,NULL,'42b29d0771f3b7ef','0.39418526030535','0.48821924206635'),
19
(18,'23529000809559','Delgado','Floyd',NULL,NULL,'',NULL,NULL,'6661 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1968-02-01','MPL','K','1988-08-05','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,160,NULL,NULL,'M','23529000809559',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.25854046014933','0.82804460528125'),
19
(18,'23529000809559','Delgado','Floyd',NULL,NULL,'',NULL,NULL,'6661 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1968-02-01','MPL','K','1988-08-05','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,160,NULL,NULL,'M','23529000809559',NULL,NULL,'42b29d0771f3b7ef','0.25854046014933','0.82804460528125'),
20
(19,'23529000035676','Acevedo','Henry',NULL,NULL,'',NULL,NULL,'4345 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1958-05-30','MPL','S','1990-09-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000035676',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.36460167669188','0.33887459834933'),
20
(19,'23529000035676','Acevedo','Henry',NULL,NULL,'',NULL,NULL,'4345 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1958-05-30','MPL','S','1990-09-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000035676',NULL,NULL,'42b29d0771f3b7ef','0.36460167669188','0.33887459834933'),
21
(20,'23529000033739','Frazier','Sonia',NULL,NULL,'',NULL,NULL,'8165 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1945-09-16','MPL','PT','1984-06-21','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000033739',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.60056799240463','0.98621619770882'),
21
(20,'23529000033739','Frazier','Sonia',NULL,NULL,'',NULL,NULL,'8165 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1945-09-16','MPL','PT','1984-06-21','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000033739',NULL,NULL,'42b29d0771f3b7ef','0.60056799240463','0.98621619770882'),
22
(21,'23529000139858','Ballard','Ronnie',NULL,NULL,'',NULL,NULL,'5730 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1956-02-23','MPL','T','1989-06-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,177,NULL,NULL,'F','23529000139858',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.12937704206386','0.68823664792649'),
22
(21,'23529000139858','Ballard','Ronnie',NULL,NULL,'',NULL,NULL,'5730 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1956-02-23','MPL','T','1989-06-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,177,NULL,NULL,'F','23529000139858',NULL,NULL,'42b29d0771f3b7ef','0.12937704206386','0.68823664792649'),
23
(22,'23529000224510','Gaines','Joyce',NULL,NULL,'',NULL,NULL,'6012 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1957-08-01','SPL','YA','1992-09-16','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000224510',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.053052144174513','0.20055080782673'),
23
(22,'23529000224510','Gaines','Joyce',NULL,NULL,'',NULL,NULL,'6012 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1957-08-01','SPL','YA','1992-09-16','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000224510',NULL,NULL,'42b29d0771f3b7ef','0.053052144174513','0.20055080782673'),
24
(23,'23529000120056','Bryan','Johnny',NULL,NULL,'',NULL,NULL,'8180 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1961-10-24','MPL','PT','1990-08-22','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000120056',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.84359763734378','0.61633579397233'),
24
(23,'23529000120056','Bryan','Johnny',NULL,NULL,'',NULL,NULL,'8180 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1961-10-24','MPL','PT','1990-08-22','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000120056',NULL,NULL,'42b29d0771f3b7ef','0.84359763734378','0.61633579397233'),
25
(24,'23529000218553','Duffy','Joann',NULL,NULL,'',NULL,NULL,'1555 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1942-02-17','MPL','ST','1984-08-02','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000218553',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.55088608856395','0.90542309163643'),
25
(24,'23529000218553','Duffy','Joann',NULL,NULL,'',NULL,NULL,'1555 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1942-02-17','MPL','ST','1984-08-02','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000218553',NULL,NULL,'42b29d0771f3b7ef','0.55088608856395','0.90542309163643'),
26
(25,'23529000662701','Mejia','Armando',NULL,NULL,'',NULL,NULL,'8209 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1939-07-22','SPL','PT','1990-09-26','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000662701',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.87445722322395','0.65601687194409'),
26
(25,'23529000662701','Mejia','Armando',NULL,NULL,'',NULL,NULL,'8209 Library Rd.',NULL,'Portland, OR','44240',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1939-07-22','SPL','PT','1990-09-26','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000662701',NULL,NULL,'42b29d0771f3b7ef','0.87445722322395','0.65601687194409'),
27
(26,'23529000092040','Hendrix','Keith',NULL,NULL,'',NULL,NULL,'6546 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1944-04-05','SPL','PT','1987-12-12','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000092040',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.65671272078223','0.31551301881253'),
27
(26,'23529000092040','Hendrix','Keith',NULL,NULL,'',NULL,NULL,'6546 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1944-04-05','SPL','PT','1987-12-12','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000092040',NULL,NULL,'42b29d0771f3b7ef','0.65671272078223','0.31551301881253'),
28
(27,'23529000058017','Turner','Sherri',NULL,NULL,'',NULL,NULL,'1731 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1964-11-21','FRL','PT','1987-09-14','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000058017',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.60742696244961','0.090595786544118'),
28
(27,'23529000058017','Turner','Sherri',NULL,NULL,'',NULL,NULL,'1731 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1964-11-21','FRL','PT','1987-09-14','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000058017',NULL,NULL,'42b29d0771f3b7ef','0.60742696244961','0.090595786544118'),
29
(28,'23529000299603','Cherry','Lillie',NULL,NULL,'',NULL,NULL,'263 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1931-01-19','MPL','PT','1993-03-19','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000299603',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.6306980761054','0.88170305162827'),
29
(28,'23529000299603','Cherry','Lillie',NULL,NULL,'',NULL,NULL,'263 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1931-01-19','MPL','PT','1993-03-19','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000299603',NULL,NULL,'42b29d0771f3b7ef','0.6306980761054','0.88170305162827'),
30
(29,'23529000121682','Schneider','Nicole',NULL,NULL,'',NULL,NULL,'1008 Library Rd.',NULL,'Centerville, CA','44306',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1954-01-12','FRL','ST','1985-09-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000121682',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.5164210605588','0.93699617864284'),
30
(29,'23529000121682','Schneider','Nicole',NULL,NULL,'',NULL,NULL,'1008 Library Rd.',NULL,'Centerville, CA','44306',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1954-01-12','FRL','ST','1985-09-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000121682',NULL,NULL,'42b29d0771f3b7ef','0.5164210605588','0.93699617864284'),
31
(30,'23529000240482','White','Jamie',NULL,NULL,'',NULL,NULL,'937 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1950-04-22','FRL','T','1990-02-03','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,254,NULL,NULL,'F','23529000240482',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.13571774227146','0.86760020616241'),
31
(30,'23529000240482','White','Jamie',NULL,NULL,'',NULL,NULL,'937 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1950-04-22','FRL','T','1990-02-03','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,254,NULL,NULL,'F','23529000240482',NULL,NULL,'42b29d0771f3b7ef','0.13571774227146','0.86760020616241'),
32
(31,'23529000714163','Burgess','Dawn',NULL,NULL,'',NULL,NULL,'7907 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','PT','1985-05-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000714163',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.93084783473131','0.051438585902973'),
32
(31,'23529000714163','Burgess','Dawn',NULL,NULL,'',NULL,NULL,'7907 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','PT','1985-05-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000714163',NULL,NULL,'42b29d0771f3b7ef','0.93084783473131','0.051438585902973'),
33
(32,'23529000318858','Bennett','Pamela',NULL,NULL,'',NULL,NULL,'9898 Library Rd.',NULL,'Centerville, CA','44310',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1946-09-16','MPL','ST','1984-05-08','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000318858',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.46464945605458','0.16893155329761'),
33
(32,'23529000318858','Bennett','Pamela',NULL,NULL,'',NULL,NULL,'9898 Library Rd.',NULL,'Centerville, CA','44310',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1946-09-16','MPL','ST','1984-05-08','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000318858',NULL,NULL,'42b29d0771f3b7ef','0.46464945605458','0.16893155329761'),
34
(33,'23529000526047','Hatfield','Lester',NULL,NULL,'',NULL,NULL,'393 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1983-01-22','SPL','ST','1988-07-30','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000526047',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.45070942905798','0.74675251613069'),
34
(33,'23529000526047','Hatfield','Lester',NULL,NULL,'',NULL,NULL,'393 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1983-01-22','SPL','ST','1988-07-30','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000526047',NULL,NULL,'42b29d0771f3b7ef','0.45070942905798','0.74675251613069'),
35
(34,'23529000686353','Harper','Ruben',NULL,NULL,'',NULL,NULL,'6963 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1917-09-24','SPL','S','1991-02-19','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000686353',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.38163432421315','0.66791410340733'),
35
(34,'23529000686353','Harper','Ruben',NULL,NULL,'',NULL,NULL,'6963 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1917-09-24','SPL','S','1991-02-19','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000686353',NULL,NULL,'42b29d0771f3b7ef','0.38163432421315','0.66791410340733'),
36
(35,'23529000719519','Kinney','Mae',NULL,NULL,'',NULL,NULL,'2114 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','J','1991-12-29','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,287,NULL,NULL,'F','23529000719519',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.19466757513086','0.96959559616595'),
36
(35,'23529000719519','Kinney','Mae',NULL,NULL,'',NULL,NULL,'2114 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','J','1991-12-29','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,287,NULL,NULL,'F','23529000719519',NULL,NULL,'42b29d0771f3b7ef','0.19466757513086','0.96959559616595'),
37
(36,'23529000179433','Williamson','Catherine',NULL,NULL,'',NULL,NULL,'5879 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1930-12-18','FRL','K','1985-01-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,288,NULL,NULL,'M','23529000179433',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.26397528617082','0.41108967308988'),
37
(36,'23529000179433','Williamson','Catherine',NULL,NULL,'',NULL,NULL,'5879 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1930-12-18','FRL','K','1985-01-23','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,288,NULL,NULL,'M','23529000179433',NULL,NULL,'42b29d0771f3b7ef','0.26397528617082','0.41108967308988'),
38
(37,'23529000197047','Charles','Lisa',NULL,NULL,'',NULL,NULL,'6813 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1982-10-14','MPL','K','1988-11-14','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,289,NULL,NULL,'M','23529000197047',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.26352253767058','0.084343699816934'),
38
(37,'23529000197047','Charles','Lisa',NULL,NULL,'',NULL,NULL,'6813 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1982-10-14','MPL','K','1988-11-14','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,289,NULL,NULL,'M','23529000197047',NULL,NULL,'42b29d0771f3b7ef','0.26352253767058','0.084343699816934'),
39
(38,'23529000695412','Singleton','Bob',NULL,NULL,'',NULL,NULL,'4554 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1983-04-15','FRL','PT','1991-07-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000695412',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.63115091680656','0.90272351531566'),
39
(38,'23529000695412','Singleton','Bob',NULL,NULL,'',NULL,NULL,'4554 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1983-04-15','FRL','PT','1991-07-01','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000695412',NULL,NULL,'42b29d0771f3b7ef','0.63115091680656','0.90272351531566'),
40
(39,'23529000603242','Mcconnell','Terrence',NULL,NULL,'',NULL,NULL,'7200 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1949-06-10','SPL','PT','1984-05-31','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000603242',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.62016485689223','0.39265376924784'),
40
(39,'23529000603242','Mcconnell','Terrence',NULL,NULL,'',NULL,NULL,'7200 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1949-06-10','SPL','PT','1984-05-31','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000603242',NULL,NULL,'42b29d0771f3b7ef','0.62016485689223','0.39265376924784'),
41
(40,'23529000589458','Knight','Mabel',NULL,NULL,'',NULL,NULL,'8997 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-12-22','SPL','T','1985-04-17','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,320,NULL,NULL,'M','23529000589458',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.10277430629616','0.33591025447092'),
41
(40,'23529000589458','Knight','Mabel',NULL,NULL,'',NULL,NULL,'8997 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-12-22','SPL','T','1985-04-17','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,320,NULL,NULL,'M','23529000589458',NULL,NULL,'42b29d0771f3b7ef','0.10277430629616','0.33591025447092'),
42
(41,'23529000054503','Odom','Gloria',NULL,NULL,'',NULL,NULL,'9156 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-04-05','SPL','S','1992-07-21','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000054503',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.37122838419976','0.84841118831971'),
42
(41,'23529000054503','Odom','Gloria',NULL,NULL,'',NULL,NULL,'9156 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-04-05','SPL','S','1992-07-21','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000054503',NULL,NULL,'42b29d0771f3b7ef','0.37122838419976','0.84841118831971'),
43
(42,'23529000126806','Hopkins','Brent',NULL,NULL,'',NULL,NULL,'6692 Library Rd.',NULL,'Santa Cruz, CA','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1977-11-13','SPL','T','1984-06-28','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,337,NULL,NULL,'F','23529000126806',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.12837081973289','0.096620564438981'),
43
(42,'23529000126806','Hopkins','Brent',NULL,NULL,'',NULL,NULL,'6692 Library Rd.',NULL,'Santa Cruz, CA','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1977-11-13','SPL','T','1984-06-28','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,337,NULL,NULL,'F','23529000126806',NULL,NULL,'42b29d0771f3b7ef','0.12837081973289','0.096620564438981'),
44
(43,'23529000104159','Benson','Clinton',NULL,NULL,'',NULL,NULL,'4695 Library Rd.',NULL,'Atwater, OH','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','YA','1985-10-28','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000104159',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.097990393729872','0.20009030606606'),
44
(43,'23529000104159','Benson','Clinton',NULL,NULL,'',NULL,NULL,'4695 Library Rd.',NULL,'Atwater, OH','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'MPL','YA','1985-10-28','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000104159',NULL,NULL,'42b29d0771f3b7ef','0.097990393729872','0.20009030606606'),
45
(44,'23529000395609','Stuart','Shannon',NULL,NULL,'',NULL,NULL,'5011 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1951-02-13','FRL','PT','1986-01-16','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000395609',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.70648037987433','0.93213101190713'),
45
(44,'23529000395609','Stuart','Shannon',NULL,NULL,'',NULL,NULL,'5011 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1951-02-13','FRL','PT','1986-01-16','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000395609',NULL,NULL,'42b29d0771f3b7ef','0.70648037987433','0.93213101190713'),
46
(45,'23529000050113','Alford','Jordan',NULL,NULL,'',NULL,NULL,'5129 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-05-27','MPL','ST','1985-09-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000050113',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.54121395064631','0.90967674824379'),
46
(45,'23529000050113','Alford','Jordan',NULL,NULL,'',NULL,NULL,'5129 Library Rd.',NULL,'Centerville, CA','44262',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1952-05-27','MPL','ST','1985-09-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000050113',NULL,NULL,'42b29d0771f3b7ef','0.54121395064631','0.90967674824379'),
47
(46,'23529000053836','Mcfarland','Marilyn',NULL,NULL,'',NULL,NULL,'4600 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000053836',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.92474192001367','0.89467938607063'),
47
(46,'23529000053836','Mcfarland','Marilyn',NULL,NULL,'',NULL,NULL,'4600 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000053836',NULL,NULL,'42b29d0771f3b7ef','0.92474192001367','0.89467938607063'),
48
(47,'23529000774373','Morris','Lauren',NULL,NULL,'',NULL,NULL,'5436 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','PT','1986-03-20','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000774373',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.69917120104578','0.81181787775067'),
48
(47,'23529000774373','Morris','Lauren',NULL,NULL,'',NULL,NULL,'5436 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'SPL','PT','1986-03-20','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000774373',NULL,NULL,'42b29d0771f3b7ef','0.69917120104578','0.81181787775067'),
49
(48,'23529000117565','Palmer','Bill',NULL,NULL,'',NULL,NULL,'2761 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1984-01-10','SPL','PT','1991-10-07','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000117565',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.96157581634966','0.37242547922994'),
49
(48,'23529000117565','Palmer','Bill',NULL,NULL,'',NULL,NULL,'2761 Library Rd.',NULL,'Springfield, MA','44224',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1984-01-10','SPL','PT','1991-10-07','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'M','23529000117565',NULL,NULL,'42b29d0771f3b7ef','0.96157581634966','0.37242547922994'),
50
(49,'23529000651225','Burton','Mary',NULL,NULL,'',NULL,NULL,'8131 Library Rd.',NULL,'Santa Cruz, CA','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1977-12-25','MPL','PT','1985-05-30','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000651225',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.97739997783434','0.76972348221552'),
50
(49,'23529000651225','Burton','Mary',NULL,NULL,'',NULL,NULL,'8131 Library Rd.',NULL,'Santa Cruz, CA','21234',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1977-12-25','MPL','PT','1985-05-30','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529000651225',NULL,NULL,'42b29d0771f3b7ef','0.97739997783434','0.76972348221552'),
51
(50,'23529001223636','Peters','Tommy',NULL,NULL,'',NULL,NULL,'5171 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1951-06-14','SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529001223636',NULL,NULL,'42b29d0771f3b7ef',NULL,'0.91641750830823','0.27291712562825');
51
(50,'23529001223636','Peters','Tommy',NULL,NULL,'',NULL,NULL,'5171 Library Rd.',NULL,'Portland, ME','44236',NULL,'(212) 555-1212',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'1951-06-14','SPL','PT','1984-05-09','2020-12-31',NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,'F','23529001223636',NULL,NULL,'42b29d0771f3b7ef','0.91641750830823','0.27291712562825');
(-)a/installer/data/mysql/kohastructure.sql (-35 / +43 lines)
Lines 610-616 CREATE TABLE `deletedborrowers` ( -- stores data related to the patrons/borrower Link Here
610
  `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor
610
  `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor
611
  `sex` varchar(1) default NULL, -- patron/borrower's gender
611
  `sex` varchar(1) default NULL, -- patron/borrower's gender
612
  `password` varchar(60) default NULL, -- patron/borrower's encrypted password
612
  `password` varchar(60) default NULL, -- patron/borrower's encrypted password
613
  `flags` int(11) default NULL, -- will include a number associated with the staff member's permissions
614
  `userid` varchar(75) default NULL, -- patron/borrower's opac and/or staff client log in
613
  `userid` varchar(75) default NULL, -- patron/borrower's opac and/or staff client log in
615
  `opacnote` mediumtext, -- a note on the patron/borrower's account that is visible in the OPAC and staff client
614
  `opacnote` mediumtext, -- a note on the patron/borrower's account that is visible in the OPAC and staff client
616
  `contactnote` varchar(255) default NULL, -- a note related to the patron/borrower's alternate address
615
  `contactnote` varchar(255) default NULL, -- a note related to the patron/borrower's alternate address
Lines 1642-1648 CREATE TABLE `borrowers` ( -- this table includes information about your patrons Link Here
1642
  `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor
1641
  `relationship` varchar(100) default NULL, -- used for children to include the relationship to their guarentor
1643
  `sex` varchar(1) default NULL, -- patron/borrower's gender
1642
  `sex` varchar(1) default NULL, -- patron/borrower's gender
1644
  `password` varchar(60) default NULL, -- patron/borrower's encrypted password
1643
  `password` varchar(60) default NULL, -- patron/borrower's encrypted password
1645
  `flags` int(11) default NULL, -- will include a number associated with the staff member's permissions
1646
  `userid` varchar(75) default NULL, -- patron/borrower's opac and/or staff client log in
1644
  `userid` varchar(75) default NULL, -- patron/borrower's opac and/or staff client log in
1647
  `opacnote` mediumtext, -- a note on the patron/borrower's account that is visible in the OPAC and staff client
1645
  `opacnote` mediumtext, -- a note on the patron/borrower's account that is visible in the OPAC and staff client
1648
  `contactnote` varchar(255) default NULL, -- a note related to the patron/borrower's alternate address
1646
  `contactnote` varchar(255) default NULL, -- a note related to the patron/borrower's alternate address
Lines 2235-2249 CREATE TABLE `tags_index` ( -- a weighted list of all tags and where they are us Link Here
2235
-- Table structure for table `userflags`
2233
-- Table structure for table `userflags`
2236
--
2234
--
2237
2235
2238
DROP TABLE IF EXISTS `userflags`;
2239
CREATE TABLE `userflags` (
2240
  `bit` int(11) NOT NULL default 0,
2241
  `flag` varchar(30) default NULL,
2242
  `flagdesc` varchar(255) default NULL,
2243
  `defaulton` int(11) default NULL,
2244
  PRIMARY KEY  (`bit`)
2245
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2246
2247
--
2236
--
2248
-- Table structure for table `virtualshelves`
2237
-- Table structure for table `virtualshelves`
2249
--
2238
--
Lines 2425-2444 CREATE TABLE language_script_mapping ( Link Here
2425
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2414
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2426
2415
2427
--
2416
--
2428
-- Table structure for table `permissions`
2429
--
2430
2431
DROP TABLE IF EXISTS `permissions`;
2432
CREATE TABLE `permissions` (
2433
  `module_bit` int(11) NOT NULL DEFAULT 0,
2434
  `code` varchar(64) NOT NULL DEFAULT '',
2435
  `description` varchar(255) DEFAULT NULL,
2436
  PRIMARY KEY  (`module_bit`, `code`),
2437
  CONSTRAINT `permissions_ibfk_1` FOREIGN KEY (`module_bit`) REFERENCES `userflags` (`bit`)
2438
    ON DELETE CASCADE ON UPDATE CASCADE
2439
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2440
2441
--
2442
-- Table structure for table `serialitems`
2417
-- Table structure for table `serialitems`
2443
--
2418
--
2444
2419
Lines 2453-2473 CREATE TABLE `serialitems` ( Link Here
2453
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2428
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2454
2429
2455
--
2430
--
2456
-- Table structure for table `user_permissions`
2431
-- Table structure for table permission_modules
2457
--
2432
--
2458
2433
2459
DROP TABLE IF EXISTS `user_permissions`;
2434
DROP TABLE IF EXISTS permission_modules;
2460
CREATE TABLE `user_permissions` (
2435
CREATE TABLE permission_modules (
2461
  `borrowernumber` int(11) NOT NULL DEFAULT 0,
2436
  permission_module_id int(11) NOT NULL auto_increment,
2462
  `module_bit` int(11) NOT NULL DEFAULT 0,
2437
  module varchar(32) NOT NULL,
2463
  `code` varchar(64) DEFAULT NULL,
2438
  description varchar(255) DEFAULT NULL,
2464
  CONSTRAINT `user_permissions_ibfk_1` FOREIGN KEY (`borrowernumber`) REFERENCES `borrowers` (`borrowernumber`)
2439
  PRIMARY KEY  (permission_module_id),
2465
    ON DELETE CASCADE ON UPDATE CASCADE,
2440
  UNIQUE KEY (module)
2466
  CONSTRAINT `user_permissions_ibfk_2` FOREIGN KEY (`module_bit`, `code`) REFERENCES `permissions` (`module_bit`, `code`)
2441
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2442
2443
--
2444
-- Table structure for table `permissions`
2445
--
2446
2447
DROP TABLE IF EXISTS permissions;
2448
CREATE TABLE permissions (
2449
  permission_id int(11) NOT NULL auto_increment,
2450
  module varchar(32) NOT NULL,
2451
  code varchar(64) NOT NULL,
2452
  description varchar(255) DEFAULT NULL,
2453
  PRIMARY KEY  (permission_id),
2454
  UNIQUE KEY (code),
2455
  CONSTRAINT permissions_to_modules_ibfk1 FOREIGN KEY (module) REFERENCES permission_modules (module)
2467
    ON DELETE CASCADE ON UPDATE CASCADE
2456
    ON DELETE CASCADE ON UPDATE CASCADE
2468
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2457
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2469
2458
2470
--
2459
--
2460
-- Table structure for table borrower_permissions
2461
--
2462
2463
DROP TABLE IF EXISTS borrower_permissions;
2464
CREATE TABLE borrower_permissions (
2465
  borrower_permission_id int(11) NOT NULL auto_increment,
2466
  borrowernumber int(11) NOT NULL,
2467
  permission_module_id int(11) NOT NULL,
2468
  permission_id int(11) NOT NULL,
2469
  PRIMARY KEY  (borrower_permission_id),
2470
  UNIQUE KEY (borrowernumber, permission_module_id, permission_id),
2471
  CONSTRAINT borrower_permissions_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber)
2472
     ON DELETE CASCADE ON UPDATE CASCADE,
2473
  CONSTRAINT borrower_permissions_ibfk_2 FOREIGN KEY (permission_id) REFERENCES permissions (permission_id)
2474
    ON DELETE CASCADE ON UPDATE CASCADE,
2475
  CONSTRAINT borrower_permissions_ibfk_3 FOREIGN KEY (permission_module_id) REFERENCES permission_modules (permission_module_id)
2476
     ON DELETE CASCADE ON UPDATE CASCADE
2477
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2478
2479
--
2471
-- Table structure for table `tmp_holdsqueue`
2480
-- Table structure for table `tmp_holdsqueue`
2472
--
2481
--
2473
2482
Lines 3420-3426 CREATE TABLE IF NOT EXISTS `borrower_modifications` ( Link Here
3420
  `relationship` varchar(100) DEFAULT NULL,
3429
  `relationship` varchar(100) DEFAULT NULL,
3421
  `sex` varchar(1) DEFAULT NULL,
3430
  `sex` varchar(1) DEFAULT NULL,
3422
  `password` varchar(30) DEFAULT NULL,
3431
  `password` varchar(30) DEFAULT NULL,
3423
  `flags` int(11) DEFAULT NULL,
3424
  `userid` varchar(75) DEFAULT NULL,
3432
  `userid` varchar(75) DEFAULT NULL,
3425
  `opacnote` mediumtext,
3433
  `opacnote` mediumtext,
3426
  `contactnote` varchar(255) DEFAULT NULL,
3434
  `contactnote` varchar(255) DEFAULT NULL,
(-)a/installer/data/mysql/userflags.sql (-21 / +21 lines)
Lines 1-22 Link Here
1
INSERT INTO userflags (bit, flag, flagdesc, defaulton) VALUES
1
INSERT INTO permission_modules (module, description) VALUES
2
(0,'superlibrarian','Access to all librarian functions',0),
2
('superlibrarian','Access to all librarian functions'),
3
(1,'circulate','Check out and check in items',0),
3
('circulate','Check out and check in items'),
4
(2,'catalogue','<b>Required for staff login.</b> Staff access, allows viewing of catalogue in staff client.',0),
4
('catalogue','<b>Required for staff login.</b> Staff access, allows viewing of catalogue in staff client.'),
5
(3,'parameters','Manage Koha system settings (Administration panel)',0),
5
('parameters','Manage Koha system settings (Administration panel)'),
6
(4,'borrowers','Add or modify patrons',0),
6
('borrowers','Add or modify patrons'),
7
(5,'permissions','Set user permissions',0),
7
('permissions','Set user permissions'),
8
(6,'reserveforothers','Place and modify holds for patrons',0),
8
('reserveforothers','Place and modify holds for patrons'),
9
(9,'editcatalogue','Edit catalog (Modify bibliographic/holdings data)',0),
9
('editcatalogue','Edit catalog (Modify bibliographic/holdings data)'),
10
(10,'updatecharges','Manage patrons fines and fees',0),
10
('updatecharges','Manage patrons fines and fees'),
11
(11,'acquisition','Acquisition and/or suggestion management',0),
11
('acquisition','Acquisition and/or suggestion management'),
12
(12,'management','Set library management parameters (deprecated)',0),
12
('management','Set library management parameters (deprecated)'),
13
(13,'tools','Use all tools (expand for granular tools permissions)',0),
13
('tools','Use all tools (expand for granular tools permissions)'),
14
(14,'editauthorities','Edit authorities',0),
14
('editauthorities','Edit authorities'),
15
(15,'serials','Manage serial subscriptions',0),
15
('serials','Manage serial subscriptions'),
16
(16,'reports','Allow access to the reports module',0),
16
('reports','Allow access to the reports module'),
17
(17,'staffaccess','Allow staff members to modify permissions for other staff members',0),
17
('staffaccess','Allow staff members to modify permissions for other staff members'),
18
(18,'coursereserves','Course reserves',0),
18
('coursereserves','Course reserves'),
19
(19, 'plugins', 'Koha plugins', '0'),
19
('plugins', 'Koha plugins'),
20
(20, 'lists', 'Lists', 0),
20
('lists', 'Lists'),
21
(21, 'clubs', 'Patron clubs', '0')
21
('clubs', 'Patron clubs')
22
;
22
;
(-)a/installer/data/mysql/userpermissions.sql (-84 / +86 lines)
Lines 1-85 Link Here
1
INSERT INTO permissions (module_bit, code, description) VALUES
1
INSERT INTO permissions (module, code, description) VALUES
2
   ( 1, 'circulate_remaining_permissions', 'Remaining circulation permissions'),
2
   ( 'superlibrarian',  'superlibrarian', 'Access to all librarian functions'),
3
   ( 1, 'override_renewals', 'Override blocked renewals'),
3
   ( 'circulate',       'circulate_remaining_permissions', 'Remaining circulation permissions'),
4
   ( 1, 'overdues_report', 'Execute overdue items report'),
4
   ( 'circulate',       'override_renewals', 'Override blocked renewals'),
5
   ( 1, 'force_checkout', 'Force checkout if a limitation exists'),
5
   ( 'circulate',       'overdues_report', 'Execute overdue items report'),
6
   ( 1, 'manage_restrictions', 'Manage restrictions for accounts'),
6
   ( 'circulate',       'force_checkout', 'Force checkout if a limitation exists'),
7
   ( 1, 'self_checkout', 'Perform self checkout at the OPAC. It should be used for the patron matching the AutoSelfCheckID'),
7
   ( 'circulate',       'manage_restrictions', 'Manage restrictions for accounts'),
8
   ( 3, 'parameters_remaining_permissions', 'Remaining system parameters permissions'),
8
   ( 'catalogue',       'staff_login', 'Allow staff login.'),
9
   ( 3, 'manage_circ_rules', 'Manage circulation rules'),
9
   ( 'parameters',      'parameters_remaining_permissions', 'Remaining system parameters permissions'),
10
   ( 6, 'place_holds', 'Place holds for patrons'),
10
   ( 'parameters',      'manage_circ_rules', 'manage circulation rules'),
11
   ( 6, 'modify_holds_priority', 'Modify holds priority'),
11
   ( 'borrowers',       'view_borrowers', 'Show borrower details and search for borrowers.'),
12
   ( 9, 'edit_catalogue', 'Edit catalog (Modify bibliographic/holdings data)'),
12
   ( 'permissions',     'set_permissions', 'Set user permissions'),
13
   ( 9, 'fast_cataloging', 'Fast cataloging'),
13
   ( 'reserveforothers','place_holds', 'Place holds for patrons'),
14
   ( 9, 'edit_items', 'Edit items'),
14
   ( 'reserveforothers','modify_holds_priority', 'Modify holds priority'),
15
   ( 9, 'edit_items_restricted', 'Limit item modification to subfields defined in the SubfieldsToAllowForRestrictedEditing preference (please note that edit_item is still required)'),
15
   ( 'editcatalogue',   'edit_catalogue', 'Edit catalog (Modify bibliographic/holdings data)'),
16
   ( 9, 'delete_all_items', 'Delete all items at once'),
16
   ( 'editcatalogue',   'fast_cataloging', 'Fast cataloging'),
17
   (10, 'writeoff', 'Write off fines and fees'),
17
   ( 'editcatalogue',   'edit_items', 'Edit items'),
18
   (10, 'remaining_permissions', 'Remaining permissions for managing fines and fees'),
18
   ( 'editcatalogue',   'edit_items_restricted', 'Limit item modification to subfields defined in the SubfieldsToAllowForRestrictedEditing preference (please note that edit_item is still required)'),
19
   (11, 'vendors_manage', 'Manage vendors'),
19
   ( 'editcatalogue',   'delete_all_items', 'Delete all items at once'),
20
   (11, 'contracts_manage', 'Manage contracts'),
20
   ( 'updatecharges',   'writeoff', 'Write off fines and fees'),
21
   (11, 'period_manage', 'Manage periods'),
21
   ( 'updatecharges',   'remaining_permissions', 'Remaining permissions for managing fines and fees'),
22
   (11, 'budget_manage', 'Manage budgets'),
22
   ( 'acquisition',     'vendors_manage', 'Manage vendors'),
23
   (11, 'budget_modify', 'Modify budget (can''t create lines, but can modify existing ones)'),
23
   ( 'acquisition',     'contracts_manage', 'Manage contracts'),
24
   (11, 'planning_manage', 'Manage budget plannings'),
24
   ( 'acquisition',     'period_manage', 'Manage periods'),
25
   (11, 'order_manage', 'Manage orders & basket'),
25
   ( 'acquisition',     'budget_manage', 'Manage budgets'),
26
   (11, 'order_manage_all', 'Manage all orders and baskets, regardless of restrictions on them'),
26
   ( 'acquisition',     'budget_modify', 'Modify budget (can''t create lines, but can modify existing ones)'),
27
   (11, 'group_manage', 'Manage orders & basketgroups'),
27
   ( 'acquisition',     'planning_manage', 'Manage budget plannings'),
28
   (11, 'order_receive', 'Manage orders & basket'),
28
   ( 'acquisition',     'order_manage', 'Manage orders & basket'),
29
   (11, 'budget_add_del', 'Add and delete budgets (but can''t modify budgets)'),
29
   ( 'acquisition',     'order_manage_all', 'Manage all orders and baskets, regardless of restrictions on them'),
30
   (11, 'budget_manage_all', 'Manage all budgets'),
30
   ( 'acquisition',     'group_manage', 'Manage orders & basketgroups'),
31
   (11, 'edi_manage', 'Manage EDIFACT transmissions'),
31
   ( 'acquisition',     'order_receive', 'Manage orders & basket'),
32
   (13, 'edit_news', 'Write news for the OPAC and staff interfaces'),
32
   ( 'acquisition',     'budget_add_del', 'Add and delete budgets (but can''t modify budgets)'),
33
   (13, 'label_creator', 'Create printable labels and barcodes from catalog and patron data'),
33
   ( 'acquisition',     'budget_manage_all', 'Manage all budgets'),
34
   (13, 'edit_calendar', 'Define days when the library is closed'),
34
   ( 'management',      'management', 'Set library management parameters (deprecated)'),
35
   (13, 'moderate_comments', 'Moderate patron comments'),
35
   ( 'tools',           'edit_news', 'Write news for the OPAC and staff interfaces'),
36
   (13, 'edit_notices', 'Define notices'),
36
   ( 'tools',           'label_creator', 'Create printable labels and barcodes from catalog and patron data'),
37
   (13, 'edit_notice_status_triggers', 'Set notice/status triggers for overdue items'),
37
   ( 'tools',           'edit_calendar', 'Define days when the library is closed'),
38
   (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
38
   ( 'tools',           'moderate_comments', 'Moderate patron comments'),
39
   (13, 'view_system_logs', 'Browse the system logs'),
39
   ( 'tools',           'edit_notices', 'Define notices'),
40
   (13, 'inventory', 'Perform inventory (stocktaking) of your catalog'),
40
   ( 'tools',           'edit_notice_status_triggers', 'Set notice/status triggers for overdue items'),
41
   (13, 'stage_marc_import', 'Stage MARC records into the reservoir'),
41
   ( 'tools',           'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
42
   (13, 'manage_staged_marc', 'Manage staged MARC records, including completing and reversing imports'),
42
   ( 'tools',           'view_system_logs', 'Browse the system logs'),
43
   (13, 'export_catalog', 'Export bibliographic and holdings data'),
43
   ( 'tools',           'inventory', 'Perform inventory (stocktaking) of your catalog'),
44
   (13, 'import_patrons', 'Import patron data'),
44
   ( 'tools',           'stage_marc_import', 'Stage MARC records into the reservoir'),
45
   (13, 'edit_patrons', 'Perform batch modification of patrons'),
45
   ( 'tools',           'manage_staged_marc', 'Managed staged MARC records, including completing and reversing imports'),
46
   (13, 'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
46
   ( 'tools',           'export_catalog', 'Export bibliographic and holdings data'),
47
   (13, 'batch_upload_patron_images', 'Upload patron images in a batch or one at a time'),
47
   ( 'tools',           'import_patrons', 'Import patron data'),
48
   (13, 'schedule_tasks', 'Schedule tasks to run'),
48
   ( 'tools',           'edit_patrons', 'Perform batch modification of patrons'),
49
   (13, 'items_batchmod', 'Perform batch modification of items'),
49
   ( 'tools',           'delete_anonymize_patrons', 'Delete old borrowers and anonymize circulation history (deletes borrower reading history)'),
50
   (13, 'items_batchmod_restricted', 'Limit batch item modification to subfields defined in the SubfieldsToAllowForRestrictedBatchmod preference (please note that items_batchmod is still required)'),
50
   ( 'tools',           'batch_upload_patron_images', 'Upload patron images in a batch or one at a time'),
51
   (13, 'items_batchdel', 'Perform batch deletion of items'),
51
   ( 'tools',           'schedule_tasks', 'Schedule tasks to run'),
52
   (13, 'manage_csv_profiles', 'Manage CSV export profiles'),
52
   ( 'tools',           'items_batchmod', 'Perform batch modification of items'),
53
   (13, 'moderate_tags', 'Moderate patron tags'),
53
   ( 'tools',           'items_batchmod_restricted', 'Limit batch item modification to subfields defined in the SubfieldsToAllowForRestrictedBatchmod preference (please note that items_batchmod is still required)'),
54
   (13, 'rotating_collections', 'Manage rotating collections'),
54
   ( 'tools',           'items_batchdel', 'Perform batch deletion of items'),
55
   (13, 'upload_local_cover_images', 'Upload local cover images'),
55
   ( 'tools',           'manage_csv_profiles', 'Manage CSV export profiles'),
56
   (13, 'manage_patron_lists', 'Add, edit and delete patron lists and their contents'),
56
   ( 'tools',           'moderate_tags', 'Moderate patron tags'),
57
   (13, 'records_batchmod', 'Perform batch modification of records (biblios or authorities)'),
57
   ( 'tools',           'rotating_collections', 'Manage rotating collections'),
58
   (13, 'marc_modification_templates', 'Manage marc modification templates'),
58
   ( 'tools',           'upload_local_cover_images', 'Upload local cover images'),
59
   (13, 'records_batchdel', 'Perform batch deletion of records (bibliographic or authority)'),
59
   ( 'tools',           'manage_patron_lists', 'Add, edit and delete patron lists and their contents'),
60
   (13, 'upload_general_files', 'Upload any file'),
60
   ( 'tools',           'records_batchmod', 'Perform batch modification of records (biblios or authorities)'),
61
   (13, 'upload_manage', 'Manage uploaded files'),
61
   ( 'tools',           'marc_modification_templates', 'Manage marc modification templates'),
62
   (15, 'check_expiration', 'Check the expiration of a serial'),
62
   ( 'tools',           'records_batchdel', 'Perform batch deletion of records (bibliographic or authority)'),
63
   (15, 'claim_serials', 'Claim missing serials'),
63
   ( 'editauthorities', 'edit_authorities', 'Edit authorities'),
64
   (15, 'create_subscription', 'Create a new subscription'),
64
   ( 'serials',         'check_expiration', 'Check the expiration of a serial'),
65
   (15, 'delete_subscription', 'Delete an existing subscription'),
65
   ( 'serials',         'claim_serials', 'Claim missing serials'),
66
   (15, 'edit_subscription', 'Edit an existing subscription'),
66
   ( 'serials',         'create_subscription', 'Create a new subscription'),
67
   (15, 'receive_serials', 'Serials receiving'),
67
   ( 'serials',         'delete_subscription', 'Delete an existing subscription'),
68
   (15, 'renew_subscription', 'Renew a subscription'),
68
   ( 'serials',         'edit_subscription', 'Edit an existing subscription'),
69
   (15, 'routing', 'Routing'),
69
   ( 'serials',         'receive_serials', 'Serials receiving'),
70
   (15, 'superserials', 'Manage subscriptions from any branch (only applies when IndependentBranches is used)'),
70
   ( 'serials',         'renew_subscription', 'Renew a subscription'),
71
   (16, 'execute_reports', 'Execute SQL reports'),
71
   ( 'serials',         'routing', 'Routing'),
72
   (16, 'create_reports', 'Create SQL reports'),
72
   ( 'serials',         'superserials', 'Manage subscriptions from any branch (only applies when IndependentBranches is used)'),
73
   (16, 'delete_reports', 'Delete SQL reports'),
73
   ( 'reports',         'execute_reports', 'Execute SQL reports'),
74
   (18, 'manage_courses', 'Add, edit and delete courses'),
74
   ( 'reports',         'create_reports', 'Create SQL reports'),
75
   (18, 'add_reserves', 'Add course reserves'),
75
   ( 'staffaccess',     'staff_access_permissions', 'Allow staff members to modify permissions for other staff members'),
76
   (18, 'delete_reserves', 'Remove course reserves'),
76
   ( 'coursereserves',  'manage_courses', 'Add, edit and delete courses'),
77
   (19, 'manage', 'Manage plugins ( install / uninstall )'),
77
   ( 'coursereserves',  'add_reserves', 'Add course reserves'),
78
   (19, 'tool', 'Use tool plugins'),
78
   ( 'coursereserves',  'delete_reserves', 'Remove course reserves'),
79
   (19, 'report', 'Use report plugins'),
79
   ( 'plugins',         'manage', 'Manage plugins ( install / uninstall )'),
80
   (19, 'configure', 'Configure plugins'),
80
   ( 'plugins',         'tool', 'Use tool plugins'),
81
   (20, 'delete_public_lists', 'Delete public lists'),
81
   ( 'plugins',         'report', 'Use report plugins'),
82
   (21, 'edit_templates', 'Create and update club templates'),
82
   ( 'plugins',         'configure', 'Configure plugins'),
83
   (21, 'edit_clubs', 'Create and update clubs'),
83
   ( 'lists',           'delete_public_lists', 'Delete public lists'),
84
   (21, 'enroll', 'Enroll patrons in clubs')
84
   ( 'clubs',           'edit_templates', 'Create and update club templates'),
85
   ( 'clubs',           'edit_clubs', 'Create and update clubs'),
86
   ( 'clubs',           'enroll', 'Enroll patrons in clubs')
85
;
87
;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/member-flags.tt (-7 / +7 lines)
Lines 11-33 Link Here
11
        $("#permissionstree").treeview({animated: "fast", collapsed: true});
11
        $("#permissionstree").treeview({animated: "fast", collapsed: true});
12
12
13
        // Enforce Superlibrarian Privilege Mutual Exclusivity
13
        // Enforce Superlibrarian Privilege Mutual Exclusivity
14
        if($('input[id="flag-0"]:checked').length){
14
        if($('input[id="flag-superlibrarian"]:checked').length){
15
            if ($('input[name="flag"]:checked').length > 1){
15
            if ($('input[name="flag"]:checked').length > 1){
16
                alert(_("Inconsistency detected! The superlibrarian privilege is mutually exclusive of other privileges, as it includes them all. This patron's privileges will now be reset to include only superlibrarian."));
16
                alert(_("Inconsistency detected! The superlibrarian privilege is mutually exclusive of other privileges, as it includes them all. This patron's privileges will now be reset to include only superlibrarian."));
17
            }
17
            }
18
18
19
            $('input[name="flag"]').each(function() {
19
            $('input[name="flag"]').each(function() {
20
                if($(this).attr('id') != "flag-0"){
20
                if($(this).attr('id') != "flag-superlibrarian"){
21
                    $(this).prop('disabled', true);
21
                    $(this).prop('disabled', true);
22
                    $(this).prop('checked', false);
22
                    $(this).prop('checked', false);
23
                }
23
                }
24
            });
24
            });
25
        }
25
        }
26
26
27
        $('input#flag-0').click(function() {
27
        $('input#flag-superlibrarian').click(function() {
28
            if($('input[id="flag-0"]:checked').length){
28
            if($('input[id="flag-superlibrarian"]:checked').length){
29
                $('input[name="flag"]').each(function() {
29
                $('input[name="flag"]').each(function() {
30
                    if($(this).attr('id') != "flag-0"){
30
                    if($(this).attr('id') != "flag-superlibrarian"){
31
                        $(this).prop('disabled', true);
31
                        $(this).prop('disabled', true);
32
                        $(this).prop('checked', false);
32
                        $(this).prop('checked', false);
33
                    }
33
                    }
Lines 131-139 Link Here
131
        <!-- <li class="folder-close">One level down<ul> -->
131
        <!-- <li class="folder-close">One level down<ul> -->
132
    [% FOREACH loo IN loop %]
132
    [% FOREACH loo IN loop %]
133
        [% IF ( loo.expand ) %]
133
        [% IF ( loo.expand ) %]
134
        <li class="open">
134
        <li class="[% loo.flag %] open">
135
        [% ELSE %]
135
        [% ELSE %]
136
        <li>
136
        <li class="[% loo.flag %]">
137
        [% END %]
137
        [% END %]
138
			[% IF ( loo.checked ) %]
138
			[% IF ( loo.checked ) %]
139
                <input type="checkbox" class="flag parent" id="flag-[% loo.bit %]" name="flag" value="[% loo.flag %]" checked="checked" />
139
                <input type="checkbox" class="flag parent" id="flag-[% loo.bit %]" name="flag" value="[% loo.flag %]" checked="checked" />
(-)a/members/member-flags.pl (-103 / +91 lines)
Lines 13-19 use C4::Auth qw(:DEFAULT :EditPermissions); Link Here
13
use C4::Context;
13
use C4::Context;
14
use C4::Members;
14
use C4::Members;
15
use C4::Members::Attributes qw(GetBorrowerAttributes);
15
use C4::Members::Attributes qw(GetBorrowerAttributes);
16
#use C4::Acquisitions;
16
use Koha::Auth::PermissionManager;
17
18
use Koha::Exception::BadParameter;
17
19
18
use Koha::Patron::Categories;
20
use Koha::Patron::Categories;
19
21
Lines 38-44 my ($template, $loggedinuser, $cookie) = get_template_and_user({ Link Here
38
        debug           => 1,
40
        debug           => 1,
39
});
41
});
40
42
41
43
my $permissionManager = Koha::Auth::PermissionManager->new();
42
my %member2;
44
my %member2;
43
$member2{'borrowernumber'}=$member;
45
$member2{'borrowernumber'}=$member;
44
46
Lines 52-173 if ($input->param('newflags')) { Link Here
52
54
53
55
54
    my $dbh=C4::Context->dbh();
56
    my $dbh=C4::Context->dbh();
55
57
    #Cast CGI-params into a permissions HASH.
56
    my @perms = $input->multi_param('flag');
58
    my @perms = $input->multi_param('flag');
57
    my %all_module_perms = ();
58
    my %sub_perms = ();
59
    my %sub_perms = ();
59
    foreach my $perm (@perms) {
60
    foreach my $perm (@perms) {
60
        if ($perm !~ /:/) {
61
        if ($perm eq 'superlibrarian') {
61
            $all_module_perms{$perm} = 1;
62
            $sub_perms{superlibrarian}->{superlibrarian} = 1;
63
        }
64
        elsif ($perm !~ /:/) {
65
            #DEPRECATED, GUI still sends the module flags here even though they have been removed from the DB.
62
        } else {
66
        } else {
63
            my ($module, $sub_perm) = split /:/, $perm, 2;
67
            my ($module, $sub_perm) = split /:/, $perm, 2;
64
            push @{ $sub_perms{$module} }, $sub_perm;
68
	    $sub_perms{$module}->{$sub_perm} = 1;
65
        }
69
        }
66
    }
70
    }
67
71
68
    # construct flags
72
    $permissionManager->revokeAllPermissions($member);
69
    my $module_flags = 0;
73
    $permissionManager->grantPermissions($member, \%sub_perms);
70
    my $sth=$dbh->prepare("SELECT bit,flag FROM userflags ORDER BY bit");
71
    $sth->execute();
72
    while (my ($bit, $flag) = $sth->fetchrow_array) {
73
        if (exists $all_module_perms{$flag}) {
74
            $module_flags += 2**$bit;
75
        }
76
    }
77
    
78
    $sth = $dbh->prepare("UPDATE borrowers SET flags=? WHERE borrowernumber=?");
79
    $sth->execute($module_flags, $member);
80
    
81
    # deal with subpermissions
82
    $sth = $dbh->prepare("DELETE FROM user_permissions WHERE borrowernumber = ?");
83
    $sth->execute($member); 
84
    $sth = $dbh->prepare("INSERT INTO user_permissions (borrowernumber, module_bit, code)
85
                        SELECT ?, bit, ?
86
                        FROM userflags
87
                        WHERE flag = ?");
88
    foreach my $module (keys %sub_perms) {
89
        next if exists $all_module_perms{$module};
90
        foreach my $sub_perm (@{ $sub_perms{$module} }) {
91
            $sth->execute($member, $sub_perm, $module);
92
        }
93
    }
94
    
74
    
95
    print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$member");
75
    print $input->redirect("/cgi-bin/koha/members/moremember.pl?borrowernumber=$member");
96
} else {
76
} else {
97
77
98
    my $flags = C4::Members::patronflags( $bor );
78
    my $all_perms  = $permissionManager->listKohaPermissionsAsHASH();
99
    my $accessflags;
79
    my $user_perms = $permissionManager->getBorrowerPermissions($member);
100
    my $dbh = C4::Context->dbh();
101
    # FIXME This needs to be improved to avoid doing the same query
102
    my $sth = $dbh->prepare("select bit,flag from userflags");
103
    $sth->execute;
104
    while ( my ( $bit, $flag ) = $sth->fetchrow ) {
105
        if ( $bor->{flags} && $bor->{flags} & 2**$bit ) {
106
            $accessflags->{$flag} = 1;
107
        }
108
    }
109
80
110
    my $all_perms  = get_all_subpermissions();
81
    $all_perms = markBorrowerGrantedPermissions($all_perms, $user_perms);
111
    my $user_perms = get_user_subpermissions($bor->{'userid'});
112
    $sth = $dbh->prepare("SELECT bit, flag FROM userflags ORDER BY bit");
113
    $sth->execute;
114
    my @loop;
82
    my @loop;
115
83
116
    while (my ($bit, $flag) = $sth->fetchrow) {
84
    push @loop, preparePermissionModuleForDisplay($all_perms, 'superlibrarian');
117
	    my $checked='';
85
    foreach my $module (sort(keys(%$all_perms))) {
118
	    if ($accessflags->{$flag}) {
86
    push @loop, preparePermissionModuleForDisplay($all_perms, $module) unless $module eq 'superlibrarian';
119
	        $checked= 1;
120
	    }
121
122
	    my %row = ( bit => $bit,
123
		    flag => $flag,
124
		    checked => $checked,
125
        );
126
127
        my @sub_perm_loop = ();
128
        my $expand_parent = 0;
129
        if ($checked) {
130
            if (exists $all_perms->{$flag}) {
131
                $expand_parent = 1;
132
                foreach my $sub_perm (sort keys %{ $all_perms->{$flag} }) {
133
                    push @sub_perm_loop, {
134
                        id => "${flag}_$sub_perm",
135
                        perm => "$flag:$sub_perm",
136
                        code => $sub_perm,
137
                        checked => 1
138
                    };
139
                }
140
            }
141
        } else {
142
            if (exists $user_perms->{$flag}) {
143
                $expand_parent = 1;
144
                # put selected ones first
145
                foreach my $sub_perm (sort keys %{ $user_perms->{$flag} }) {
146
                    push @sub_perm_loop, {
147
                        id => "${flag}_$sub_perm",
148
                        perm => "$flag:$sub_perm",
149
                        code => $sub_perm,
150
                        checked => 1
151
                    };
152
                }
153
            }
154
            # then ones not selected
155
            if (exists $all_perms->{$flag}) {
156
                foreach my $sub_perm (sort keys %{ $all_perms->{$flag} }) {
157
                    push @sub_perm_loop, {
158
                        id => "${flag}_$sub_perm",
159
                        perm => "$flag:$sub_perm",
160
                        code => $sub_perm,
161
                        checked => 0
162
                    } unless exists $user_perms->{$flag} and exists $user_perms->{$flag}->{$sub_perm};
163
                }
164
            }
165
        }
166
        $row{expand} = $expand_parent;
167
        if ($#sub_perm_loop > -1) {
168
            $row{sub_perm_loop} = \@sub_perm_loop;
169
        }
170
	    push @loop, \%row;
171
    }
87
    }
172
88
173
    if ( $bor->{'category_type'} eq 'C') {
89
    if ( $bor->{'category_type'} eq 'C') {
Lines 219-221 $template->param( Link Here
219
    output_html_with_http_headers $input, $cookie, $template->output;
135
    output_html_with_http_headers $input, $cookie, $template->output;
220
136
221
}
137
}
138
139
=head markBorrowerGrantedPermissions
140
141
Adds a 'checked'-value for all subpermissions in the all-Koha-Permissions-list
142
that the current borrower has been granted.
143
@PARAM1 HASHRef of all Koha permissions and modules.
144
@PARAM1 ARRAYRef of all the granted Koha::Auth::BorrowerPermission-objects.
145
@RETURNS @PARAM1, slightly checked.
146
=cut
147
148
sub markBorrowerGrantedPermissions {
149
	my ($all_perms, $user_perms) = @_;
150
151
	foreach my $borrowerPermission (@$user_perms) {
152
		my $module = $borrowerPermission->getPermissionModule->module;
153
		my $code   = $borrowerPermission->getPermission->code;
154
		$all_perms->{$module}->{permissions}->{$code}->{checked} = 1;
155
	}
156
	return $all_perms;
157
}
158
159
=head checkIfAllModulePermissionsGranted
160
161
@RETURNS Boolean, 1 if all permissions granted.
162
=cut
163
164
sub checkIfAllModulePermissionsGranted {
165
	my ($moduleHash) = @_;
166
	foreach my $code (keys(%{$moduleHash->{permissions}})) {
167
		unless ($moduleHash->{permissions}->{$code}->{checked}) {
168
			return 0;
169
		}
170
	}
171
	return 1;
172
}
173
174
sub preparePermissionModuleForDisplay {
175
	my ($all_perms, $module) = @_;
176
177
	my $moduleHash = $all_perms->{$module};
178
	my $checked = checkIfAllModulePermissionsGranted($moduleHash);
179
180
	my %row = (
181
		bit => $module,
182
		flag => $module,
183
		checked => $checked,
184
		flagdesc => $moduleHash->{description} );
185
186
	my @sub_perm_loop = ();
187
	my $expand_parent = 0;
188
189
	if ($module ne 'superlibrarian') {
190
		foreach my $sub_perm (sort keys %{ $all_perms->{$module}->{permissions} }) {
191
			my $sub_perm_checked = $all_perms->{$module}->{permissions}->{$sub_perm}->{checked};
192
			$expand_parent = 1 if $sub_perm_checked;
193
194
			push @sub_perm_loop, {
195
				id => "${module}_$sub_perm",
196
				perm => "$module:$sub_perm",
197
				code => $sub_perm,
198
				description => $all_perms->{$module}->{permissions}->{$sub_perm}->{description},
199
				checked => $sub_perm_checked || 0,
200
			};
201
		}
202
203
		$row{expand} = $expand_parent;
204
		if ($#sub_perm_loop > -1) {
205
			$row{sub_perm_loop} = \@sub_perm_loop;
206
		}
207
	}
208
	return \%row;
209
}
(-)a/opac/opac-user.pl (-1 / +1 lines)
Lines 293-299 $template->param( Link Here
293
);
293
);
294
294
295
# current alert subscriptions
295
# current alert subscriptions
296
my $alerts = getalert($borrowernumber);
296
my $alerts = getalert($borrowernumber) if $borrowernumber;
297
foreach ( @$alerts ) {
297
foreach ( @$alerts ) {
298
    $_->{ $_->{type} } = 1;
298
    $_->{ $_->{type} } = 1;
299
    $_->{relatedto} = findrelatedto( $_->{type}, $_->{externalid} );
299
    $_->{relatedto} = findrelatedto( $_->{type}, $_->{externalid} );
(-)a/t/Patron.t (-6 / +8 lines)
Lines 93-99 my $patron = Koha::Patron->new( Link Here
93
        relationship        => 'myRelationship',
93
        relationship        => 'myRelationship',
94
        sex                 => 'M',
94
        sex                 => 'M',
95
        password            => 'hfkurhfe976634èj!',
95
        password            => 'hfkurhfe976634èj!',
96
        flags               => '55555',
96
#        flags               => '55555',
97
        userid              => '87987',
97
        userid              => '87987',
98
        opacnote            => 'myOpacnote',
98
        opacnote            => 'myOpacnote',
99
        contactnote         => 'myContactnote',
99
        contactnote         => 'myContactnote',
Lines 115-121 my $patron = Koha::Patron->new( Link Here
115
115
116
# patron Accessor tests
116
# patron Accessor tests
117
subtest 'Accessor tests' => sub {
117
subtest 'Accessor tests' => sub {
118
    plan tests => 65;
118
#    plan tests => 65; #skipped flags test
119
    plan tests => 64;
119
    is( $patron->borrowernumber, '12345',                           'borrowernumber accessor returns correct value' );
120
    is( $patron->borrowernumber, '12345',                           'borrowernumber accessor returns correct value' );
120
    is( $patron->cardnumber,     '1234567890',                      'cardnumber accessor returns correct value' );
121
    is( $patron->cardnumber,     '1234567890',                      'cardnumber accessor returns correct value' );
121
    is( $patron->surname,        'mySurname',                       'surname accessor returns correct value' );
122
    is( $patron->surname,        'mySurname',                       'surname accessor returns correct value' );
Lines 164-170 subtest 'Accessor tests' => sub { Link Here
164
    is( $patron->relationship,        'myRelationship',        'relationship accessor returns correct value' );
165
    is( $patron->relationship,        'myRelationship',        'relationship accessor returns correct value' );
165
    is( $patron->sex,                 'M',                     'sex accessor returns correct value' );
166
    is( $patron->sex,                 'M',                     'sex accessor returns correct value' );
166
    is( $patron->password,            'hfkurhfe976634èj!',    'password accessor returns correct value' );
167
    is( $patron->password,            'hfkurhfe976634èj!',    'password accessor returns correct value' );
167
    is( $patron->flags,               '55555',                 'flags accessor returns correct value' );
168
#    is( $patron->flags,               '55555',                 'flags accessor returns correct value' );
168
    is( $patron->userid,              '87987',                 'userid accessor returns correct value' );
169
    is( $patron->userid,              '87987',                 'userid accessor returns correct value' );
169
    is( $patron->opacnote,            'myOpacnote',            'opacnote accessor returns correct value' );
170
    is( $patron->opacnote,            'myOpacnote',            'opacnote accessor returns correct value' );
170
    is( $patron->contactnote,         'myContactnote',         'contactnote accessor returns correct value' );
171
    is( $patron->contactnote,         'myContactnote',         'contactnote accessor returns correct value' );
Lines 185-191 subtest 'Accessor tests' => sub { Link Here
185
186
186
# patron Set tests
187
# patron Set tests
187
subtest 'Set tests' => sub {
188
subtest 'Set tests' => sub {
188
    plan tests => 65;
189
#    plan tests => 65; skipped flags test
190
    plan tests => 64;
189
191
190
    $patron->set(
192
    $patron->set(
191
        {
193
        {
Lines 237-243 subtest 'Set tests' => sub { Link Here
237
            relationship        => 'SmyRelationship',
239
            relationship        => 'SmyRelationship',
238
            sex                 => 'F',
240
            sex                 => 'F',
239
            password            => 'zerzerzer#',
241
            password            => 'zerzerzer#',
240
            flags               => '666666',
242
#            flags               => '666666',
241
            userid              => '98233',
243
            userid              => '98233',
242
            opacnote            => 'SmyOpacnote',
244
            opacnote            => 'SmyOpacnote',
243
            contactnote         => 'SmyContactnote',
245
            contactnote         => 'SmyContactnote',
Lines 305-311 subtest 'Set tests' => sub { Link Here
305
    is( $patron->relationship,        'SmyRelationship',                  'relationship field set ok' );
307
    is( $patron->relationship,        'SmyRelationship',                  'relationship field set ok' );
306
    is( $patron->sex,                 'F',                                'sex field set ok' );
308
    is( $patron->sex,                 'F',                                'sex field set ok' );
307
    is( $patron->password,            'zerzerzer#',                       'password field set ok' );
309
    is( $patron->password,            'zerzerzer#',                       'password field set ok' );
308
    is( $patron->flags,               '666666',                           'flags field set ok' );
310
#    is( $patron->flags,               '666666',                           'flags field set ok' );
309
    is( $patron->userid,              '98233',                            'userid field set ok' );
311
    is( $patron->userid,              '98233',                            'userid field set ok' );
310
    is( $patron->opacnote,            'SmyOpacnote',                      'opacnote field set ok' );
312
    is( $patron->opacnote,            'SmyOpacnote',                      'opacnote field set ok' );
311
    is( $patron->contactnote,         'SmyContactnote',                   'contactnote field set ok' );
313
    is( $patron->contactnote,         'SmyContactnote',                   'contactnote field set ok' );
(-)a/t/db_dependent/Auth/haspermission.t (-1 / +11 lines)
Lines 20-26 Link Here
20
# along with Koha; if not, see <http://www.gnu.org/licenses>.
20
# along with Koha; if not, see <http://www.gnu.org/licenses>.
21
21
22
use Modern::Perl;
22
use Modern::Perl;
23
use Test::More tests => 13;
23
use Test::More tests => 16;
24
24
25
use Koha::Database;
25
use Koha::Database;
26
use t::lib::TestBuilder;
26
use t::lib::TestBuilder;
Lines 104-108 $r = haspermission( $borr2->{userid}, { Link Here
104
});
104
});
105
is( ref($r), 'HASH', 'Borrower2/tools granular two upload subperms' );
105
is( ref($r), 'HASH', 'Borrower2/tools granular two upload subperms' );
106
106
107
# Check haspermission for undef userid
108
$r = haspermission( undef, undef );
109
is( ref($r), 'HASH', 'ok');
110
111
$r = haspermission( undef, { borrowers => '*' });
112
is( $r, 0, 'ok');
113
114
$r = haspermission( undef, { reserveforothers => 'place_holds' });
115
is( $r, 0, 'ok');
116
107
# End
117
# End
108
$schema->storage->txn_rollback;
118
$schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Auth.t (-6 / +51 lines)
Lines 22-28 use Modern::Perl; Link Here
22
use Test::More;
22
use Test::More;
23
use Try::Tiny; #Even Selenium::Remote::Driver uses Try::Tiny :)
23
use Try::Tiny; #Even Selenium::Remote::Driver uses Try::Tiny :)
24
24
25
use Koha::Auth::PermissionManager;
26
25
use t::lib::Page::Mainpage;
27
use t::lib::Page::Mainpage;
28
use t::lib::Page::Opac::OpacMain;
26
29
27
use t::lib::TestObjects::PatronFactory;
30
use t::lib::TestObjects::PatronFactory;
28
31
Lines 36-52 my $borrowers = $borrowerFactory->createTestGroup([ Link Here
36
             surname    => 'Kivi',
39
             surname    => 'Kivi',
37
             cardnumber => '1A01',
40
             cardnumber => '1A01',
38
             branchcode => 'CPL',
41
             branchcode => 'CPL',
39
             flags      => '1', #superlibrarian, not exactly a very good way of doing permission testing?
40
             userid     => 'mini_admin',
42
             userid     => 'mini_admin',
41
             password   => $password,
43
             password   => $password,
42
            },
44
            },
45
            {firstname  => 'Admin',
46
             surname    => 'Administrative',
47
             cardnumber => 'maxi_admin',
48
             branchcode => 'FPL',
49
             userid     => 'maxi_admin',
50
             password   => $password,
51
            },
43
        ], undef, $testContext);
52
        ], undef, $testContext);
44
53
54
my $permissionManager = Koha::Auth::PermissionManager->new();
55
$permissionManager->grantPermission($borrowers->{'1A01'}, 'catalogue', 'staff_login');
56
$permissionManager->grantPermission($borrowers->{'maxi_admin'}, 'superlibrarian', 'superlibrarian');
57
45
##Test context set, starting testing:
58
##Test context set, starting testing:
46
eval { #run in a eval-block so we don't die without tearing down the test context
59
eval { #run in a eval-block so we don't die without tearing down the test context
47
60
48
    testPasswordLogin();
61
    my $mainpage = t::lib::Page::Mainpage->new();
62
    testPasswordLoginLogout($mainpage);
63
    testSuperuserPasswordLoginLogout($mainpage);
64
    testSuperlibrarianPasswordLoginLogout($mainpage);
65
    $mainpage->quit();
49
66
67
    my $opacmain = t::lib::Page::Opac::OpacMain->new();
68
    testOpacPasswordLoginLogout($opacmain);
69
    testSuperuserPasswordLoginLogout($opacmain);
70
    testOpacSuperlibrarianPasswordLoginLogout($opacmain);
71
    $opacmain->quit();
50
};
72
};
51
if ($@) { #Catch all leaking errors and gracefully terminate.
73
if ($@) { #Catch all leaking errors and gracefully terminate.
52
    warn $@;
74
    warn $@;
Lines 66-72 sub tearDown { Link Here
66
    ###  STARTING TEST IMPLEMENTATIONS         ###
88
    ###  STARTING TEST IMPLEMENTATIONS         ###
67
######################################################
89
######################################################
68
90
69
sub testPasswordLogin {
91
sub testPasswordLoginLogout {
70
    my $mainpage = t::lib::Page::Mainpage->new();
92
    my ($mainpage) = @_;
71
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'1A01'}->userid(), $password)->quit();
93
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'1A01'}->userid(), $password)
72
}
94
             ->isLoggedInBranchCode($borrowers->{'1A01'}->branchcode())
95
             ->doPasswordLogout();
96
}
97
sub testOpacPasswordLoginLogout {
98
    my ($mainpage) = @_;
99
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'1A01'}->userid(), $password)
100
             ->doPasswordLogout();
101
}
102
sub testSuperuserPasswordLoginLogout {
103
    my ($mainpage) = @_;
104
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin(C4::Context->config('user'), C4::Context->config('pass'))
105
             ->doPasswordLogout();
106
}
107
sub testSuperlibrarianPasswordLoginLogout {
108
    my ($mainpage) = @_;
109
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'maxi_admin'}->userid(), $password)
110
             ->isLoggedInBranchCode($borrowers->{'maxi_admin'}->branchcode())
111
             ->doPasswordLogout();
112
}
113
sub testOpacSuperlibrarianPasswordLoginLogout {
114
    my ($mainpage) = @_;
115
    $mainpage->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'maxi_admin'}->userid(), $password)
116
             ->doPasswordLogout();
117
}
(-)a/t/db_dependent/Koha/Auth/BorrowerPermission.t (+102 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More;
22
23
use Koha::Auth::BorrowerPermission;
24
use Koha::Auth::BorrowerPermissions;
25
26
use t::lib::TestObjects::ObjectFactory;
27
use t::lib::TestObjects::PatronFactory;
28
29
##Setting up the test context
30
my $testContext = {};
31
32
my $borrowerFactory = t::lib::TestObjects::PatronFactory->new();
33
my $borrowers = $borrowerFactory->createTestGroup([
34
            {firstname  => 'Olli-Antti',
35
             surname    => 'Kivi',
36
             cardnumber => '1A01',
37
             branchcode => 'CPL',
38
            },
39
            {firstname  => 'Alli-Ontti',
40
             surname    => 'Ivik',
41
             cardnumber => '1A02',
42
             branchcode => 'CPL',
43
            },
44
        ], undef, $testContext);
45
46
##Test context set, starting testing:
47
eval { #run in a eval-block so we don't die without tearing down the test context
48
    ##Basic id-based creation.
49
    my $borrowerPermissionById = Koha::Auth::BorrowerPermission->new({borrowernumber => $borrowers->{'1A01'}->borrowernumber, permission_module_id => 1, permission_id => 1});
50
    $borrowerPermissionById->store();
51
    my @borrowerPermissionById = Koha::Auth::BorrowerPermissions->search({borrowernumber => $borrowers->{'1A01'}->borrowernumber});
52
    is(scalar(@borrowerPermissionById), 1, "BorrowerPermissions, id-based creation:> Borrower has only one permission");
53
    is($borrowerPermissionById[0]->permission_module_id, 1, "BorrowerPermissions, id-based creation:> Same permission_module_id");
54
    is($borrowerPermissionById[0]->permission_id, 1, "BorrowerPermissions, id-based creation:> Same permission_id");
55
56
    ##Basic name-based creation.
57
    my $borrowerPermissionByName = Koha::Auth::BorrowerPermission->new({borrowernumber => $borrowers->{'1A02'}->borrowernumber, permissionModule => 'circulate', permission => 'manage_restrictions'});
58
    $borrowerPermissionByName->store();
59
    my @borrowerPermissionByName = Koha::Auth::BorrowerPermissions->search({borrowernumber => $borrowers->{'1A02'}->borrowernumber});
60
    is(scalar(@borrowerPermissionByName), 1, "BorrowerPermissions, name-based creation:> Borrower has only one permission");
61
    is($borrowerPermissionByName[0]->getPermissionModule->module, 'circulate', "BorrowerPermissions, name-based creation:> Same permission_module");
62
    is($borrowerPermissionByName[0]->getPermission->code, 'manage_restrictions', "BorrowerPermissions, name-based creation:> Same permission");
63
64
    ##Testing setter/getter for Borrower
65
    my $borrower1A01 = $borrowerPermissionById->getBorrower();
66
    is($borrower1A01->cardnumber, "1A01", "BorrowerPermissions, setter/getter:> getBorrower() 1A01");
67
    my $borrower1A02 = $borrowerPermissionByName->getBorrower();
68
    is($borrower1A02->cardnumber, "1A02", "BorrowerPermissions, setter/getter:> getBorrower() 1A02");
69
70
    $borrowerPermissionById->setBorrower($borrower1A02);
71
    is($borrowerPermissionById->getBorrower()->cardnumber, "1A02", "BorrowerPermissions, setter/getter:> setBorrower() 1A02");
72
    $borrowerPermissionByName->setBorrower($borrower1A01);
73
    is($borrowerPermissionByName->getBorrower()->cardnumber, "1A01", "BorrowerPermissions, setter/getter:> setBorrower() 1A01");
74
75
    ##Testing getter for PermissionModule
76
    my $permissionModule1 = $borrowerPermissionById->getPermissionModule();
77
    is($permissionModule1->permission_module_id, 1, "BorrowerPermissions, setter/getter:> getPermissionModule() 1");
78
    my $permissionModuleCirculate = $borrowerPermissionByName->getPermissionModule();
79
    is($permissionModuleCirculate->module, "circulate", "BorrowerPermissions, setter/getter:> getPermissionModule() circulate");
80
81
    #Not testing setters because changing the module might not make any sense.
82
    #Then we would need to make sure we dont end up with bad permissionModule->permission combinations.
83
84
    ##Testing getter for Permission
85
    my $permission1 = $borrowerPermissionById->getPermission();
86
    is($permission1->permission_id, 1, "BorrowerPermissions, setter/getter:> getPermission() 1");
87
    my $permissionManage_restrictions = $borrowerPermissionByName->getPermission();
88
    is($permissionManage_restrictions->code, "manage_restrictions", "BorrowerPermissions, setter/getter:> getPermission() manage_restrictions");
89
};
90
if ($@) { #Catch all leaking errors and gracefully terminate.
91
    warn $@;
92
    tearDown();
93
    exit 1;
94
}
95
96
##All tests done, tear down test context
97
$borrowerFactory->tearDownTestContext($testContext);
98
done_testing;
99
100
sub tearDown {
101
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
102
}
(-)a/t/db_dependent/Koha/Auth/PermissionManager.t (+221 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More;
22
use Try::Tiny;
23
use Scalar::Util qw(blessed);
24
25
use Koha::Auth::PermissionManager;
26
27
use t::lib::TestObjects::ObjectFactory;
28
use t::lib::TestObjects::PatronFactory;
29
30
31
##Setting up the test context
32
my $testContext = {};
33
34
my $borrowerFactory = t::lib::TestObjects::PatronFactory->new();
35
my $borrowers = $borrowerFactory->createTestGroup([
36
            {firstname  => 'Olli-Antti',
37
             surname    => 'Kivi',
38
             cardnumber => '1A01',
39
             branchcode => 'CPL',
40
            },
41
            {firstname  => 'Alli-Ontti',
42
             surname    => 'Ivik',
43
             cardnumber => '1A02',
44
             branchcode => 'CPL',
45
            },
46
        ], undef, $testContext);
47
48
##Test context set, starting testing:
49
eval { #run in a eval-block so we don't die without tearing down the test context
50
    my $permissionManager = Koha::Auth::PermissionManager->new();
51
    my ($permissionModule, $permission, $failureCaughtFlag, $permissionsList);
52
53
    ##Test getBorrowerPermissions
54
    $permissionManager->grantPermission($borrowers->{'1A01'}, 'circulate', 'force_checkout');
55
    $permissionManager->grantPermission($borrowers->{'1A01'}, 'circulate', 'manage_restrictions');
56
    $permissionsList = $permissionManager->getBorrowerPermissions($borrowers->{'1A01'});
57
    is($permissionsList->[0]->getPermission->code, 'force_checkout', "PermissionManager, getBorrowerPermissions:> Check 1.");
58
    is($permissionsList->[1]->getPermission->code, 'manage_restrictions', "PermissionManager, getBorrowerPermissions:> Check 2.");
59
    $permissionManager->revokePermission($borrowers->{'1A01'}, 'circulate', 'force_checkout');
60
    $permissionManager->revokePermission($borrowers->{'1A01'}, 'circulate', 'manage_restrictions');
61
62
    ##Test grantPermissions && revokeAllPermissions
63
    $permissionManager->grantPermissions($borrowers->{'1A01'},
64
                                         {  borrowers => 'view_borrowers',
65
                                            reserveforothers => ['place_holds'],
66
                                            tools => ['edit_news', 'edit_notices'],
67
                                            acquisition => {
68
                                              budget_add_del => 1,
69
                                              budget_modify => 1,
70
                                            },
71
                                        });
72
    $permissionManager->hasPermission($borrowers->{'1A01'}, 'borrowers', 'view_borrowers');
73
    $permissionManager->hasPermission($borrowers->{'1A01'}, 'tools', 'edit_notices');
74
    $permissionManager->hasPermission($borrowers->{'1A01'}, 'acquisition', 'budget_modify');
75
    $permissionsList = $permissionManager->getBorrowerPermissions($borrowers->{'1A01'});
76
    is(scalar(@$permissionsList), 6, "PermissionManager, grantPermissions:> Permissions as HASH, ARRAY and Scalar.");
77
78
    $permissionManager->revokeAllPermissions($borrowers->{'1A01'});
79
    $permissionsList = $permissionManager->getBorrowerPermissions($borrowers->{'1A01'});
80
    is(scalar(@$permissionsList), 0, "PermissionManager, revokeAllPermissions:> No permissions left.");
81
82
    ##Test listKohaPermissionsAsHASH
83
    my $listedPermissions = $permissionManager->listKohaPermissionsAsHASH();
84
    ok(ref($listedPermissions->{circulate}->{permissions}->{force_checkout}) eq 'HASH', "PermissionManager, listKohaPermissionsAsHASH:> Check 1.");
85
    ok(ref($listedPermissions->{editcatalogue}->{permissions}->{edit_catalogue}) eq 'HASH', "PermissionManager, listKohaPermissionsAsHASH:> Check 2.");
86
    ok(defined($listedPermissions->{reports}->{permissions}->{create_reports}->{description}), "PermissionManager, listKohaPermissionsAsHASH:> Check 3.");
87
    ok(defined($listedPermissions->{permissions}->{description}), "PermissionManager, listKohaPermissionsAsHASH:> Check 4.");
88
89
90
91
    ###   TESTING WITH unique keys, instead of the recommended Koha::Objects. ###
92
    #Arguably this makes for more clear tests cases :)
93
    ##Add/get PermissionModule
94
    $permissionModule = $permissionManager->addPermissionModule({module => 'test', description => 'Just testing this module.'});
95
    is($permissionModule->module, "test", "PermissionManager from names, add/getPermissionModule:> Module added.");
96
    $permissionModule = $permissionManager->getPermissionModule('test');
97
    is($permissionModule->module, "test", "PermissionManager from names, add/getPermissionModule:> Module got.");
98
99
    ##Add/get Permission
100
    $permission = $permissionManager->addPermission({module => 'test', code => 'testperm', description => 'Just testing this permission.'});
101
    is($permission->code, "testperm", "PermissionManager from names, add/getPermission:> Permission added.");
102
    $permission = $permissionManager->getPermission('testperm');
103
    is($permission->code, "testperm", "PermissionManager from names, add/getPermission:> Permission got.");
104
105
    ##Grant permission
106
    $permissionManager->grantPermission($borrowers->{'1A01'}, 'test', 'testperm');
107
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, 'test', 'testperm'), "PermissionManager from names, grant/hasPermission:> Borrower granted permission.");
108
109
    ##hasPermission with wildcard
110
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, 'test', '*'), "PermissionManager from names, hasPermission:> Wildcard permission.");
111
112
    ##hasPermissions with wildcard
113
    ok($permissionManager->hasPermissions($borrowers->{'1A01'}, {test => ['*']}), "PermissionManager from names, hasPermission:> Wildcard permissions from array.");
114
115
    ##Revoke permission
116
    $permissionManager->revokePermission($borrowers->{'1A01'}, 'test', 'testperm');
117
    $failureCaughtFlag = 0;
118
    try {
119
        $permissionManager->hasPermission($borrowers->{'1A01'}, 'test', 'testperm');
120
    } catch {
121
        if (blessed($_) && $_->isa('Koha::Exception::NoPermission')) {
122
            $failureCaughtFlag = 1;
123
        }
124
        else {
125
            die $_; #Somekind of another problem arised and rethrow it.
126
        }
127
    };
128
    ok($failureCaughtFlag, "PermissionManager from names, revoke/hasPermission:> Borrower revoked permission.");
129
130
    ##Delete permissions and modules we just made. When we delete the module first, the permissions is ON CASCADE DELETEd
131
    $permissionManager->delPermissionModule('test');
132
    $permissionModule = $permissionManager->getPermissionModule('test');
133
    ok(not(defined($permissionModule)), "PermissionManager from names, delPermissionModule:> Module deleted.");
134
135
    $failureCaughtFlag = 0;
136
    try {
137
        #This subpermission is now deleted due to cascading delete of the parent permissionModule
138
        #We catch the exception gracefully and report test success
139
        $permissionManager->delPermission('testperm');
140
    } catch {
141
        if (blessed($_) && $_->isa('Koha::Exception::UnknownObject')) {
142
            $failureCaughtFlag = 1;
143
        }
144
        else {
145
            die $_; #Somekind of another problem arised and rethrow it.
146
        }
147
    };
148
    ok($failureCaughtFlag, "PermissionManager from names, delPermission:> Permission already deleted, exception caught.");
149
    $permission = $permissionManager->getPermission('testperm');
150
    ok(not(defined($permission)), "PermissionManager from names, delPermission:> Permission deleted.");
151
152
153
154
    ###  TESTING WITH Koha::Object parameters instead.  ###
155
    ##Add/get PermissionModule
156
    $permissionModule = $permissionManager->addPermissionModule({module => 'test', description => 'Just testing this module.'});
157
    is($permissionModule->module, "test", "PermissionManager from objects, add/getPermissionModule:> Module added.");
158
    $permissionModule = $permissionManager->getPermissionModule($permissionModule);
159
    is($permissionModule->module, "test", "PermissionManager from objects, add/getPermissionModule:> Module got.");
160
161
    ##Add/get Permission
162
    $permission = $permissionManager->addPermission({module => 'test', code => 'testperm', description => 'Just testing this permission.'});
163
    is($permission->code, "testperm", "PermissionManager from objects, add/getPermission:> Permission added.");
164
    $permission = $permissionManager->getPermission($permission);
165
    is($permission->code, "testperm", "PermissionManager from objects, add/getPermission:> Permission got.");
166
167
    ##Grant permission
168
    $permissionManager->grantPermission($borrowers->{'1A01'}, $permissionModule, $permission);
169
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, $permissionModule, $permission), "PermissionManager from objects, grant/hasPermission:> Borrower granted permission.");
170
171
    ##hasPermission with wildcard
172
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, $permissionModule, '*'), "PermissionManager from objects, hasPermission:> Wildcard permission.");
173
174
    ##hasPermissions with wildcard, we quite cannot use a blessed Object as a HASH key
175
    #ok($permissionManager->hasPermissions($borrowers->{'1A01'}, {$permissionModule->module() => ['*']}), "PermissionManager from objects, hasPermission:> Wildcard permissions from array.");
176
177
    ##Revoke permission
178
    $permissionManager->revokePermission($borrowers->{'1A01'}, $permissionModule, $permission);
179
    $failureCaughtFlag = 0;
180
    try {
181
        $permissionManager->hasPermission($borrowers->{'1A01'}, $permissionModule, $permission);
182
    } catch {
183
        if (blessed($_) && $_->isa('Koha::Exception::NoPermission')) {
184
            $failureCaughtFlag = 1;
185
        }
186
        else {
187
            die $_; #Somekind of another problem arised and rethrow it.
188
        }
189
    };
190
    ok($failureCaughtFlag, "PermissionManager from objects, revoke/hasPermission:> Borrower revoked permission.");
191
192
    ##Delete permissions and modules we just made
193
    $permissionManager->delPermission($permission);
194
    $permission = $permissionManager->getPermission('testperm');
195
    ok(not(defined($permission)), "PermissionManager from objects, delPermission:> Permission deleted.");
196
197
    $permissionManager->delPermissionModule($permissionModule);
198
    $permissionModule = $permissionManager->getPermissionModule('test');
199
    ok(not(defined($permissionModule)), "PermissionManager from objects, delPermissionModule:> Module deleted.");
200
201
202
203
    ##Testing superlibrarian permission
204
    $permissionManager->revokeAllPermissions($borrowers->{'1A01'});
205
    $permissionManager->grantPermission($borrowers->{'1A01'}, 'superlibrarian', 'superlibrarian');
206
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, 'staffaccess', 'staff_access_permissions'), "PermissionManager, superuser permission:> Superuser has all permissions 1.");
207
    ok($permissionManager->hasPermission($borrowers->{'1A01'}, 'tools', 'batch_upload_patron_images'), "PermissionManager, superuser permission:> Superuser has all permissions 2.");
208
};
209
if ($@) { #Catch all leaking errors and gracefully terminate.
210
    warn $@;
211
    tearDown();
212
    exit 1;
213
}
214
215
##All tests done, tear down test context
216
tearDown();
217
done_testing;
218
219
sub tearDown {
220
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
221
}
(-)a/t/db_dependent/Members/member-flags.t (+100 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# Copyright 2015 Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More;
23
use Try::Tiny; #Even Selenium::Remote::Driver uses Try::Tiny :)
24
use Scalar::Util qw(blessed);
25
26
use t::lib::Page::Members::MemberFlags;
27
use t::lib::TestObjects::PatronFactory;
28
use Koha::Auth::PermissionManager;
29
30
31
##Setting up the test context
32
my $testContext = {};
33
34
my $password = '1234';
35
my $borrowerFactory = t::lib::TestObjects::PatronFactory->new();
36
my $borrowers = $borrowerFactory->createTestGroup([
37
            {firstname  => 'Olli-Antti',
38
             surname    => 'Kivi',
39
             cardnumber => '1A01',
40
             branchcode => 'CPL',
41
             userid     => 'mini_admin',
42
             password   => $password,
43
            },
44
        ], undef, $testContext);
45
46
##Test context set, starting testing:
47
eval { #run in a eval-block so we don't die without tearing down the test context
48
49
    testGrantRevokePermissions();
50
51
};
52
if ($@) { #Catch all leaking errors and gracefully terminate.
53
    warn $@;
54
    tearDown();
55
    exit 1;
56
}
57
58
##All tests done, tear down test context
59
tearDown();
60
done_testing;
61
62
sub tearDown {
63
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
64
}
65
66
sub testGrantRevokePermissions {
67
    my $permissionManager = Koha::Auth::PermissionManager->new();
68
    $permissionManager->grantPermissions($borrowers->{'1A01'}, {permissions => 'set_permissions',
69
                                                                catalogue => 'staff_login',
70
                                                                staffaccess => 'staff_access_permissions',
71
                                                                circulate => 'override_renewals',
72
                                                                borrowers => 'view_borrowers',
73
                                                              });
74
75
    my $memberflags = t::lib::Page::Members::MemberFlags->new({borrowernumber => $borrowers->{'1A01'}->borrowernumber});
76
77
    $memberflags->isPasswordLoginAvailable()->doPasswordLogin($borrowers->{'1A01'}->userid, $password)
78
                ->togglePermission('editcatalogue', 'delete_all_items') #Add this
79
                ->togglePermission('editcatalogue', 'edit_items') #Add this
80
                ->togglePermission('circulate', 'override_renewals') #Remove this permission
81
                ->submitPermissionTree();
82
83
    ok($permissionManager->hasPermissions($borrowers->{'1A01'},{editcatalogue => ['delete_all_items', 'edit_items']}),
84
    "member-flags.pl:> Granting new permissions succeeded.");
85
86
    my $failureCaughtFlag = 0;
87
    try {
88
        $permissionManager->hasPermission($borrowers->{'1A01'}, 'circulate', 'override_renewals');
89
    } catch {
90
        if (blessed($_) && $_->isa('Koha::Exception::NoPermission')) {
91
            $failureCaughtFlag = 1;
92
        }
93
        else {
94
            die $_; #Somekind of another problem arised and rethrow it.
95
        }
96
    };
97
    ok($failureCaughtFlag, "member-flags.pl:> Revoking permissions succeeded.");
98
99
    $permissionManager->revokeAllPermissions($borrowers->{'1A01'});
100
}
(-)a/t/db_dependent/Opac/opac-search.t (-1 / +79 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# Copyright 2015 Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use Test::More;
23
24
use t::lib::Page::Opac::OpacSearch;
25
use t::lib::TestObjects::PatronFactory;
26
27
28
##Setting up the test context
29
my $testContext = {};
30
31
my $password = '1234';
32
my $borrowerFactory = t::lib::TestObjects::PatronFactory->new();
33
my $borrowers = $borrowerFactory->createTestGroup([
34
            {firstname  => 'Olli-Antti',
35
             surname    => 'Kivi',
36
             cardnumber => '1A01',
37
             branchcode => 'CPL',
38
             userid     => 'mini_admin',
39
             password   => $password,
40
            },
41
        ], undef, $testContext);
42
43
##Test context set, starting testing:
44
eval { #run in a eval-block so we don't die without tearing down the test context
45
46
    my $opacsearch = t::lib::Page::Opac::OpacSearch->new();
47
    testAnonymousSearchHistory($opacsearch);
48
49
};
50
if ($@) { #Catch all leaking errors and gracefully terminate.
51
    warn $@;
52
    tearDown();
53
    exit 1;
54
}
55
56
##All tests done, tear down test context
57
tearDown();
58
done_testing;
59
60
sub tearDown {
61
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
62
}
63
64
sub testAnonymousSearchHistory {
65
    my $opacsearch = shift;
66
67
    $opacsearch->doSetSearchFieldTerm(1, 'Author', 'nengard')->doSearchSubmit()->navigateAdvancedSearch()
68
               ->doSetSearchFieldTerm(1, 'Author', 'joubu')->doSearchSubmit()->navigateAdvancedSearch()
69
               ->doSetSearchFieldTerm(1, 'Author', 'khall')->doSearchSubmit()->navigateHome()
70
               ->doPasswordLogin($borrowers->{'1A01'}->userid, $password)->navigateAdvancedSearch()
71
               ->doSetSearchFieldTerm(1, 'Author', 'magnuse')->doSearchSubmit()->navigateAdvancedSearch()
72
               ->doSetSearchFieldTerm(1, 'Author', 'cait')->doSearchSubmit()->navigateSearchHistory()
73
               ->testDoSearchHistoriesExist(['nengard',
74
                                             'joubu',
75
                                             'khall',
76
                                             'magnuse',
77
                                             'cait'])
78
               ->quit();
79
}

Return to bug 14540