@@ -, +, @@ module --- a/admin/searchengine/elasticsearch/mappings.pl +++ a/admin/searchengine/elasticsearch/mappings.pl @@ -0,0 +1,169 @@ +#!/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 C4::Koha; +use C4::Output; +use C4::Auth; + +use Koha::ElasticSearch; +use Koha::SearchMarcMaps; +use Koha::SearchFields; + +my $input = new CGI; +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { template_name => 'admin/searchengine/elasticsearch/mappings.tt', + query => $input, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { superlibrarian => 1 }, # Create a specific permission? + } +); + +my $index = $input->param('index') || 'biblios'; +my $op = $input->param('op') || 'list'; +my @messages; + +my $database = Koha::Database->new(); +my $schema = $database->schema; + +my $marc_type = lc C4::Context->preference('marcflavour'); +my $mappings = Koha::ElasticSearch->new( { index => 'biblios' } )->get_elasticsearch_mappings->{data}->{properties}; + +if ( $op eq 'edit' ) { + my @mapping_id = $input->param('mapping_id'); + my @search_field_label = $input->param('search_field_label'); + my @search_field_id = $input->param('search_field_id'); + my @mapping_marc_field = $input->param('mapping_marc_field'); + my @mapping_facet = $input->param('mapping_facet'); + my @mapping_suggestible = $input->param('mapping_suggestible'); + my @mapping_sort = $input->param('mapping_sort'); + my @index_name = $input->param('index_name'); + + my $everything_went_fine = 1; + $schema->storage->txn_begin; + + my $marc_mappings_to_delete = Koha::SearchMarcMaps->search( { marc_type => $marc_type, } ); + while ( my $marc_mapping = $marc_mappings_to_delete->next ) { + eval { $marc_mapping->delete; }; + if ($@) { + push @messages, { + type => 'error', + code => 'error_on_delete', + values => { + field_name => $marc_mapping->search_field->name, + marc_field => $marc_mapping->marc_field, + }, + message => $@ + }; + $everything_went_fine = 1; + } + } + + my %already_updated_labels; + for my $i ( 0 .. scalar(@mapping_id) - 1 ) { + my $mapping_id = $mapping_id[$i]; + my $search_field_label = $search_field_label[$i]; + my $search_field_id = $search_field_id[$i]; + my $mapping_marc_field = $mapping_marc_field[$i]; + my $mapping_facet = $mapping_facet[$i]; + my $mapping_suggestible = $mapping_suggestible[$i]; + my $mapping_sort = $mapping_sort[$i]; + my $index_name = $index_name[$i]; + + # If not mapping defined, don't insert + next unless $mapping_marc_field; + + # TODO Check mapping format + $mapping_sort = undef if $mapping_sort eq 'undef'; + my $marc_mapping = Koha::SearchMarcMap->new( + { index_name => $index_name, + marc_type => $marc_type, + marc_field => $mapping_marc_field, + facet => $mapping_facet, + suggestible => $mapping_suggestible, + sort => $mapping_sort, + } + ); + + my $search_field = Koha::SearchFields->find($search_field_id); + eval { + $marc_mapping->store; + $marc_mapping->add_to_search_fields( { id => $search_field_id } ); + + # This is a bit awkward... + # There is only 1 label for a given search_field, but the interface let the user changes it row by row. + # So for a given search_field, several labels could be defined. + # Here we assign the label if at least 1 has changed, and keep only the first modified. + if ( $search_field->label ne $search_field_label ) { + unless ( exists $already_updated_labels{$search_field_id} ) { + $already_updated_labels{$search_field_id} = $search_field_label; + $search_field->label($search_field_label); + $search_field->store; + } + } + }; + + if ($@) { + $everything_went_fine = 0; + push @messages, { + type => 'error', + code => 'error_on_insert', + values => { + field_name => $search_field->name, + marc_field => $mapping_marc_field, + }, + message => $@ + }; + } + } + if ($everything_went_fine) { + push @messages, { type => 'message', code => 'success_on_update' }; + $schema->storage->txn_commit; + } else { + $schema->storage->txn_rollback; + } +} + +my @indexes; +for my $index_name (qw| biblios authorities |) { + my @search_fields; + my $search_fields = $schema->resultset('SearchField')->search; + while ( my $search_field = $search_fields->next ) { + my @mappings = $search_field->search_marc_maps->search( { index_name => $index_name, marc_type => $marc_type } )->all; + next unless @mappings; + push @search_fields, + { id => $search_field->id, + name => $search_field->name, + type => $search_field->type, + label => $search_field->label, + mappings => \@mappings, + }; + } + push @indexes, { index_name => $index_name, search_fields => \@search_fields }; +} + +my $search_fields = $schema->resultset('SearchField')->search; +my @all_search_fields = $search_fields->search( {}, { order_by => ['name'] } ); +$template->param( + indexes => \@indexes, + all_search_fields => \@all_search_fields, + messages => \@messages, +); + +output_html_with_http_headers $input, $cookie, $template->output; --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/elasticsearch/mappings.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/elasticsearch/mappings.tt @@ -0,0 +1,262 @@ +[% INCLUDE 'doc-head-open.inc' %] +Koha › Administration › Elastic Search mappings +[% INCLUDE 'doc-head-close.inc' %] + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
+ +
+
+
+ + [% FOR m IN messages %] +
+ [% SWITCH m.code %] + [% CASE 'error_on_insert' %] + An error occurred when inserting a mapping. + (search field [% m.values.field_name %] with mapping [% m.values.marc_field %].) + [% CASE 'error_on_delete' %] + An error occurred when deleting the existing mappings. Nothing has been changed! + (search field [% m.values.field_name %] with mapping [% m.values.marc_field %].) + [% CASE 'success_on_update' %] + Mapping updated successfully. + [% CASE %] + [% m.code %] + [% END %] +
+ [% END %] + +

Search engine configuration

+
+ Warning: Any modification in these configurations will need a total reindexation to be fully taken into account ! +
+ [% IF errors %] +
+ Errors occurred, Modifications does not apply. Please check following values: +
    + [% FOREACH e IN errors %] +
  • + [% IF ( e.type == "malformed_mapping" ) %] + The value "[% e.value %]" is not supported for mappings + [% ELSIF ( e.type == "no_mapping" ) %] + There is no mapping for the index [% e.value %] + [% END %] +
  • + [% END %] +
+
+ [% END %] + +
+ + [% FOREACH index IN indexes %] + [% SWITCH index.index_name %] + [% CASE 'biblios' %]

Biblios

+ [% CASE 'authorities' %]

Authorities

+ [% CASE %]

[% index.index_name %]

+ [% END %] + + + + + + + + + + + + + + [% FOREACH search_field IN index.search_fields %] + [% FOREACH mapping IN search_field.mappings %] + + + + + + + + + + [% END %] + [% END %] + + + + + + + + + + + + +
Search fieldLabelSortableFacetableSuggestibleMapping
+ + + + + + + + + + Delete
+ + + + + + + Add
+ [% END %] +

+
+
+ +
+
+[% INCLUDE 'admin-menu.inc' %] +
+
+[% INCLUDE 'intranet-bottom.inc' %] --