From 6b845d14153eb99a7a866a5d78433c9bfaadd7a2 Mon Sep 17 00:00:00 2001 From: David Gustafsson Date: Tue, 14 Nov 2023 19:56:32 +0100 Subject: [PATCH] Bug 33268: Overlay rules don't work correctly when source is set to * Fallback to overlay rules with wildcard filter if no match found for exact filter match. --- Koha/MarcOverlayRules.pm | 80 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/Koha/MarcOverlayRules.pm b/Koha/MarcOverlayRules.pm index b874f7cd075..caaa30340e2 100644 --- a/Koha/MarcOverlayRules.pm +++ b/Koha/MarcOverlayRules.pm @@ -16,13 +16,14 @@ package Koha::MarcOverlayRules; # along with Koha; if not, see . use Modern::Perl; -use List::Util qw(first); +use List::Util qw(first any); use Koha::MarcOverlayRule; use Carp; use Koha::Exceptions::MarcOverlayRule; use Try::Tiny; use Scalar::Util qw(looks_like_number); +use Clone qw(clone); use parent qw(Koha::Objects); @@ -46,6 +47,17 @@ sub operations { return ('add', 'append', 'remove', 'delete'); } +=head3 modules + +Returns a list of all modules in order of priority. + +=cut + +sub modules { + return ('userid', 'categorycode', 'source'); +} + + =head3 context_rules my $rules = Koha::MarcOverlayRules->context_rules($context); @@ -96,19 +108,77 @@ sub context_rules { $cache->set_in_cache('marc_overlay_rules', $rules); } - my $context_rules = undef; - foreach my $module_name (keys %{$context}) { + my $context_rules; + my @context_modules = grep { exists $context->{$_} } $self->modules(); + + foreach my $module_name (@context_modules) { if ( exists $rules->{$module_name} && exists $rules->{$module_name}->{$context->{$module_name}} ) { $context_rules = $rules->{$module_name}->{$context->{$module_name}}; + + unless (exists $rules->{$module_name}->{'*'}) { + # No wildcard filter rules defined + last; + } + + # Merge in all wildcard filter rules which has not been overriden + # by the matching context + if ($context_rules->{'*'}) { + # Wildcard tag for matching context will override all rules, + # nothing left to do + last; + } + + # Clone since we will potentially be modified cached value + # fetched with unsafe => 1 + $context_rules = clone($context_rules); + + if (exists $rules->{$module_name}->{'*'}->{'*'}) { + # Merge in wildcard filter wildcard tag rule if exists + $context_rules->{'*'} = $rules->{$module_name}->{'*'}->{'*'}; + } + + if (exists $rules->{$module_name}->{'*'}->{tags}) { + if (exists $context_rules->{regexps}) { + # If the current context has regexp rules, we have to make sure + # to not only to skip tags already present but also those matching + # any of those rules + + my @regexps = map { qr/^$_->[0]$/ } @{$context_rules->{regexps}}; + + foreach my $tag (keys %{$rules->{$module_name}->{'*'}->{tags}}) { + unless ((any { $tag =~ $_ } @regexps) || exists $context_rules->{tags}->{$tag}) { + $context_rules->{tags}->{$tag} = $rules->{$module_name}->{'*'}->{tags}->{$tag}; + } + } + } + else { + # Merge in wildcard filter tag rules not already present + # in the matching context + foreach my $tag (keys %{$rules->{$module_name}->{'*'}->{tags}}) { + unless (exists $context_rules->{tags}->{$tag}) { + $context_rules->{tags}->{$tag} = $rules->{$module_name}->{'*'}->{tags}->{$tag}; + } + } + } + } + + if (exists $rules->{$module_name}->{'*'}->{regexps}) { + # Merge in wildcard filter regexp rules last, making sure rules from the + # matching context have precidence + $context_rules->{regexps} //= []; + push @{$context_rules->{regexps}}, @{$rules->{$module_name}->{'*'}->{regexps}}; + } + last; } } + if (!$context_rules) { - # No perms matching specific context conditions found, try wildcard value for each active context - foreach my $module_name (keys %{$context}) { + # No rules matching specific context conditions found, try wildcard value for each active context + foreach my $module_name (@context_modules) { if (exists $rules->{$module_name}->{'*'}) { $context_rules = $rules->{$module_name}->{'*'}; last; -- 2.42.0