From 5ea4b68481d1950b1a9c7598f23cb5c2650071a6 Mon Sep 17 00:00:00 2001
From: jeremy breuillard <jeremy.breuillard@biblibre.com>
Date: Mon, 7 Feb 2022 12:00:00 +0100
Subject: [PATCH] Bug 21330: Allow XSLT for authority detail view in OPAC

This patch adds a syspref that allow to customize the authority detail
view in OPAC with XSLT.

Test plan:
1. Make sure to have at least one or more authorities
2. OPAC: Home > Authority search(Submit) > Authority search results
3. Click details on a result and notice the view
4. Apply patch
5. INTRA: Home > Administration > System preferences ->find
   "AuthorityXSLTOpacDetailsDisplay"
6. Write the path where your file is. You can try with the XSLT for
   biblio for instance:
   .../koha/koha-tmpl/opac-tmpl/bootstrap/en/xslt/UNIMARCslim2OPACDetail.xsl
7. Save changes
8. Repeat 2-3 and notice the display

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Thibault <thibault.keromnes@univ-paris8.fr>
---
 .../data/mysql/atomicupdate/bug-21330.pl      |  15 ++
 installer/data/mysql/mandatory/sysprefs.sql   |   1 +
 .../admin/preferences/staff_interface.pref    |   5 +
 .../bootstrap/en/modules/opac-auth-detail.tt  | 156 +++++++++---------
 opac/opac-authoritiesdetail.pl                |  23 ++-
 5 files changed, 122 insertions(+), 78 deletions(-)
 create mode 100644 installer/data/mysql/atomicupdate/bug-21330.pl

diff --git a/installer/data/mysql/atomicupdate/bug-21330.pl b/installer/data/mysql/atomicupdate/bug-21330.pl
new file mode 100644
index 0000000000..fb1f231bf0
--- /dev/null
+++ b/installer/data/mysql/atomicupdate/bug-21330.pl
@@ -0,0 +1,15 @@
+use Modern::Perl;
+
+return {
+    bug_number => '21330',
+    description => 'Add syspref AuthorityXSLTOpacDetailsDisplay',
+    up => sub {
+        my ($args) = @_;
+        my ($dbh, $out) = @$args{qw(dbh out)};
+
+        $dbh->do(q{
+            INSERT IGNORE INTO systempreferences (`variable`, `value`, `options`, `explanation`, `type`)
+            VALUES ('AuthorityXSLTOpacDetailsDisplay','','','Enable XSL stylesheet control over authority results page display on intranet','Free')
+        });
+    },
+};
diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql
index 98eced6bc0..df77f523c4 100644
--- a/installer/data/mysql/mandatory/sysprefs.sql
+++ b/installer/data/mysql/mandatory/sysprefs.sql
@@ -72,6 +72,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
 ('AuthorityMergeLimit','50',NULL,'Maximum number of biblio records updated immediately when an authority record has been modified.','integer'),
 ('AuthorityMergeMode','loose','loose|strict','Authority merge mode','Choice'),
 ('AuthoritySeparator','--','10','Used to separate a list of authorities in a display. Usually --','free'),
+('AuthorityXSLTOpacDetailsDisplay','','','Enable XSL stylesheet control over authority details page in the OPAC','Free'),
 ('AuthorityXSLTOpacResultsDisplay','','','Enable XSL stylesheet control over authority results page in the OPAC','Free'),
 ('AuthorityXSLTResultsDisplay','','','Enable XSL stylesheet control over authority results page display on intranet','Free'),
 ('AuthSuccessLog','0',NULL,'If enabled, log successful authentications','YesNo'),
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref
index 0e5bb27f4c..2952e363dd 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/staff_interface.pref
@@ -1,5 +1,10 @@
 Staff interface:
     Appearance:
+        -
+            - 'Display authority details in the opac interface using XSLT stylesheet at: '
+            - pref: AuthorityXSLTOpacDetailsDisplay
+              class: file
+            - '<br />Options:<ul><li>Put a path to define a xslt file</li><li>Put an URL for an external specific stylesheet.</li></ul>{langcode} will be replaced with current interface language and {authtypecode} will be replaced by the authority type code'
         -
             - 'Display authority results in the staff interface using XSLT stylesheet at: '
             - pref: AuthorityXSLTResultsDisplay
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth-detail.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth-detail.tt
index a84b103784..4711b0f1ac 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth-detail.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-auth-detail.tt
@@ -75,89 +75,93 @@
                             [% IF count %]<a href="/cgi-bin/koha/opac-search.pl?type=opac&amp;q=[% authid | uri %]&amp;idx=an,phr">Number of records used in: [% count | html %]</a>[% ELSE %]This authority is not used in any records.[% END %]
                         </div>
 
-                        <div class="authstanza">
-                            [% FOREACH authorize IN summary.authorized %]
-                                <div class="heading authorized auth[% seefro.field | html %]">
-                                    <span class="label">Preferred form: </span>
-                                    <span class="authorized">[% authorize.heading | html %]</span>
+                        [% IF html %]
+                            [% html | $raw %]
+                        [% ELSE %]
+                            <div class="authstanza">
+                                [% FOREACH authorize IN summary.authorized %]
+                                    <div class="heading authorized auth[% seefro.field | html %]">
+                                        <span class="label">Preferred form: </span>
+                                        <span class="authorized">[% authorize.heading | html %]</span>
+                                    </div>
+                                [% END %]
+                                [% PROCESS otherscript headings=summary.otherscript wantcategory='preferred' %]
+                            </div>
+
+                            [% IF summary.seefrom.size %]
+                                <div class="authstanza seefrom">
+                                    <div class="authstanzaheading">Used for/see from:</div>
+                                    <ul class="seefrom">
+                                        [% FOREACH seefro IN summary.seefrom %]
+                                            <li class="heading seefrom auth[% seefro.field | html %]">
+                                                [% IF seefro.type && seefro.type != 'seefrom' %]
+                                                    <span class="label">[% PROCESS authtypelabel type=seefro.type | trim %]:</span>
+                                                [% END %]
+                                                <span class="seefrom">[% PROCESS authheadingdisplay heading=seefro.heading search=seefrosearch authid=seefro.authid %]</span>
+                                            </li>
+                                        [% END %]
+                                        [% PROCESS otherscript headings=summary.otherscript wantcategory='seefrom' %]
+                                    </ul>
                                 </div>
                             [% END %]
-                            [% PROCESS otherscript headings=summary.otherscript wantcategory='preferred' %]
-                        </div>
 
-                        [% IF summary.seefrom.size %]
-                            <div class="authstanza seefrom">
-                                <div class="authstanzaheading">Used for/see from:</div>
-                                <ul class="seefrom">
-                                    [% FOREACH seefro IN summary.seefrom %]
-                                        <li class="heading seefrom auth[% seefro.field | html %]">
-                                            [% IF seefro.type && seefro.type != 'seefrom' %]
-                                                <span class="label">[% PROCESS authtypelabel type=seefro.type | trim %]:</span>
-                                            [% END %]
-                                            <span class="seefrom">[% PROCESS authheadingdisplay heading=seefro.heading search=seefrosearch authid=seefro.authid %]</span>
-                                        </li>
-                                    [% END %]
-                                    [% PROCESS otherscript headings=summary.otherscript wantcategory='seefrom' %]
-                                </ul>
-                            </div>
-                        [% END %]
+                            [% IF summary.seealso.size %]
+                                <div class="authstanza seealso">
+                                    <div class="authstanzaheading">See also:</div>
+                                    <ul class="seelso">
+                                        [% FOREACH seeals IN summary.seealso %]
+                                            <li class="heading seealso auth[% seeals.field | html %]">
+                                                [% IF seeals.type && seeals.type != 'seealso' %]
+                                                    <span class="label">[% PROCESS authtypelabel type=seeals.type | trim %]:</span>
+                                                [% END %]
+                                                <span class="seealso">[% PROCESS authheadingdisplay heading=seeals.heading search=seeals.search authid=seeals.authid %]</span>
+                                            </li>
+                                        [% END %]
+                                        [% PROCESS otherscript headings=summary.otherscript wantcategory='seealso' %]
+                                    </ul>
+                                </div>
+                            [% END %]
 
-                        [% IF summary.seealso.size %]
-                            <div class="authstanza seealso">
-                                <div class="authstanzaheading">See also:</div>
-                                <ul class="seelso">
-                                    [% FOREACH seeals IN summary.seealso %]
-                                        <li class="heading seealso auth[% seeals.field | html %]">
-                                            [% IF seeals.type && seeals.type != 'seealso' %]
-                                                <span class="label">[% PROCESS authtypelabel type=seeals.type | trim %]:</span>
-                                            [% END %]
-                                            <span class="seealso">[% PROCESS authheadingdisplay heading=seeals.heading search=seeals.search authid=seeals.authid %]</span>
-                                        </li>
-                                    [% END %]
-                                    [% PROCESS otherscript headings=summary.otherscript wantcategory='seealso' %]
-                                </ul>
-                            </div>
-                        [% END %]
+                            [% IF marcflavour == 'UNIMARC' && summary.otherscript %]
+                                <div class="authstanza">
+                                    <div class="authstanzaheading">Other forms:</div>
+                                    <ul>
+                                        [% FOREACH otherscrip IN summary.otherscript %]
+                                            <li>
+                                                [% PROCESS language lang=otherscrip.lang | trim %]:
+                                                <span class="otherscript">[% otherscrip.term | html %]</span>
+                                            </li>
+                                        [% END %]
+                                    </ul>
+                                </div>
+                            [% END %]
 
-                        [% IF marcflavour == 'UNIMARC' && summary.otherscript %]
-                            <div class="authstanza">
-                                <div class="authstanzaheading">Other forms:</div>
-                                <ul>
-                                    [% FOREACH otherscrip IN summary.otherscript %]
-                                        <li>
-                                            [% PROCESS language lang=otherscrip.lang | trim %]:
-                                            <span class="otherscript">[% otherscrip.term | html %]</span>
-                                        </li>
-                                    [% END %]
-                                </ul>
-                            </div>
+                            [% IF ( MARCURLS ) %]
+                                <div class="authstanza online_resources">
+                                    <span class="label">Online resources:</span>
+                                    <ul>
+                                        [% FOREACH MARCurl IN MARCURLS %]
+                                            <li>[% IF ( MARCurl.part ) %][% MARCurl.part | html %]<br />[% END %]
+                                                [% IF ( Koha.Preference('OPACURLOpenInNewWindow') ) %]
+                                                    <a href="[% MARCurl.MARCURL | url %]" title="[% MARCurl.MARCURL | html %]" target="_blank" rel="noreferrer">
+                                                [% ELSE %]
+                                                    <a href="[% MARCurl.MARCURL | url %]" title="[% MARCurl.MARCURL | html %]">
+                                                [% END %]
+                                                [% MARCurl.linktext | html %]</a>
+                                                [% IF ( MARCurl.notes ) %]
+                                                    <ul>
+                                                        [% FOREACH note IN MARCurl.notes %]
+                                                            <li>[% note.note | html %]</li>
+                                                        [% END %]
+                                                    </ul>
+                                                [% END %]
+                                            </li>
+                                        [% END # /FOREACH MARCURLS %]
+                                    </ul>
+                                </div>
+                            [% END # / IF MARCURLS %]
                         [% END %]
 
-                        [% IF ( MARCURLS ) %]
-                            <div class="authstanza online_resources">
-                                <span class="label">Online resources:</span>
-                                <ul>
-                                    [% FOREACH MARCurl IN MARCURLS %]
-                                        <li>[% IF ( MARCurl.part ) %][% MARCurl.part | html %]<br />[% END %]
-                                            [% IF ( Koha.Preference('OPACURLOpenInNewWindow') ) %]
-                                                <a href="[% MARCurl.MARCURL | url %]" title="[% MARCurl.MARCURL | html %]" target="_blank" rel="noreferrer">
-                                            [% ELSE %]
-                                                <a href="[% MARCurl.MARCURL | url %]" title="[% MARCurl.MARCURL | html %]">
-                                            [% END %]
-                                            [% MARCurl.linktext | html %]</a>
-                                            [% IF ( MARCurl.notes ) %]
-                                                <ul>
-                                                    [% FOREACH note IN MARCurl.notes %]
-                                                        <li>[% note.note | html %]</li>
-                                                    [% END %]
-                                                </ul>
-                                            [% END %]
-                                        </li>
-                                    [% END # /FOREACH MARCURLS %]
-                                </ul>
-                            </div>
-                        [% END # / IF MARCURLS %]
-
                         <div id="authdescriptions" class="toptabs">
                             <ul class="nav nav-tabs" role="tablist">
                                 <li id="tab_descriptions" class="nav-item" role="presentation">
diff --git a/opac/opac-authoritiesdetail.pl b/opac/opac-authoritiesdetail.pl
index e6d41f7bd5..26d22f3a43 100755
--- a/opac/opac-authoritiesdetail.pl
+++ b/opac/opac-authoritiesdetail.pl
@@ -41,6 +41,7 @@ use Modern::Perl;
 use C4::Auth qw( get_template_and_user );
 use C4::Biblio qw( GetMarcUrls );
 use C4::Context;
+use C4::Languages;
 use C4::Output qw( output_html_with_http_headers );
 use C4::AuthoritiesMarc qw( GetAuthority BuildSummary GetTagsLabels GenerateHierarchy );
 use CGI qw ( -utf8 );
@@ -48,6 +49,7 @@ use C4::Koha;
 
 use Koha::Authorities;
 use Koha::Authority::Types;
+use Koha::XSLT::Base;
 
 my $query = CGI->new;
 
@@ -166,8 +168,25 @@ if ($show_marc) {
     }
     $template->param( "Tab0XX" => \@loop_data );
 } else {
-    my $summary = BuildSummary($record, $authid, $authtypecode);
-    $template->{VARS}->{'summary'} = $summary;
+    my $AuthorityXSLTOpacDetailsDisplay = C4::Context->preference('AuthorityXSLTOpacDetailsDisplay');
+    if ($AuthorityXSLTOpacDetailsDisplay) {
+        my $lang = C4::Languages::getlanguage();
+
+        my $xsl = $AuthorityXSLTOpacDetailsDisplay;
+
+        $xsl =~ s/\{langcode\}/$lang/g;
+        $xsl =~ s/\{authtypecode\}/$authtypecode/g;
+        my $xslt_engine = Koha::XSLT::Base->new;
+        my $output = $xslt_engine->transform({ xml => $authority->marcxml, file => $xsl });
+        if ($xslt_engine->err) {
+            warn "XSL transformation failed ($xsl): " . $xslt_engine->err;
+            next;
+        }
+        $template->param(html => $output);
+    } else {
+        my $summary = BuildSummary($record, $authid, $authtypecode);
+        $template->param(summary => $summary);
+    }
 
     if ( C4::Context->preference('OPACAuthorIdentifiers') ) {
         my $authority = Koha::Authorities->find($authid);
-- 
2.30.2