From b1724b37096ff5efd98f3cbf3a88ba4eed6b6188 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 27 Feb 2026 07:06:24 +0000 Subject: [PATCH] Bug 10190: Enforce manage_circ_rules_from_any_libraries permission - Add OR-type x-koha-authorization to /circulation_rules, /circulation_rules/kinds, and /circulation_rules/config endpoints so users with either circulate:circulate_remaining_permissions OR parameters:manage_circ_rules can access them - Enforce manage_circ_rules_from_any_libraries in the set_rules controller: users without this permission may only set rules for their own library and cannot set default (*) rules - Add explicit use C4::Auth qw(haspermission) import to CirculationRules.pm - Lock the library selector in the Vue UI for users who lack manage_circ_rules_from_any_libraries, defaulting them to their own library - Update set_rules() tests to cover the new permission restrictions --- Koha/REST/V1/CirculationRules.pm | 16 ++++- api/v1/swagger/paths/circulation_rules.yaml | 3 + .../paths/circulation_rules_config.yaml | 1 + .../en/modules/admin/circulation_triggers.tt | 1 + .../CirculationTriggersFormAdd.vue | 25 +++++++- .../CirculationTriggersList.vue | 35 ++++++++--- .../Admin/CirculationTriggers/Main.vue | 4 +- .../prog/js/vue/stores/circulation-rules.js | 22 ++++++- t/db_dependent/api/v1/circulation_rules.t | 59 ++++++++++++++++++- 9 files changed, 147 insertions(+), 19 deletions(-) diff --git a/Koha/REST/V1/CirculationRules.pm b/Koha/REST/V1/CirculationRules.pm index 23f77a0681d..a42a6c8a71c 100644 --- a/Koha/REST/V1/CirculationRules.pm +++ b/Koha/REST/V1/CirculationRules.pm @@ -19,6 +19,7 @@ use Modern::Perl; use Mojo::Base 'Mojolicious::Controller'; +use C4::Auth qw( haspermission ); use Koha::CirculationRules; =head1 API @@ -240,6 +241,19 @@ sub set_rules { ) unless $library; } + my $logged_in_user = $c->stash('koha.user'); + unless ( haspermission( $logged_in_user->userid, { parameters => 'manage_circ_rules_from_any_libraries' } ) ) { + if ( !defined $branchcode || $branchcode ne $logged_in_user->branchcode ) { + return $c->render( + status => 403, + openapi => { + error => + 'manage_circ_rules_from_any_libraries permission is required to manage circulation rules for libraries other than your own' + } + ); + } + } + if ( $patron_category eq '*' ) { $patron_category = undef; } else { @@ -326,7 +340,7 @@ sub config { my $c = shift->openapi->valid_input or return; my $patron = $c->stash('koha.user'); - my $userflags = C4::Auth::haspermission( $patron->userid ); + my $userflags = haspermission( $patron->userid ); my $permissions = Koha::Auth::Permissions->get_authz_from_flags( { flags => $userflags } ); return $c->render( diff --git a/api/v1/swagger/paths/circulation_rules.yaml b/api/v1/swagger/paths/circulation_rules.yaml index b08e1f6bf7f..3767932b181 100644 --- a/api/v1/swagger/paths/circulation_rules.yaml +++ b/api/v1/swagger/paths/circulation_rules.yaml @@ -77,6 +77,7 @@ x-koha-authorization: permissions: - circulate: circulate_remaining_permissions + - parameters: manage_circ_rules put: x-mojo-to: CirculationRules#set_rules operationId: setCirculationRules @@ -131,6 +132,7 @@ x-koha-authorization: permissions: - circulate: circulate_remaining_permissions + - parameters: manage_circ_rules /circulation_rules/kinds: get: x-mojo-to: CirculationRules#get_kinds @@ -169,3 +171,4 @@ x-koha-authorization: permissions: - circulate: circulate_remaining_permissions + - parameters: manage_circ_rules diff --git a/api/v1/swagger/paths/circulation_rules_config.yaml b/api/v1/swagger/paths/circulation_rules_config.yaml index 6d8c7bf7f90..67c9003b714 100644 --- a/api/v1/swagger/paths/circulation_rules_config.yaml +++ b/api/v1/swagger/paths/circulation_rules_config.yaml @@ -36,3 +36,4 @@ x-koha-authorization: permissions: - circulate: circulate_remaining_permissions + - parameters: manage_circ_rules diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/circulation_triggers.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/circulation_triggers.tt index 1d30f010470..c42a87abb65 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/circulation_triggers.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/circulation_triggers.tt @@ -34,6 +34,7 @@ const letters = [% To.json(letters) | $raw %]; const default_view = "[%- IF Koha.Preference('DefaultToLoggedInLibraryOverdueTriggers') -%][% Branches.GetLoggedInBranchcode | html %][%- ELSE -%]*[%- END -%]"; const from_branch = "[% Koha.Preference('OverdueNoticeFrom') | html %]"; + const logged_in_library_id = "[% Branches.GetLoggedInBranchcode | html %]"; [% Asset.js("js/vue/dist/admin/circulation_triggers.js") | $raw %] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue index 5ceaf3c7788..a0422292ed2 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersFormAdd.vue @@ -36,8 +36,19 @@ v-model="context.library_id" label="name" :reduce="lib => lib.library_id" - :options="libraries" - :disabled="editMode !== 'confirmContext'" + :options=" + canManageAnyLibrary + ? libraries + : libraries.filter( + lib => + lib.library_id === + logged_in_library_id + ) + " + :disabled=" + editMode !== 'confirmContext' || + !canManageAnyLibrary + " >