From 6f157748ad99608a6b697f346f2d5fc79301351e Mon Sep 17 00:00:00 2001 From: Marcel de Rooy Date: Thu, 26 Jun 2025 16:23:43 +0200 Subject: [PATCH] Bug 40272: Add an alert for bad fixed-length control fields Content-Type: text/plain; charset=utf-8 Development wise it is much simpler to do this check in perl when opening the editor than getting this logic into the template with javascript. Furthermore, older data may be corrupted, but we trust the current plugins to not insert such fields anymore. Test plan: Run t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t Open an existing record in the basic editor. Shorten 008 without plugin. Save and open the record again. Do you get the alert? Signed-off-by: Marcel de Rooy --- Koha/Biblio/Metadata/Extractor/MARC/MARC21.pm | 54 +++++++++++++++++++ cataloguing/addbiblio.pl | 11 +++- .../prog/en/modules/cataloguing/addbiblio.tt | 4 ++ .../Biblio/Metadata/Extractor/MARC/MARC21.t | 40 +++++++++++++- 4 files changed, 106 insertions(+), 3 deletions(-) diff --git a/Koha/Biblio/Metadata/Extractor/MARC/MARC21.pm b/Koha/Biblio/Metadata/Extractor/MARC/MARC21.pm index 4fe7df8afe..fc3d9fcbfc 100644 --- a/Koha/Biblio/Metadata/Extractor/MARC/MARC21.pm +++ b/Koha/Biblio/Metadata/Extractor/MARC/MARC21.pm @@ -96,6 +96,60 @@ sub get_normalized_oclc { } } +=head2 check_fixed_length + + my $info = $extractor->check_fixed_length; + +Returns a hash containing passed and failed fixed-length control fields. + +=cut + +sub check_fixed_length { + my $self = shift; + my $len_ok = { + '005' => 16, + '006' => 18, + '007' => { + a => 8, + c => [ 6, 14 ], + d => 6, + f => 10, + g => 9, + h => 13, + k => 6, + m => [ 8, 23 ], + o => 2, + q => 2, + r => 11, + s => 14, + t => 2, + v => 9, + z => 2, + }, + '008' => 40, + }; + my $record = $self->metadata; + my $result = { passed => [], failed => [] }; + foreach my $field ( $record->field( '005', '006', '007', '008' ) ) { + my ( $length, $pass ); + if ( $field->tag ne '007' ) { + $length = $len_ok->{ $field->tag }; + $pass = length( $field->data ) eq $length; + } else { + my $pos_0 = substr( $field->data, 0, 1 ); + $length = $len_ok->{ $field->tag }->{$pos_0}; + if ( ref($length) eq 'ARRAY' ) { + $pass = grep { $_ eq length( $field->data ) } @$length; + } else { + $pass = length( $field->data ) eq $length; + } + } + push @{ $result->{passed} }, $field->tag if $pass; + push @{ $result->{failed} }, $field->tag unless $pass; + } + return $result; +} + =head1 AUTHOR Tomas Cohen Arazi, Etomascohen@theke.ioE diff --git a/cataloguing/addbiblio.pl b/cataloguing/addbiblio.pl index 58f555d6de..627c5dcc75 100755 --- a/cataloguing/addbiblio.pl +++ b/cataloguing/addbiblio.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl # Copyright 2000-2002 Katipo Communications # Copyright 2004-2010 BibLibre @@ -53,7 +53,7 @@ use Koha::Biblios; use Koha::ItemTypes; use Koha::Libraries; -use Koha::BiblioFrameworks; +use Koha::Biblio::Metadata::Extractor::MARC::MARC21; use Koha::Patrons; use Koha::UI::Form::Builder::Biblio; @@ -833,6 +833,13 @@ if ( $op eq "cud-addbiblio" ) { #---------------------------------------------------------------------------- # If we're in a duplication case, we have to set to "" the biblionumber # as we'll save the biblio as a new one. + + if ( C4::Context->preference('marcflavour') eq 'MARC21' ) { + my $fixed_length_info = + Koha::Biblio::Metadata::Extractor::MARC::MARC21->new( { biblio => $biblio } )->check_fixed_length; + $template->param( marc21_fixlen => $fixed_length_info ) if @{ $fixed_length_info->{failed} }; + } + $template->param( biblionumberdata => $biblionumber, op => $op, diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt index 003358530c..fb1dff7940 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/addbiblio.tt @@ -805,6 +805,10 @@ [% END %] + [% IF marc21_fixlen %] +

WARNING

The following fixed-length control field(s) have an invalid length: [% marc21_fixlen.failed.join(',') | html %]. Please fix.

+ [% END %] + [% IF ( Koha.Preference('EnableAdvancedCatalogingEditor') && CAN_user_editcatalogue_advanced_editor ) %]
diff --git a/t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t b/t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t index de5c62d7f9..32d7261a28 100755 --- a/t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t +++ b/t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t @@ -20,13 +20,15 @@ use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 4; +use Test::More tests => 5; use Test::Exception; use t::lib::TestBuilder; use t::lib::Mocks; +use C4::Biblio qw(ModBiblio); use Koha::Biblio::Metadata::Extractor; +use Koha::Biblio::Metadata::Extractor::MARC::MARC21; my $schema = Koha::Database->schema; my $builder = t::lib::TestBuilder->new; @@ -87,3 +89,39 @@ subtest 'get_normalized_oclc() tests' => sub { is( $extractor->get_normalized_oclc, "" ); }; + +subtest 'check_fixed_length' => sub { + + plan tests => 6; + $schema->storage->txn_begin; + + my $record = MARC::Record->new; + $record->append_fields( + MARC::Field->new( '005', '0123456789012345' ), + ); + my $biblio = $builder->build_sample_biblio; + ModBiblio( $record, $biblio->biblionumber ); + + my $extractor; + $extractor = Koha::Biblio::Metadata::Extractor::MARC::MARC21->new( { biblio => $biblio } ); + my $result = $extractor->check_fixed_length; + is( $result->{passed}->[0], '005', 'Check first passed field' ); + is( scalar @{ $result->{failed} }, 0, 'Check failed count' ); + + $record->append_fields( + MARC::Field->new( '006', '01234567890123456789' ), # too long + MARC::Field->new( '007', 'a1234567' ), + MARC::Field->new( '007', 'm12345678' ), # should be 8 or 23 + MARC::Field->new( '007', 'm1234567890123456789012' ), + ); + + # Passing latest record changes via metadata now + $extractor = Koha::Biblio::Metadata::Extractor::MARC::MARC21->new( { metadata => $record } ); + $result = $extractor->check_fixed_length; + is( $result->{passed}->[1], '007', 'Check second passed field' ); + is( $result->{passed}->[2], '007', 'Check third passed field' ); + is( $result->{failed}->[0], '006', 'Check first failed field' ); + is( $result->{failed}->[1], '007', 'Check second failed field' ); + + $schema->storage->txn_rollback; +}; -- 2.39.5