From 174d220057cacd4d791d60b50da49285f8c49d25 Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Thu, 14 Sep 2023 04:06:24 +0000 Subject: [PATCH] Bug 11300: (Fix) Fixing the authority linking --- C4/Biblio.pm.rej | 20 ----- C4/Linker/Z3950Server.pm | 157 +++++++++++++++++++++++++++++++-------- 2 files changed, 125 insertions(+), 52 deletions(-) delete mode 100644 C4/Biblio.pm.rej diff --git a/C4/Biblio.pm.rej b/C4/Biblio.pm.rej deleted file mode 100644 index dc41b7d742..0000000000 --- a/C4/Biblio.pm.rej +++ /dev/null @@ -1,20 +0,0 @@ -diff a/C4/Biblio.pm b/C4/Biblio.pm (rejected hunks) -@@ -461,7 +462,7 @@ sub BiblioAutoLink { - - =head2 LinkBibHeadingsToAuthorities - -- my $num_headings_changed, %results = LinkBibHeadingsToAuthorities($linker, $marc, $frameworkcode, [$allowrelink, $verbose]); -+ my $num_headings_changed, %results = LinkBibHeadingsToAuthorities($linker, $marc, $frameworkcode, [$allowrelink, $verbose, $dont_auto_create]); - - Links bib headings to authority records by checking - each authority-controlled field in the C -@@ -484,7 +485,9 @@ sub LinkBibHeadingsToAuthorities { - my $frameworkcode = shift; - my $allowrelink = shift; - my $verbose = shift; -+ my $dont_auto_create = shift; - my %results; -+ my $linker_default=C4::Linker::Default->new(); - if (!$bib) { - carp 'LinkBibHeadingsToAuthorities called on undefined bib record'; - return ( 0, {}); diff --git a/C4/Linker/Z3950Server.pm b/C4/Linker/Z3950Server.pm index 5c2074012e..2b76571e28 100644 --- a/C4/Linker/Z3950Server.pm +++ b/C4/Linker/Z3950Server.pm @@ -15,8 +15,7 @@ package C4::Linker::Z3950Server; # You should have received a copy of the GNU General Public License # along with Koha; if not, see . -use strict; -use warnings; +use Modern::Perl; use Carp; use MARC::Field; use MARC::Record; @@ -135,10 +134,51 @@ sub flip_heading { =cut +sub GetMandatoryFieldZ3950 { + my $authtypecode = shift; + if ( C4::Context->preference('marcflavour') eq 'MARC21' ){ + return { + 'PERSO_NAME' =>'authorpersonal', + 'CORPO_NAME' => 'authorcorp', + 'MEETI_NAME' => 'authormeetingcon', + 'UNIF_TITLE' => 'uniformtitle', + 'TOPIC_TERM' =>'subject', + }; + } + else{ + return { + 'NP' => 'authorpersonal', + 'CO' => 'authorcorp', + 'TU'=> 'uniformtitle', + } + } +} + +sub _auth_build_query { + my $attr = shift; + + my $qry_build = { + authorcorp => '@attr 1=2 "#term" ', + authorpersonal => '@attr 1=1 "#term" ', + authormeetingcon => '@attr 1=3 "#term" ', + subject => '@attr 1=21 "#term" ', + uniformtitle => '@attr 1=6 "#term" ', + }; + return $qry_build->{$attr}; +} + sub getZ3950Authority { my $self = shift; my $heading = shift; + my @connexion; + my $record; + my $result; + my $dbh = C4::Context->dbh; + my $authtypecode = $heading->{'auth_type'}; + my $mandatory_z3950 = $self->GetMandatoryFieldZ3950($authtypecode); + return ( undef, undef, 'Z3950_SEARCH_ERROR' ) if ( !exists $mandatory_z3950->{$authtypecode} ); + my $attr = $mandatory_z3950->{$authtypecode}; # Try to find a match on the Z39.50 server if LinkerZ3950Server is set if(C4::Context->preference('LinkerZ3950Server')) { unless($self->{'conn'}) { @@ -149,18 +189,72 @@ sub getZ3950Authority { if($server) { my $options = ZOOM::Options->new(); - $options->option('cclfile' => C4::Context->new()->{"serverinfo"}->{"authorityserver"}->{"ccl2rpn"}); $options->option('elementSetName', 'F'); $options->option('async', 0); $options->option('databaseName', $server->{db}); $options->option('user', $server->{userid} ) if $server->{userid}; $options->option('password', $server->{password}) if $server->{password}; $options->option('preferredRecordSyntax', $server->{syntax}); - $self->{'conn'} = create ZOOM::Connection($options); - eval{ $self->{'conn'}->connect( $server->{host}, $server->{port} ) }; - if($@) { - return (undef, undef, 'NO_CONNECTION'); - }} + if( $server->{servertype} eq 'sru' ) { + foreach( split ',', $server->{sru_options}//'' ) { + #first remove surrounding spaces at comma and equals-sign + s/^\s+|\s+$//g; + my @temp= split '=', $_, 2; + @temp= map { my $c=$_; $c=~s/^\s+|\s+$//g; $c; } @temp; + $options->option( $temp[0] => $temp[1] ) if @temp; + } + } elsif( $server->{servertype} eq 'zed' ) { + $options->option( 'databaseName', $server->{db} ); + $options->option( 'user', $server->{userid} ) if $server->{userid}; + $options->option( 'password', $server->{password} ) if $server->{password}; + } + $connexion[0]= ZOOM::Connection->create($options); + if( $server->{servertype} eq 'sru' ) { + my $host= $server->{host}; + if( $host !~ /^https?:\/\// ) { + $host = 'http://' . $host; + } + eval{ $connexion[0]->connect( $host.':'.$server->{port}.'/'.$server->{db} ); }; + if($@) { + return (undef, undef, 'NO_CONNECTION'); + } + } else { + eval{ $connexion[0]->connect( $server->{host}, $server->{port} ); }; + if($@) { + return (undef, undef, 'NO_CONNECTION'); + } + } + my $qry_build->{$attr} = _auth_build_query($attr); + my $zqueryq=''; + my $squery=''; + if( $heading->{'search_form'} && $qry_build->{$attr} ) { + $qry_build->{$attr} =~ s/#term/$heading->{'search_form'}/g; + $zqueryq = $qry_build->{$attr}; + $squery = "[".$attr."]=\"$heading->{'search_form'}\""; + + } + if ( $server->{servertype} eq 'zed' ) { + my $server_zquery = $zqueryq; + if ( my $attributes = $server->{attributes} ) { + $server_zquery = "$attributes $zqueryq"; + } + $result = $connexion[0]->search_pqf( $server_zquery ); + } + else { + $result = $connexion[0]->search( + ZOOM::Query::CQL->new(_translate_query( $server, $squery )) + ); + } + if ( ZOOM::event( \@connexion ) != 0 ) { + $connexion[0]->last_event(); + } + if( $result->size() > 0 ) { + $record = MARC::Record::new_from_usmarc($result->record(0)->raw()); + } + else{ + return (undef, undef, 'Z3950_SEARCH_ERROR'); + } + } else { return (undef, undef, 'SERVER_NOT_FOUND'); } @@ -169,29 +263,6 @@ sub getZ3950Authority { else { return; } - my $query =qq(Match-Heading,do-not-truncate,ext="$heading->{'search_form'}"); - my $zquery = eval{ ZOOM::Query::CCL2RPN->new($query, $self->{'conn'}) }; - if($@) { - warn $query . "\n" . $@; - return (undef, undef, 'Z3950_QUERY_ERROR'); - } - - # Try to send the search query to the server. - my $rs = eval{ $self->{'conn'}->search($zquery) }; - if($@){ - warn $query . "\n" . $@; - return (undef, undef, 'Z3950_SEARCH_EMPTY'); - } - - # If authorities are found, select the first valid one for addition in the local authority table. - my $record; - if($rs->size() != 0) { - $record = MARC::Record::new_from_usmarc($rs->record(0)->raw()); - }else{ - return (undef, undef, 'Z3950_SEARCH_ERROR'); - } - $rs->destroy(); - $zquery->destroy(); # If a valid authority was found, add it in the local authority database. if($record) { @@ -201,7 +272,7 @@ sub getZ3950Authority { my $authId; # Use the control number to prevent the creation of duplicate authorities. - my $controlNumber = $record->field('970')->subfield('0'); + my $controlNumber = $record->field('001')->data; my $sthExist=$dbh->prepare("SELECT authid FROM auth_header WHERE origincode =?"); $sthExist->execute($controlNumber) or die $sthExist->errstr; ($authId) = $sthExist->fetchrow; @@ -313,4 +384,26 @@ sub getZ3950Authority { return ; } +sub _translate_query { #SRU query adjusted per server cf. srufields column + my ($server, $query) = @_; + + #sru_fields is in format title=field,isbn=field,... + #if a field doesn't exist, try anywhere or remove [field]= + my @parts= split(',', $server->{sru_fields} ); + my %trans= map { if( /=/ ) { ( $`,$' ) } else { () } } @parts; + my $any= $trans{srchany}?$trans{srchany}.'=':''; + + my $q=$query; + foreach my $key (keys %trans) { + my $f=$trans{$key}; + if( $f ) { + $q=~s/\[$key\]/$f/g; + } else { + $q=~s/\[$key\]=/$any/g; + } + } + $q=~s/\[\w+\]=/$any/g; # remove remaining fields (not found in field list) + return $q; +} + 1; -- 2.34.1