Jonathan Druart
ca5b112376
To test and understand what's going on, you can try that bit of code: my @a = qw( a b c a); my @b = qw( b c d ); my @c; @c = grep { 'a' eq $_ } @a ? 'ok' : (); say @c; @c = ( grep { 'a' eq $_ } @a ) ? 'ok' : (); say @c; @c = grep { 'a' eq $_ } @a ? ('ok') : (undef); say @c; The problem here: Have patrons in 3 branches CPL, MPL, SPL Have a non superlibrarian with edit_borrowers permission but without view_borrower_infos_from_any_libraries, from CPL Create a library group with CPL, MPL Use that non superlibrarian to search for patrons You can search for patrons fro CPL and MPL BUT, edit the value for CPL, use SPL (edit the DOM) Search and... oops Apply this patch, try again Also use a superlibrarian patron (and/or with view_borrower_infos_from_any_libraries) and confirm that they can see all patrons Signed-off-by: Bernardo Gonzalez Kriegel <bgkriegel@gmail.com> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
303 lines
11 KiB
Perl
303 lines
11 KiB
Perl
package C4::Utils::DataTables::Members;
|
|
|
|
use Modern::Perl;
|
|
use C4::Context;
|
|
use C4::Utils::DataTables;
|
|
use Koha::DateUtils;
|
|
|
|
sub search {
|
|
my ( $params ) = @_;
|
|
my $searchmember = $params->{searchmember};
|
|
my $firstletter = $params->{firstletter};
|
|
my $categorycode = $params->{categorycode};
|
|
my $branchcode = $params->{branchcode};
|
|
my $searchtype = $params->{searchtype} || 'contain';
|
|
my $searchfieldstype = $params->{searchfieldstype} || 'standard';
|
|
my $has_permission = $params->{has_permission};
|
|
my $dt_params = $params->{dt_params};
|
|
|
|
unless ( $searchmember ) {
|
|
$searchmember = $dt_params->{sSearch} // '';
|
|
}
|
|
|
|
# If branches are independent and user is not superlibrarian
|
|
# The search has to be only on the user branch
|
|
my $userenv = C4::Context->userenv;
|
|
my $logged_in_user = Koha::Patrons->find( $userenv->{number} );
|
|
my @restricted_branchcodes = $logged_in_user->libraries_where_can_see_patrons;
|
|
|
|
my ($sth, $query, $iTotalQuery, $iTotalRecords, $iTotalDisplayRecords);
|
|
my $dbh = C4::Context->dbh;
|
|
|
|
# Get the module_bit from a given permission code
|
|
if ( $has_permission ) {
|
|
($has_permission->{module_bit}) = $dbh->selectrow_array(q|
|
|
SELECT bit FROM userflags WHERE flag=?
|
|
|, undef, $has_permission->{permission});
|
|
}
|
|
|
|
# Get the iTotalRecords DataTable variable
|
|
$iTotalQuery = "SELECT COUNT(borrowers.borrowernumber) FROM borrowers";
|
|
if ( $has_permission ) {
|
|
$iTotalQuery .= ' LEFT JOIN user_permissions on borrowers.borrowernumber=user_permissions.borrowernumber';
|
|
}
|
|
|
|
my (@where, @conditions);
|
|
if ( @restricted_branchcodes ) {
|
|
push @where, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
|
|
push @conditions, @restricted_branchcodes;
|
|
}
|
|
if ( $has_permission ) {
|
|
push @where, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
|
|
push @conditions, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
|
|
}
|
|
$iTotalQuery .= ' WHERE ' . join ' AND ', @where if @where;
|
|
($iTotalRecords) = $dbh->selectrow_array( $iTotalQuery, undef, @conditions );
|
|
|
|
# Do that after iTotalQuery!
|
|
if ( defined $branchcode and $branchcode ) {
|
|
@restricted_branchcodes = @restricted_branchcodes
|
|
? grep ({ $_ eq $branchcode } @restricted_branchcodes)
|
|
? ($branchcode)
|
|
: (undef) # Do not return any results
|
|
: ($branchcode);
|
|
}
|
|
|
|
if ( $searchfieldstype eq 'dateofbirth' ) {
|
|
# Return an empty list if the date of birth is not correctly formatted
|
|
$searchmember = eval { output_pref( { str => $searchmember, dateformat => 'iso', dateonly => 1 } ); };
|
|
if ( $@ or not $searchmember ) {
|
|
return {
|
|
iTotalRecords => $iTotalRecords,
|
|
iTotalDisplayRecords => 0,
|
|
patrons => [],
|
|
};
|
|
}
|
|
}
|
|
|
|
my $select = "SELECT
|
|
borrowers.borrowernumber, borrowers.surname, borrowers.firstname,
|
|
borrowers.othernames,
|
|
borrowers.flags,
|
|
borrowers.streetnumber, borrowers.streettype, borrowers.address,
|
|
borrowers.address2, borrowers.city, borrowers.state, borrowers.zipcode,
|
|
borrowers.country, cardnumber, borrowers.dateexpiry,
|
|
borrowers.borrowernotes, borrowers.branchcode, borrowers.email,
|
|
borrowers.userid, borrowers.dateofbirth, borrowers.categorycode,
|
|
categories.description AS category_description, categories.category_type,
|
|
branches.branchname, borrowers.phone";
|
|
my $from = "FROM borrowers
|
|
LEFT JOIN branches ON borrowers.branchcode = branches.branchcode
|
|
LEFT JOIN categories ON borrowers.categorycode = categories.categorycode";
|
|
if ( $has_permission ) {
|
|
$from .= '
|
|
LEFT JOIN user_permissions on borrowers.borrowernumber=user_permissions.borrowernumber';
|
|
}
|
|
my @where_args;
|
|
my @where_strs;
|
|
if(defined $firstletter and $firstletter ne '') {
|
|
push @where_strs, "borrowers.surname LIKE ?";
|
|
push @where_args, "$firstletter%";
|
|
}
|
|
if(defined $categorycode and $categorycode ne '') {
|
|
push @where_strs, "borrowers.categorycode = ?";
|
|
push @where_args, $categorycode;
|
|
}
|
|
if(@restricted_branchcodes ) {
|
|
push @where_strs, "borrowers.branchcode IN (" . join( ',', ('?') x @restricted_branchcodes ) . ")";
|
|
push @where_args, @restricted_branchcodes;
|
|
}
|
|
|
|
my $searchfields = {
|
|
standard => C4::Context->preference('DefaultPatronSearchFields') || 'surname,firstname,othernames,cardnumber,userid',
|
|
email => 'email,emailpro,B_email',
|
|
borrowernumber => 'borrowernumber',
|
|
phone => 'phone,phonepro,B_phone,altcontactphone,mobile',
|
|
address => 'streetnumber,streettype,address,address2,city,state,zipcode,country',
|
|
};
|
|
|
|
# * is replaced with % for sql
|
|
$searchmember =~ s/\*/%/g;
|
|
|
|
# split into search terms
|
|
my @terms;
|
|
# consider coma as space
|
|
$searchmember =~ s/,/ /g;
|
|
if ( $searchtype eq 'contain' ) {
|
|
@terms = split / /, $searchmember;
|
|
} else {
|
|
@terms = ($searchmember);
|
|
}
|
|
|
|
foreach my $term (@terms) {
|
|
next unless $term;
|
|
|
|
my $term_dt = eval { local $SIG{__WARN__} = {}; output_pref( { str => $term, dateonly => 1, dateformat => 'sql' } ); };
|
|
|
|
if ($term_dt) {
|
|
$term = $term_dt;
|
|
} else {
|
|
$term .= '%' # end with anything
|
|
if $term !~ /%$/;
|
|
$term = "%$term" # begin with anythin unless start_with
|
|
if $searchtype eq 'contain' && $term !~ /^%/;
|
|
}
|
|
|
|
my @where_strs_or;
|
|
if ( defined $searchfields->{$searchfieldstype} ) {
|
|
for my $searchfield ( split /,/, $searchfields->{$searchfieldstype} ) {
|
|
push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfield) . " LIKE ?";
|
|
push @where_args, $term;
|
|
}
|
|
} else {
|
|
push @where_strs_or, "borrowers." . $dbh->quote_identifier($searchfieldstype) . " LIKE ?";
|
|
push @where_args, $term;
|
|
}
|
|
|
|
|
|
if ( $searchfieldstype eq 'standard' and C4::Context->preference('ExtendedPatronAttributes') and $searchmember ) {
|
|
my @matching_borrowernumbers = Koha::Patrons->filter_by_attribute_value($searchmember)->get_column('borrowernumber');
|
|
|
|
for my $borrowernumber ( @matching_borrowernumbers ) {
|
|
push @where_strs_or, "borrowers.borrowernumber = ?";
|
|
push @where_args, $borrowernumber;
|
|
}
|
|
}
|
|
|
|
push @where_strs, '('. join (' OR ', @where_strs_or) . ')'
|
|
if @where_strs_or;
|
|
}
|
|
|
|
if ( $has_permission ) {
|
|
push @where_strs, '( borrowers.flags = 1 OR borrowers.flags & (1 << ?) OR module_bit=? AND code=? )';
|
|
push @where_args, ($has_permission->{module_bit}) x 2, $has_permission->{subpermission};
|
|
}
|
|
|
|
my $where = @where_strs ? " WHERE " . join (" AND ", @where_strs) : undef;
|
|
my $orderby = dt_build_orderby($dt_params);
|
|
|
|
my $limit;
|
|
# If iDisplayLength == -1, we want to display all patrons
|
|
if ( !$dt_params->{iDisplayLength} || $dt_params->{iDisplayLength} > -1 ) {
|
|
# In order to avoid sql injection
|
|
$dt_params->{iDisplayStart} =~ s/\D//g if defined($dt_params->{iDisplayStart});
|
|
$dt_params->{iDisplayLength} =~ s/\D//g if defined($dt_params->{iDisplayLength});
|
|
$dt_params->{iDisplayStart} //= 0;
|
|
$dt_params->{iDisplayLength} //= 20;
|
|
$limit = "LIMIT $dt_params->{iDisplayStart},$dt_params->{iDisplayLength}";
|
|
}
|
|
|
|
$query = join(
|
|
" ",
|
|
($select ? $select : ""),
|
|
($from ? $from : ""),
|
|
($where ? $where : ""),
|
|
($orderby ? $orderby : ""),
|
|
($limit ? $limit : "")
|
|
);
|
|
$sth = $dbh->prepare($query);
|
|
$sth->execute(@where_args);
|
|
my $patrons = $sth->fetchall_arrayref({});
|
|
|
|
# Get the iTotalDisplayRecords DataTable variable
|
|
$query = "SELECT COUNT(borrowers.borrowernumber) " . $from . ($where ? $where : "");
|
|
$sth = $dbh->prepare($query);
|
|
$sth->execute(@where_args);
|
|
($iTotalDisplayRecords) = $sth->fetchrow_array;
|
|
|
|
# Get some information on patrons
|
|
foreach my $patron (@$patrons) {
|
|
my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
|
|
$patron->{overdues} = $patron_object->get_overdues->count;
|
|
$patron->{issues} = $patron_object->checkouts->count;
|
|
my $balance = $patron_object->account->balance;
|
|
# FIXME Should be formatted from the template
|
|
$patron->{fines} = sprintf("%.2f", $balance);
|
|
|
|
if( $patron->{dateexpiry} ) {
|
|
# FIXME We should not format the date here, do it in template-side instead
|
|
$patron->{dateexpiry} = output_pref( { dt => scalar dt_from_string( $patron->{dateexpiry}, 'iso'), dateonly => 1} );
|
|
} else {
|
|
$patron->{dateexpiry} = '';
|
|
}
|
|
}
|
|
|
|
return {
|
|
iTotalRecords => $iTotalRecords,
|
|
iTotalDisplayRecords => $iTotalDisplayRecords,
|
|
patrons => $patrons
|
|
}
|
|
}
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
C4::Utils::DataTables::Members - module for using DataTables with patrons
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
This module provides (one for the moment) routines used by the patrons search
|
|
|
|
=head2 FUNCTIONS
|
|
|
|
=head3 search
|
|
|
|
my $dt_infos = C4::Utils::DataTables::Members->search($params);
|
|
|
|
$params is a hashref with some keys:
|
|
|
|
=over 4
|
|
|
|
=item searchmember
|
|
|
|
String to search in the borrowers sql table
|
|
|
|
=item firstletter
|
|
|
|
Introduced to contain 1 letter but can contain more.
|
|
The search will done on the borrowers.surname field
|
|
|
|
=item categorycode
|
|
|
|
Search patrons with this categorycode
|
|
|
|
=item branchcode
|
|
|
|
Search patrons with this branchcode
|
|
|
|
=item searchtype
|
|
|
|
Can be 'start_with' or 'contain' (default value). Used for the searchmember parameter.
|
|
|
|
=item searchfieldstype
|
|
|
|
Can be 'standard' (default value), 'email', 'borrowernumber', 'phone', 'address' or 'dateofbirth', 'sort1', 'sort2'
|
|
|
|
=item dt_params
|
|
|
|
Is the reference of C4::Utils::DataTables::dt_get_params($input);
|
|
|
|
=cut
|
|
|
|
=back
|
|
|
|
=head1 LICENSE
|
|
|
|
This file is part of Koha.
|
|
|
|
Copyright 2013 BibLibre
|
|
|
|
Koha is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Koha is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Koha; if not, see <http://www.gnu.org/licenses>.
|