From e4aecaa519003eef4b5c407aa755ba5dbb2bdb36 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Tue, 24 Mar 2026 10:47:33 +0100 Subject: [PATCH] Bug 10190: Add manage_circ_triggers permission for notice trigger access Replaces the broad manage_circ_rules permission requirement on the circulation triggers page with a new dedicated manage_circ_triggers sub-permission (under parameters, flag 3). - Add manage_circ_triggers to userpermissions.sql - Update atomicupdate to add the permission, grant it to existing edit_notice_status_triggers users, and remove the old permission - Update admin/circulation_triggers.pl to require manage_circ_triggers - Add manage_circ_triggers as an OR option on all circulation_rules API endpoints (GET/PUT /circulation_rules, /kinds, /config) - Restrict manage_circ_triggers users in the API controller to overdue_* rule names only on write Sponsored-by: Glasgow Colleges Library Group Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim --- Koha/REST/V1/CirculationRules.pm | 15 +++++++++ admin/circulation_triggers.pl | 2 +- api/v1/swagger/paths/circulation_rules.yaml | 3 ++ .../paths/circulation_rules_config.yaml | 1 + .../data/mysql/atomicupdate/bug_10190.pl | 33 +++++++++++++++---- .../data/mysql/mandatory/userpermissions.sql | 1 + .../CirculationTriggersList.vue | 2 +- 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/Koha/REST/V1/CirculationRules.pm b/Koha/REST/V1/CirculationRules.pm index a42a6c8a71..aeb86cff73 100644 --- a/Koha/REST/V1/CirculationRules.pm +++ b/Koha/REST/V1/CirculationRules.pm @@ -254,6 +254,21 @@ sub set_rules { } } + unless ( haspermission( $logged_in_user->userid, { parameters => 'manage_circ_rules' } ) + || haspermission( $logged_in_user->userid, { circulate => 'circulate_remaining_permissions' } ) ) + { + my $rules_to_set = {%$body}; + delete $rules_to_set->{context}; + my @non_trigger_rules = grep { !/^overdue_/ } keys %{$rules_to_set}; + if (@non_trigger_rules) { + return $c->render( + status => 403, + openapi => + { error => 'manage_circ_rules permission is required to manage non-trigger circulation rules' } + ); + } + } + if ( $patron_category eq '*' ) { $patron_category = undef; } else { diff --git a/admin/circulation_triggers.pl b/admin/circulation_triggers.pl index 07845c8cff..4ec6195479 100755 --- a/admin/circulation_triggers.pl +++ b/admin/circulation_triggers.pl @@ -31,7 +31,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( template_name => "admin/circulation_triggers.tt", query => $query, type => "intranet", - flagsrequired => { parameters => 'manage_circ_rules' }, + flagsrequired => { parameters => 'manage_circ_triggers' }, } ); diff --git a/api/v1/swagger/paths/circulation_rules.yaml b/api/v1/swagger/paths/circulation_rules.yaml index 3767932b18..8f493f4f2c 100644 --- a/api/v1/swagger/paths/circulation_rules.yaml +++ b/api/v1/swagger/paths/circulation_rules.yaml @@ -78,6 +78,7 @@ permissions: - circulate: circulate_remaining_permissions - parameters: manage_circ_rules + - parameters: manage_circ_triggers put: x-mojo-to: CirculationRules#set_rules operationId: setCirculationRules @@ -133,6 +134,7 @@ permissions: - circulate: circulate_remaining_permissions - parameters: manage_circ_rules + - parameters: manage_circ_triggers /circulation_rules/kinds: get: x-mojo-to: CirculationRules#get_kinds @@ -172,3 +174,4 @@ permissions: - circulate: circulate_remaining_permissions - parameters: manage_circ_rules + - parameters: manage_circ_triggers diff --git a/api/v1/swagger/paths/circulation_rules_config.yaml b/api/v1/swagger/paths/circulation_rules_config.yaml index 67c9003b71..136ae56327 100644 --- a/api/v1/swagger/paths/circulation_rules_config.yaml +++ b/api/v1/swagger/paths/circulation_rules_config.yaml @@ -37,3 +37,4 @@ permissions: - circulate: circulate_remaining_permissions - parameters: manage_circ_rules + - parameters: manage_circ_triggers diff --git a/installer/data/mysql/atomicupdate/bug_10190.pl b/installer/data/mysql/atomicupdate/bug_10190.pl index aabdb48a38..47e627d96b 100755 --- a/installer/data/mysql/atomicupdate/bug_10190.pl +++ b/installer/data/mysql/atomicupdate/bug_10190.pl @@ -3,11 +3,36 @@ use Koha::Installer::Output qw(say_warning say_failure say_success say_info); return { bug_number => "10190", - description => "Migrate overduerules to circulation_rules", + description => "Migrate overduerules to circulation_rules and add manage_circ_triggers permission", up => sub { my ($args) = @_; my ( $dbh, $out ) = @$args{qw(dbh out)}; + # Add the new dedicated permission for managing overdue notice triggers. + $dbh->do( + q{ + INSERT IGNORE INTO permissions (module_bit, code, description) VALUES + (3, 'manage_circ_triggers', 'Manage overdue notice triggers') + } + ); + say_success( $out, "Added new permission 'manage_circ_triggers'" ); + + # Grant manage_circ_triggers to any user who previously had edit_notice_status_triggers, + # so they retain access to the notice triggers page after the permission migration. + $dbh->do( + q{ + INSERT IGNORE INTO user_permissions (borrowernumber, module_bit, code) + SELECT borrowernumber, 3, 'manage_circ_triggers' + FROM user_permissions + WHERE code = 'edit_notice_status_triggers' + } + ); + + # Remove the old tools sub-permission for notice triggers. + # user_permissions rows are cleaned up automatically via ON DELETE CASCADE. + $dbh->do(q|DELETE FROM permissions WHERE code = 'edit_notice_status_triggers'|); + say_success( $out, "Removed deprecated permission 'edit_notice_status_triggers'" ); + # This script pulls data from these tables then drops them. # Skip silently if they no longer exist (e.g. fresh install or already migrated). if ( !TableExists('overduerules_transport_types') || !TableExists('overduerules') ) { @@ -15,12 +40,6 @@ return { return; } - # Remove the tools sub-permission for notice triggers; access is now - # controlled by parameters/manage_circ_rules instead. - # user_permissions rows are cleaned up automatically via ON DELETE CASCADE. - $dbh->do(q|DELETE FROM permissions WHERE code = 'edit_notice_status_triggers'|); - say_success( $out, "Removed deprecated permission 'edit_notice_status_triggers'" ); - # Fetch all explicit overdue rules with their transport types. # No phantom rows are added - only rules that were explicitly configured are migrated. my $rules = $dbh->selectall_arrayref( diff --git a/installer/data/mysql/mandatory/userpermissions.sql b/installer/data/mysql/mandatory/userpermissions.sql index 0515afc877..6469c74452 100644 --- a/installer/data/mysql/mandatory/userpermissions.sql +++ b/installer/data/mysql/mandatory/userpermissions.sql @@ -11,6 +11,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES ( 3, 'manage_accounts', 'Manage Account Debit and Credit Types' ), ( 3, 'manage_circ_rules', 'Manage circulation rules'), ( 3, 'manage_circ_rules_from_any_libraries', 'Manage circ rules for any libraries'), + ( 3, 'manage_circ_triggers', 'Manage overdue notice triggers'), ( 3, 'manage_sysprefs', 'Manage system preferences'), ( 3, 'manage_libraries', 'Manage libraries and library groups'), ( 3, 'manage_itemtypes', 'Manage item types'), diff --git a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersList.vue b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersList.vue index 989f145c89..9c3d5f9c3d 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersList.vue +++ b/koha-tmpl/intranet-tmpl/prog/js/vue/components/Admin/CirculationTriggers/CirculationTriggersList.vue @@ -243,7 +243,7 @@ :options="[ { value: 0, - label: 'explictly set rules.', + label: 'explicitly set rules.', }, { value: 1,