From 45cfb29345d1669f4e5d2a98a718e5ae595a7510 Mon Sep 17 00:00:00 2001 From: William Lavoie Date: Thu, 3 Apr 2025 10:39:38 -0400 Subject: [PATCH] Bug 38040: Preventing editing other libraries' holds with IndependentBranches enabled I added the verification to modrequest.pl as well. --- installer/data/mysql/mandatory/sysprefs.sql | 2 + .../prog/en/includes/holds_table.inc | 10 ++- .../en/modules/admin/preferences/admin.pref | 7 ++ .../prog/en/modules/reserve/request.tt | 27 ++++++- reserve/modrequest.pl | 64 +++++++++-------- reserve/request.pl | 72 +++++++++++++------ 6 files changed, 127 insertions(+), 55 deletions(-) diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 2bf9d0b648..56532cdaca 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -336,8 +336,10 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('IncludeSeeAlsoFromInSearches','0','','Include see-also-from references in searches.','YesNo'), ('IncludeSeeFromInSearches','0','','Include see-from references in searches.','YesNo'), ('IndependentBranches','0',NULL,'If ON, increases security between libraries','YesNo'), +('IndependentBranchesHolds','0', NULL, 'Allow non-superlibrarians to modify holds between libraries','YesNo'), ('IndependentBranchesPatronModifications','0', NULL, 'Show only modification request for the logged in branch','YesNo'), ('IndependentBranchesTransfers','0', NULL, 'Allow non-superlibrarians to transfer items between libraries','YesNo'), +('intranet_includes','includes',NULL,'The includes directory you want for specific look of Koha (includes or includes_npl for example)','Free'), ('IntranetAddMastheadLibraryPulldown','0', NULL, 'Add a library select pulldown menu on the staff header search','YesNo'), ('IntranetBiblioDefaultView','normal','normal|marc|isbd|labeled_marc','Choose the default detail view in the staff interface; choose between normal, labeled_marc, marc or isbd','Choice'), ('intranetbookbag','1','','If ON, enables display of Cart feature in the intranet','YesNo'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc index 2d65e83dc1..719d7179c3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/holds_table.inc @@ -33,7 +33,13 @@ [% SET all_priorities = [] %] [% FOREACH hold IN holds %] - [% all_priorities.push( hold.priority ) %] + [% IF CAN_user_superlibrarian || !Koha.Preference('IndependentBranchesHolds') %] + [% all_priorities.push( hold.priority ) %] + [% ELSE %] + [% IF Branches.GetLoggedInBranchcode == hold.branchcode %] + [% all_priorities.push( hold.priority ) %] + [% END %] + [% END %] [% END %] @@ -42,7 +48,7 @@ [%- first_priority = hold.priority -%] [%- found_holds = loop.index() -%] [%- END -%] - [%- IF Koha.Preference('HoldsSplitQueueNumbering') == 'actual' -%] + [%- IF Koha.Preference('HoldsSplitQueueNumbering') == 'actual' || (Koha.Preference('IndependentBranchesHolds') && !CAN_user_superlibrarian) -%] [%- this_priority = hold.priority -%] [%- ELSE -%] [%- this_priority = loop.count() - found_holds -%] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref index 18d21a955a..db1e65f2dd 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/admin.pref @@ -148,6 +148,13 @@ Administration: choices: 1: "Yes" 0: "No" + - + - "Prevent staff (but not superlibrarians) from modifying holds from other libraries: " + - pref: IndependentBranchesHolds + default: 0 + choices: + 1: "Yes" + 0: "No" - - pref: ForceLibrarySelection choices: diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt index 558b5e0d9f..7b79d48252 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -105,6 +105,12 @@ :disabled { opacity: 0.5; } + + .disabled_trash{ + pointer-events: none; + cursor: not-allowed ; + color: #777; + } [% END %] @@ -1247,7 +1253,7 @@ [% END %] - [% IF Koha.Preference('HoldsSplitQueue') == 'branch' %] + [% IF Koha.Preference('HoldsSplitQueue') == 'branch' || ((!CAN_user_superlibrarian) && Koha.Preference('IndependentBranchesHolds'))%] [% SET branchcodes = [] %] @@ -1801,6 +1807,25 @@ return false; }); + [% IF ((!CAN_user_superlibrarian) || Koha.Preference('IndependentBranchesHolds')) %] + var user_branch = "[% Branches.GetLoggedInBranchcode %]"; + if(user_branch !== undefined && user_branch !== ""){ + $('#patron_holds_table tbody tr').each(function() { + var link = $(this).find('a[href*="member"]'); + var rankRequest = $(this).find("select[name='rank-request']"); + if (!link.length){ + $(this).find('.cancel-hold, .fa-trash').addClass('disabled_trash'); + $(this).find('.select_hold, .rank-request, td a[data-op="cud-move"], .flatpickr, .toggle-suspend, .clear_date, [name*="change_hold_type_"]').addClass('disabled').attr('disabled', 'disabled'); + $(this).find('.select_hold_all, .hold-arrow').addClass('disabled').attr('disabled', 'disabled'); + $(this).find('.suspend-hold').prop('disabled', true); + $(this).find('.icon-move-hold-top').css('border-top', '2px solid #999999'); + $(this).find('.icon-move-hold-bottom').css('border-bottom', '2px solid #999999'); + $(this).find('.pickup_location_dropdown').prop('disabled', true); + } + }); + } + [% END %] + [% UNLESS ( patron || patron.borrowernumber || borrowers || noitems || nobiblio ) %] [% IF ( PatronAutoComplete ) %] patron_autocomplete($(".search_patron_filter"), { 'link-to': 'reserve', 'url-params': '[% url_biblio_params | url %]' }); diff --git a/reserve/modrequest.pl b/reserve/modrequest.pl index 63f7a23e1b..2959ef2ecc 100755 --- a/reserve/modrequest.pl +++ b/reserve/modrequest.pl @@ -49,46 +49,52 @@ my $count = @rank; @biblionumber = uniq @biblionumber; +my $is_super_librarian = C4::Context->IsSuperLibrarian(); +my $user_branch = C4::Context->preference("IndependentBranches") ? C4::Context->userenv->{'branch'}: undef; +my $can_modify_all_holds = $is_super_librarian || !defined($user_branch); + # Cancel or modify the queue list of reserves (without item linked) if ( $op eq 'cud-cancelall' || $op eq 'cud-modifyall' ) { for ( my $i = 0 ; $i < $count ; $i++ ) { - undef $itemnumber[$i] if !$itemnumber[$i]; - my $suspend_until = $query->param( "suspend_until_" . $reserve_id[$i] ); - my $cancellation_reason = $query->param("cancellation-reason"); - my $params = { - rank => $rank[$i], - reserve_id => $reserve_id[$i], - expirationdate => $expirationdates[$i] || undef, - branchcode => $branch[$i], - itemnumber => $itemnumber[$i], - defined $suspend_until ? ( suspend_until => $suspend_until ) : (), - cancellation_reason => $cancellation_reason, - }; - if ( C4::Context->preference('AllowHoldDateInFuture') ) { - $params->{reservedate} = $reservedates[$i] || undef; - } - - try { - ModReserve($params); - } catch { - if ( $_->isa('Koha::Exceptions::ObjectNotFound') ) { - warn $_; - } else { - $_->rethrow; + if ( $can_modify_all_holds || $branch[$i] eq $user_branch ) { + undef $itemnumber[$i] if !$itemnumber[$i]; + my $suspend_until = $query->param( "suspend_until_" . $reserve_id[$i] ); + my $cancellation_reason = $query->param("cancellation-reason"); + my $params = { + rank => $rank[$i], + reserve_id => $reserve_id[$i], + expirationdate => $expirationdates[$i] || undef, + branchcode => $branch[$i], + itemnumber => $itemnumber[$i], + defined $suspend_until ? ( suspend_until => $suspend_until ) : (), + cancellation_reason => $cancellation_reason, + }; + if ( C4::Context->preference('AllowHoldDateInFuture') ) { + $params->{reservedate} = $reservedates[$i] || undef; } - }; - - if ( $query->param( "change_hold_type_" . $reserve_id[$i] ) ) { - my $hold = Koha::Holds->find( $reserve_id[$i] ); try { - $hold->change_type; + ModReserve($params); } catch { - if ( $_->isa('Koha::Exceptions::Hold::CannotChangeHoldType') ) { + if ( $_->isa('Koha::Exceptions::ObjectNotFound') ) { warn $_; } else { $_->rethrow; } + }; + + if ( $query->param( "change_hold_type_" . $reserve_id[$i] ) ) { + my $hold = Koha::Holds->find( $reserve_id[$i] ); + + try { + $hold->change_type; + } catch { + if ( $_->isa('Koha::Exceptions::Hold::CannotChangeHoldType') ) { + warn $_; + } else { + $_->rethrow; + } + } } } } diff --git a/reserve/request.pl b/reserve/request.pl index c5e354aa7d..eea72ecc08 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -39,7 +39,8 @@ use C4::Koha qw( getitemtypeimagelocation ); use C4::Serials qw( CountSubscriptionFromBiblionumber ); use C4::Circulation qw( _GetCircControlBranch GetBranchItemRule ); use Koha::DateUtils qw( dt_from_string ); -use C4::Search qw( enabled_staff_search_views ); +use C4::Search qw( enabled_staff_search_views ); +use C4::Context; use Koha::Biblios; use Koha::Checkouts; @@ -64,6 +65,14 @@ my ( $template, $borrowernumber, $cookie, $flags ) = get_template_and_user( } ); +my $is_super_librarian = C4::Context->IsSuperLibrarian(); +my $user_branch = C4::Context->preference("IndependentBranches") ? C4::Context->userenv->{'branch'}: undef; + +$template->param( + is_super_librarian => $is_super_librarian, + user_branch => $user_branch, +); + my $showallitems = $input->param('showallitems'); my $pickup = $input->param('pickup'); @@ -88,8 +97,9 @@ my $warnings; my $messages; my $exceeded_maxreserves; my $exceeded_holds_per_record; -my @failed_holds = $input->multi_param('failed_holds'); +my @failed_holds = $input->multi_param('failed_holds'); my $form_submitted = $input->param('form_submitted'); +my $can_modify_all_holds = $is_super_librarian || !defined($user_branch); my $op = $input->param('op') || q{}; @@ -101,44 +111,60 @@ if ( $op eq 'cud-move' ) { my $first_priority = $input->param('first_priority'); my $last_priority = $input->param('last_priority'); my $hold_itemnumber = $input->param('itemnumber'); - if ( $prev_priority == 0 && $next_priority == 1 ) { - C4::Reserves::RevertWaitingStatus( { itemnumber => $hold_itemnumber } ); - } else { - AlterPriority( - $where, $reserve_id, $prev_priority, - $next_priority, $first_priority, $last_priority - ); - } + if ( $prev_priority == 0 && $next_priority == 1 ) { + C4::Reserves::RevertWaitingStatus( { itemnumber => $hold_itemnumber } ); + } else { + AlterPriority( + $where, $reserve_id, $prev_priority, + $next_priority, $first_priority, $last_priority + ); + } } elsif ( $op eq 'cud-cancel' ) { my $reserve_id = $input->param('reserve_id'); my $cancellation_reason = $input->param("cancellation-reason"); my $hold = Koha::Holds->find($reserve_id); - $hold->cancel( { cancellation_reason => $cancellation_reason } ) if $hold; + if ( $can_modify_all_holds || $hold->branchcode eq $user_branch ) { + $hold->cancel( { cancellation_reason => $cancellation_reason } ) if $hold; + } } elsif ( $op eq 'cud-setLowestPriority' ) { my $reserve_id = $input->param('reserve_id'); - ToggleLowestPriority($reserve_id); + if ( $can_modify_all_holds || Koha::Holds->find($reserve_id)->branchcode eq $user_branch ) { + ToggleLowestPriority($reserve_id); + } } elsif ( $op eq 'cud-suspend' ) { my $reserve_id = $input->param('reserve_id'); my $suspend_until = $input->param('suspend_until'); my $hold = Koha::Holds->find($reserve_id); - $hold->suspend_hold($suspend_until) if $hold; + if (( $can_modify_all_holds || $hold->branchcode) eq $user_branch ) { + $hold->suspend_hold($suspend_until) if $hold; + } } elsif ( $op eq 'cud-unsuspend' ) { my $reserve_id = $input->param('reserve_id'); my $hold = Koha::Holds->find($reserve_id); - $hold->resume() if $hold; + if ( $can_modify_all_holds || $hold->branchcode eq $user_branch ) { + $hold->resume() if $hold; + } } elsif ( $op eq 'cud-cancel_bulk' ) { my $cancellation_reason = $input->param("cancellation-reason"); my @hold_ids = split( ',', scalar $input->param("ids") ); - my $params = { - reason => $cancellation_reason, - hold_ids => \@hold_ids, - }; - my $job_id = Koha::BackgroundJob::BatchCancelHold->new->enqueue($params); + for (my $i = 0; $i < @hold_ids; $i++) { + if (!( $can_modify_all_holds || (Koha::Holds->find($hold_ids[$i])->branchcode) eq $user_branch )) { + splice(@hold_ids, $i, 1); + $i--; + } + } + unless (scalar @hold_ids == 0) { + my $params = { + reason => $cancellation_reason, + hold_ids => \@hold_ids, + }; + my $job_id = Koha::BackgroundJob::BatchCancelHold->new->enqueue($params); - $template->param( - enqueued => 1, - job_id => $job_id - ); + $template->param( + enqueued => 1, + job_id => $job_id + ); + } } if ($findborrower) { -- 2.43.0