From 297b1a3fceac5d7e041d0b5d01d84e24a46480f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Demians?= Date: Tue, 22 Nov 2022 09:30:32 +0100 Subject: [PATCH] Bug 32333: IdRef system preference revamping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IdRef system preference enables a Unimarc-only functionality. Authors fields contain in $3 subfield a PPN, an unique identifier in IdRef a French national authority file, similar to VIAF. KohaLa, the Koha French users association, has designed a revamped implementation of IdRef in Koha. The goal is to improve the visual and to add a functionality. - Visually — The author publications list is currently displayed in an old fashion dialog box. It uses greybox library, which is deprecated. See bug 8290. With this patch, the list is displayed in a distinct tab of holdings block. - Functionality — The title in the list are searched in Koha local catalog. So it's possible to mark titles locally available and link to them. PPN are searched directly in Elasticsearch for efficiency. Koha IdRef users are academic libraries or higher education school. So Zebra support is not required for them. NOTE: After pushing this patch, greybox library could be removed completely for OPAC : /koha-tmpl/opac-tmpl/bootstrap/lib/greybox/ TO TEST : - On a Unimarc Koha, with a Sudoc compliant Catalog, enable IdRef. - Use default OPAC XSL. - On opac-detail.pl page, you can see a logo IdRef next to authors having a $3 (ppn) subfield. Click on the logo. - Confirm that a tab is added to holdings. It contains the author publications found in the Sudoc. - A Sudoc logo is displayed in front of each title. Clicking the icon open the title in Sudoc web site. - A Koha logo is displayed in from of each title available locally. Clicking the logo open the title in Koha OPAC. --- .../bootstrap/en/includes/opac-bottom.inc | 4 + .../bootstrap/en/modules/opac-detail.tt | 4 + .../bootstrap/en/modules/opac-idref.tt | 77 ---- .../bootstrap/en/xslt/UNIMARCslimUtils.xsl | 18 +- .../bootstrap/images/idref-short.svg | 90 ++++ .../opac-tmpl/bootstrap/images/idref.svg | 403 ++++++++++++++++++ .../opac-tmpl/bootstrap/images/sudoc.png | Bin 0 -> 1319 bytes koha-tmpl/opac-tmpl/bootstrap/js/idref.js | 83 ++++ opac/opac-idref.pl | 91 ---- opac/svc/idref | 107 +++++ 10 files changed, 703 insertions(+), 174 deletions(-) delete mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-idref.tt create mode 100644 koha-tmpl/opac-tmpl/bootstrap/images/idref-short.svg create mode 100644 koha-tmpl/opac-tmpl/bootstrap/images/idref.svg create mode 100644 koha-tmpl/opac-tmpl/bootstrap/images/sudoc.png create mode 100644 koha-tmpl/opac-tmpl/bootstrap/js/idref.js delete mode 100755 opac/opac-idref.pl create mode 100755 opac/svc/idref diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc index 4fab59077d..819de4193e 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc @@ -250,6 +250,10 @@ [% END %] +[% IF Koha.Preference( 'IdRef' ) == 1 %] + [% Asset.js("js/idref.js") | $raw %] +[% END %] + [% IF ( BakerTaylorEnabled ) %] [% Asset.js("js/bakertaylorimages.js") | $raw %] -[% END %] - -[% INCLUDE 'opac-bottom.inc' is_popup=1%] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslimUtils.xsl b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslimUtils.xsl index dc02e6fc8e..44010459e1 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslimUtils.xsl +++ b/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslimUtils.xsl @@ -523,15 +523,21 @@ - - - /cgi-bin/koha/opac-idref.pl?unimarc3= + + - IdRef - gb_page_center[600,500] - Idref + + See publications in IdRef + + +
+ + idref-dialog- + + +
diff --git a/koha-tmpl/opac-tmpl/bootstrap/images/idref-short.svg b/koha-tmpl/opac-tmpl/bootstrap/images/idref-short.svg new file mode 100644 index 0000000000..5e25b27628 --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/images/idref-short.svg @@ -0,0 +1,90 @@ + + + +image/svg+xml + + + + + diff --git a/koha-tmpl/opac-tmpl/bootstrap/images/idref.svg b/koha-tmpl/opac-tmpl/bootstrap/images/idref.svg new file mode 100644 index 0000000000..b6f7dea38c --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/images/idref.svg @@ -0,0 +1,403 @@ + + + +image/svg+xml + + \ No newline at end of file diff --git a/koha-tmpl/opac-tmpl/bootstrap/images/sudoc.png b/koha-tmpl/opac-tmpl/bootstrap/images/sudoc.png new file mode 100644 index 0000000000000000000000000000000000000000..b43ebd00caff24e0eb9735831a59f3958c916cdd GIT binary patch literal 1319 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstPBjy3;{kN zu0U}y^*A~8czKNk1>jndxCPTXxWBazeirMoPEL^Z?@uDS5mn>Vpboq+qD_5;ty=K*# zwQJU`U$$a`icWm3SbH}dTyY}qey?5W<{Rj3RJaq8zkwZt09yxaW z|Ns9$SB-+v5THW{{5vOB$H2hIP!i-93`}?<888HYXIBLVIcI@KWHAGS5EwJ|DD7ki z3QCl?MwA5SrbP0l+eTl0E{TF Aa{vGU literal 0 HcmV?d00001 diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/idref.js b/koha-tmpl/opac-tmpl/bootstrap/js/idref.js new file mode 100644 index 0000000000..5523c08a1e --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/js/idref.js @@ -0,0 +1,83 @@ +if (KOHA === undefined || !KOHA) { var KOHA = {}; } + + +/** + * A namespace for idref + */ +KOHA.idref = { + + /** + * Set a click handler for all anchors . + */ + init: function() { + $("a[class='idref-link']").click(this.click); + }, + + /** + * Get the publications from author identified by its ppn, using Koha svc + * webservice. Display the result in a new tab of the holdings table. + */ + click: function(e) { + const ppn = $(this).attr("ppn"); + const url = '/cgi-bin/koha/svc/idref?ppn=' + ppn; + $.getJSON(url, function(publications) { + let html; + if (publications.name === '') { + html = __('Author not found in IdRef'); + } else { + const navig = publications.roles.map(role => '' + role.label + ' (' + role.docs.length + ')'); + html = + "

" + publications.name + " / " + + "" + + publications.ppn + "

" + + "
" + navig.join(' • ') + "
"; + publications.roles.forEach((role) => { + html += + "

" + role.label + "

" + + ""; + role.docs.forEach((doc) => { + html += + ""; + }); + html += '
" + + "" + + "" + + ""; + if (doc.bib) { + html += + "" + + "" + + ""; + } + html += "" + doc.citation + "
'; + }); + html += '
'; + } + const idrefDiv = $('#idref-publications'); + if (idrefDiv.length) { + idrefDiv.html(html); + } else { + html = "
" + html + "
"; + const tabMenu = + ''; + const tabs = $('#bibliodescriptions').tabs(); + const ul = tabs.find("ul"); + $(ul).append(tabMenu); + $('.tab-content').append(html); + tabs.tabs("refresh"); + } + $('a[href="#idref-publications"]').click(); + $([document.documentElement, document.body]).animate({ + scrollTop: $("#idref-publications").offset().top + }, 2000); + }); + } + +}; diff --git a/opac/opac-idref.pl b/opac/opac-idref.pl deleted file mode 100755 index 795842215f..0000000000 --- a/opac/opac-idref.pl +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/perl - -# This file is part of Koha. -# -# Copyright (C) 2014 BibLibre -# -# Koha is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# Koha is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Koha; if not, see . - -use Modern::Perl; - -use CGI; -use LWP::UserAgent; -use JSON qw( from_json ); -use Encode; - -use C4::Auth qw( get_template_and_user ); -use C4::Context; -use C4::Search; -use C4::Output qw( output_html_with_http_headers ); - -my $cgi = CGI->new; -my ( $template, $borrowernumber, $cookie ) = get_template_and_user( - { - template_name => "opac-idref.tt", - query => $cgi, - type => "opac", - authnotrequired => ( C4::Context->preference("OpacPublic") ? 1 : 0 ), - } -); - -my $ua = LWP::UserAgent->new; - -# See http://documentation.abes.fr/aideidrefdeveloppeur/index.html#MicroWebBiblio -my $base = 'http://www.idref.fr/services/biblio/'; -my $unimarc3 = $cgi->param('unimarc3'); - -my $request = HTTP::Request->new( - 'GET', - $base . $unimarc3 . ".json", -); -$request->protocol('HTTP/1.1'); -my $response = $ua->request($request); -if ( not $response->is_success) { - $template->param(error => $base.$unimarc3.'.json'); - output_html_with_http_headers $cgi, $cookie, $template->output; - exit; -} - -my $content = Encode::decode("utf8", $response->content); -my $json = from_json( $content ); -my $r; -my @results = ref $json->{sudoc}{result} eq "ARRAY" - ? @{ $json->{sudoc}{result} } - : ($json->{sudoc}{result}); - -for my $result (@results) { - my $role_node = $result->{'role'}; - my @roles = - ref $role_node eq "ARRAY" - ? @$role_node - : ($role_node); - for my $role (@roles) { - my @docs = ref $role->{doc} eq "ARRAY" - ? @{ $role->{doc} } - : $role->{doc}; - push @$r, - { - role_name => $role->{roleName}, - count => $role->{count}, - docs => \@docs, - }; - } -} - -$template->param( - content => $r, - unimarc3 => $unimarc3, -); - -output_html_with_http_headers $cgi, $cookie, $template->output; diff --git a/opac/svc/idref b/opac/svc/idref new file mode 100755 index 0000000000..b29cde474f --- /dev/null +++ b/opac/svc/idref @@ -0,0 +1,107 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use CGI; +use LWP::UserAgent; +use JSON qw( from_json to_json ); +use Encode; +use C4::Context; +use C4::Output qw( output_with_http_headers ); +use Search::Elasticsearch; + + +my $cgi = CGI->new; + +# See http://documentation.abes.fr/aideidrefdeveloppeur/index.html#MicroWebBiblio +my $base = 'http://www.idref.fr/services/biblio/'; +my $unimarc3 = $cgi->param('ppn'); + +my $publications = { name => '', ppn => $unimarc3, roles => [] }; +my $send_result = sub { + my $json = to_json($publications); + utf8::encode($json); + output_with_http_headers($cgi, undef, $json, 'json'); + exit; +}; + +my $ua = LWP::UserAgent->new; +my $request = HTTP::Request->new( + 'GET', + $base . $unimarc3 . ".json", +); +$request->protocol('HTTP/1.1'); +my $response = $ua->request($request); +$send_result->() if not $response->is_success; + +my $content = Encode::decode("utf8", $response->content); +my $json = from_json($content); +my $result = $json->{sudoc}->{result}; +$send_result->() if $result->{countRoles} == 0; + +$publications->{name} = $result->{name}; +$result->{role} = [ $result->{role} ] if ref($result->{role}) ne 'ARRAY'; +my $ppn; +for my $r (@{$result->{role}}) { + my $role = { + code => $r->{unimarcCode}, + label => $r->{roleName}, + docs => [], + }; + $r->{doc} = [ $r->{doc} ] if ref $r->{doc} ne 'ARRAY'; + for my $doc ( @{$r->{doc}} ) { + push @{$role->{docs}}, { + ppn => $doc->{ppn}, + citation => $doc->{citation}, + }; + push @$ppn, $doc->{ppn}; + } + push @{$publications->{roles}}, $role; +} + +my $ec = C4::Context->config('elasticsearch'); +my $e = Search::Elasticsearch->new( nodes => $ec->{server} ); +my $query = { + index => $ec->{index_name} . '_biblios', + body => { + _source => ["ppn"], + size => '10000', + query => { terms => { ppn => $ppn } } + } +}; +my $res = $e->search($query); +my $hits = $res->{hits}->{hits}; +my $ppn_to_bib; +for my $hit (@$hits) { + my $ppn = $hit->{_source}->{ppn}->[0]; + $ppn_to_bib->{$ppn} = $hit->{_id}; +} +for my $role (@{$publications->{roles}}) { + my @docs = @{$role->{docs}}; + for my $d (@docs) { + my $bib = $ppn_to_bib->{ $d->{ppn} }; + $d->{bib} = $bib if $bib; + } + my $key = sub { + my $doc = shift; + ($doc->{bib} ? 'a' : 'b') . $doc->{citation}; + }; + @docs = sort { $key->($a) cmp $key->($b) } @docs; + $role->{docs} = \@docs; +} +$send_result->(); -- 2.34.1