瀏覽代碼

Bug 19482: Add support for defining 'mandatory' mappings

To test:
1 - Apply patch
2 - ./installer/data/mysql/updatedatabase.pl
3 - Reset ES mapping: Administration->Search engine configuration , button at bottom of page
4 - 'issues' and 'title' mapping under 'search fields' should be mandatory and not editable
5 - On 'Bibliographic records' tab you should not be able to delete the single entry for issues
6 - You should be able to delete 'title' mappings, however, at the final one you should be stopped by javascript
7 - Bonus: force remove the last mapping from the page using developer tools - attempt to save and should be warned of missing mandatory mapping

Signed-off-by: Nicolas Legrand <nicolas.legrand@bulac.fr>
Signed-off-by: Bouzid Fergani <bouzid.fergani@inlibro.com>

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
20.11.x
Nick Clemens 7 年之前
committed by Jonathan Druart
父節點
當前提交
975e06bd7c
  1. 2
      Koha/SearchEngine/Elasticsearch.pm
  2. 9
      admin/searchengine/elasticsearch/mappings.pl
  3. 2
      admin/searchengine/elasticsearch/mappings.yaml
  4. 267
      koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/elasticsearch/mappings.tt

2
Koha/SearchEngine/Elasticsearch.pm

@ -353,7 +353,7 @@ sub reset_elasticsearch_mappings {
while ( my ( $index_name, $fields ) = each %$indexes ) {
while ( my ( $field_name, $data ) = each %$fields ) {
my %sf_params = map { $_ => $data->{$_} } grep { exists $data->{$_} } qw/ type label weight staff_client opac facet_order /;
my %sf_params = map { $_ => $data->{$_} } grep { exists $data->{$_} } qw/ type label weight staff_client opac facet_order mandatory/;
# Set default values
$sf_params{staff_client} //= 1;

9
admin/searchengine/elasticsearch/mappings.pl

@ -132,6 +132,9 @@ if ( $op eq 'edit' ) {
my @facetable_fields = Koha::SearchEngine::Elasticsearch->get_facetable_fields();
my @facetable_field_names = map { $_->name } @facetable_fields;
my $mandatory_before = Koha::SearchFields->search({mandatory=>1})->count;
my $mandatory_after = 0;
my %seen_fields;
for my $i ( 0 .. scalar(@index_name) - 1 ) {
my $index_name = $index_name[$i];
my $search_field_name = $search_field_name[$i];
@ -143,6 +146,8 @@ if ( $op eq 'edit' ) {
my $mapping_search = $mapping_search[$i];
my $search_field = Koha::SearchFields->find({ name => $search_field_name }, { key => 'name' });
$mandatory_after++ if $search_field->mandatory && !defined $seen_fields{$search_field_name};
$seen_fields{$search_field_name} = 1;
# TODO Check mapping format
my $marc_field = Koha::SearchMarcMaps->find_or_create({
index_name => $index_name,
@ -156,8 +161,9 @@ if ( $op eq 'edit' ) {
search => $mapping_search
});
}
push @messages, { type => 'error', code => 'missing_mandatory_fields' } if $mandatory_after < $mandatory_before;
};
if ($@) {
if ($@ || @messages) {
push @messages, { type => 'error', code => 'error_on_update', message => $@, };
$schema->storage->txn_rollback;
} else {
@ -236,6 +242,7 @@ for my $index_name (@index_names) {
search_field_name => $name,
search_field_label => $s->label,
search_field_type => $s->type,
search_field_mandatory => $s->mandatory,
marc_field => $s->get_column('marc_field'),
sort => $s->get_column('sort') // 'undef', # To avoid warnings "Use of uninitialized value in lc"
suggestible => $s->get_column('suggestible'),

2
admin/searchengine/elasticsearch/mappings.yaml

@ -2209,6 +2209,7 @@ biblios:
sort: 1
suggestible: ''
type: sum
mandatory: 1
itemnumber:
label: itemnumber
mappings:
@ -4182,6 +4183,7 @@ biblios:
sort: ~
suggestible: ''
type: string
mandatory: 1
title-abbreviated:
label: title-abbreviated
mappings:

267
koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/elasticsearch/mappings.tt

@ -29,7 +29,12 @@
$(document).ready(function() {
$("#tabs").tabs();
$('.delete').click(function() {
$(this).parents('tr').remove();
if( $(this).hasClass('mandatory') && $(".mandatory[data-field_name="+$(this).attr('data-field_name')+"]").length < 2 ){
alert("This field is mandatory and must have at least one mapping");
return;
} else {
$(this).parents('tr').remove();
}
});
$("table.mappings").tableDnD( {
@ -87,6 +92,8 @@ a.add, a.delete {
[% tx("(search field {field_name} with mapping {marc_field}.)", { field_name = m.values.field_name, marc_field = m.values.marc_field }) | html %]
[% CASE 'invalid_field_weight' %]
[% tx("Invalid field weight '{weight}', must be a positive decimal number.", { weight = m.weight }) | html %]
[% CASE 'missing_mandatory_fields' %]
[% t("You attempted to delete all mappings for a required index, you must leave at least one mapping") | $raw %]
[% CASE 'error_on_update_es_mappings' %]
[% tx("An error occurred when updating Elasticsearch index mappings: {message}.", { message = m.message }) | html %]
[% CASE 'reindex_required' %]
@ -176,57 +183,66 @@ a.add, a.delete {
</thead>
<tbody>
[% FOREACH search_field IN all_search_fields %]
[% IF search_field.mandatory %]
[% SET is_readonly = "readonly" %]
[% ELSE %]
[% SET is_readonly = "" %]
[% END %]
<tr>
<td>
<input type="text" name="search_field_name" value="[% search_field.name | html %]" />
<input type="text" name="search_field_name" value="[% search_field.name | html %]" [% is_readonly %]/>
</td>
<td>
<input type="text" name="search_field_label" value="[% search_field.label | html %]" />
</td>
<input type="text" name="search_field_label" value="[% search_field.label | html %]" [% is_readonly %]/>
<td>
<select name="search_field_type">
<option value=""></option>
[% IF search_field.type == "string" %]
<option value="string" selected="selected">String</option>
[% ELSE %]
<option value="string">String</option>
[% END %]
[% IF search_field.type == "date" %]
<option value="date" selected="selected">Date</option>
[% ELSE %]
<option value="date">Date</option>
[% END %]
[% IF search_field.type == "year" %]
<option value="year" selected="selected">Year</option>
[% ELSE %]
<option value="year">Year</option>
[% END %]
[% IF search_field.type == "number" %]
<option value="number" selected="selected">Number</option>
[% ELSE %]
<option value="number">Number</option>
[% END %]
[% IF search_field.type == "boolean" %]
<option value="boolean" selected="selected">Boolean</option>
[% ELSE %]
<option value="boolean">Boolean</option>
[% END %]
[% IF search_field.type == "sum" %]
<option value="sum" selected="selected">Sum</option>
[% ELSE %]
<option value="sum">Sum</option>
[% END %]
[% IF search_field.type == "isbn" %]
<option value="isbn" selected="selected">ISBN</option>
[% ELSE %]
<option value="isbn">ISBN</option>
[% END %]
[% IF search_field.type == "stdno" %]
<option value="stdno" selected="selected">Std. Number</option>
[% ELSE %]
<option value="stdno">Std. Number</option>
[% END %]
</select>
[% IF is_readonly %]
<input type="hidden" name="search_field_type" value="[% search_field.type | html %]" />
<select name="search_field_type" disabled>
[% ELSE %]
<select name="search_field_type">
<option value=""></option>
[% IF search_field.type == "string" %]
<option value="string" selected="selected">String</option>
[% ELSE %]
<option value="string">String</option>
[% END %]
[% IF search_field.type == "date" %]
<option value="date" selected="selected">Date</option>
[% ELSE %]
<option value="date">Date</option>
[% END %]
[% IF search_field.type == "year" %]
<option value="year" selected="selected">Year</option>
[% ELSE %]
<option value="year">Year</option>
[% END %]
[% IF search_field.type == "number" %]
<option value="number" selected="selected">Number</option>
[% ELSE %]
<option value="number">Number</option>
[% END %]
[% IF search_field.type == "boolean" %]
<option value="boolean" selected="selected">Boolean</option>
[% ELSE %]
<option value="boolean">Boolean</option>
[% END %]
[% IF search_field.type == "sum" %]
<option value="sum" selected="selected">Sum</option>
[% ELSE %]
<option value="sum">Sum</option>
[% END %]
[% IF search_field.type == "isbn" %]
<option value="isbn" selected="selected">ISBN</option>
[% ELSE %]
<option value="isbn">ISBN</option>
[% END %]
[% IF search_field.type == "stdno" %]
<option value="stdno" selected="selected">Std. Number</option>
[% ELSE %]
<option value="stdno">Std. Number</option>
[% END %]
</select>
[% END %]
</td>
<td>
<select name="search_field_staff_client">
@ -278,74 +294,103 @@ a.add, a.delete {
</thead>
<tbody>
[% FOREACH mapping IN index.mappings %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
<select name="mapping_sort">
[% IF mapping.sort == 'undef' %]
<option value="undef" selected="selected">Undef</option>
[% ELSE %]
<option value="undef">Undef</option>
[% END %]
[% IF mapping.sort == 0 %]
<option value="0" selected="selected">0</option>
[% ELSE %]
<option value="0">0</option>
[% END %]
[% IF mapping.sort == 1 %]
<option value="1" selected="selected">1</option>
[% ELSE %]
<option value="1">1</option>
[% END %]
</select>
</td>
<td>
[% IF mapping.is_facetable %]
<select name="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% IF mapping.search_field_mandatory && mapping.search_field_label != loop.next.search_field_label && mapping.search_field_label != loop.prev.search_field_label %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
<input type="hidden" name="mapping_sort" value="[% mapping.sort | html %]" readonly />[% IF mapping.sort == 'undef' %]Undef[% ELSE %][% mapping.sort | html %][% END %]
</td>
<td>
<input type="hidden" name="mapping_facet" value="[% mapping.facet | html %]" readonly />[% IF mapping.facet == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_suggestible" value="[% mapping.suggestible | html %]" readonly />[% IF mapping.suggestible == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_search" value="[% mapping.search | html %]" readonly />[% IF mapping.search == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
</tr>
[% ELSE %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
<select name="mapping_sort">
[% IF mapping.sort == 'undef' %]
<option value="undef" selected="selected">Undef</option>
[% ELSE %]
<option value="undef">Undef</option>
[% END %]
[% IF mapping.sort == 0 %]
<option value="0" selected="selected">0</option>
[% ELSE %]
<option value="0">0</option>
[% END %]
[% IF mapping.sort == 1 %]
<option value="1" selected="selected">1</option>
[% ELSE %]
<option value="1">1</option>
[% END %]
</select>
</td>
<td>
[% IF mapping.is_facetable %]
<select name="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
<input type="hidden" name="mapping_facet" value="0" />
No
[% END %]
</select>
[% ELSE %]
<input type="hidden" name="mapping_facet" value="0" />
No
[% END %]
</td>
<td>
<select name="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select name="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
</td>
<td>
<select name="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select name="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
[% IF mapping.search_field_mandatory %]
<td><a class="btn btn-default btn-xs delete mandatory" data-field_name="[% mapping.search_field_name %]" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
<td><a class="btn btn-default btn-xs delete" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
[% END %]
</select>
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
<td><a class="btn btn-default btn-xs delete" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
</tr>
</tr>
[% END %]
[% END %]
</tbody>
<tfoot>

Loading…
取消
儲存