View | Details | Raw Unified | Return to bug 14899
Collapse All | Expand All

(-)a/admin/searchengine/elasticsearch/mappings.pl (+169 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
use CGI;
20
use C4::Koha;
21
use C4::Output;
22
use C4::Auth;
23
24
use Koha::ElasticSearch;
25
use Koha::SearchMarcMaps;
26
use Koha::SearchFields;
27
28
my $input = new CGI;
29
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
30
    {   template_name   => 'admin/searchengine/elasticsearch/mappings.tt',
31
        query           => $input,
32
        type            => 'intranet',
33
        authnotrequired => 0,
34
        flagsrequired   => { superlibrarian => 1 },                          # Create a specific permission?
35
    }
36
);
37
38
my $index = $input->param('index') || 'biblios';
39
my $op    = $input->param('op')    || 'list';
40
my @messages;
41
42
my $database = Koha::Database->new();
43
my $schema   = $database->schema;
44
45
my $marc_type = lc C4::Context->preference('marcflavour');
46
my $mappings = Koha::ElasticSearch->new( { index => 'biblios' } )->get_elasticsearch_mappings->{data}->{properties};
47
48
if ( $op eq 'edit' ) {
49
    my @mapping_id          = $input->param('mapping_id');
50
    my @search_field_label  = $input->param('search_field_label');
51
    my @search_field_id     = $input->param('search_field_id');
52
    my @mapping_marc_field  = $input->param('mapping_marc_field');
53
    my @mapping_facet       = $input->param('mapping_facet');
54
    my @mapping_suggestible = $input->param('mapping_suggestible');
55
    my @mapping_sort        = $input->param('mapping_sort');
56
    my @index_name          = $input->param('index_name');
57
58
    my $everything_went_fine = 1;
59
    $schema->storage->txn_begin;
60
61
    my $marc_mappings_to_delete = Koha::SearchMarcMaps->search( { marc_type => $marc_type, } );
62
    while ( my $marc_mapping = $marc_mappings_to_delete->next ) {
63
        eval { $marc_mapping->delete; };
64
        if ($@) {
65
            push @messages, {
66
                type => 'error',
67
                code => 'error_on_delete',
68
                values => {
69
                    field_name => $marc_mapping->search_field->name,
70
                    marc_field => $marc_mapping->marc_field,
71
                },
72
                message => $@
73
            };
74
            $everything_went_fine = 1;
75
        }
76
    }
77
78
    my %already_updated_labels;
79
    for my $i ( 0 .. scalar(@mapping_id) - 1 ) {
80
        my $mapping_id          = $mapping_id[$i];
81
        my $search_field_label  = $search_field_label[$i];
82
        my $search_field_id     = $search_field_id[$i];
83
        my $mapping_marc_field  = $mapping_marc_field[$i];
84
        my $mapping_facet       = $mapping_facet[$i];
85
        my $mapping_suggestible = $mapping_suggestible[$i];
86
        my $mapping_sort        = $mapping_sort[$i];
87
        my $index_name          = $index_name[$i];
88
89
        # If not mapping defined, don't insert
90
        next unless $mapping_marc_field;
91
92
        # TODO Check mapping format
93
        $mapping_sort = undef if $mapping_sort eq 'undef';
94
        my $marc_mapping = Koha::SearchMarcMap->new(
95
            {   index_name  => $index_name,
96
                marc_type   => $marc_type,
97
                marc_field  => $mapping_marc_field,
98
                facet       => $mapping_facet,
99
                suggestible => $mapping_suggestible,
100
                sort        => $mapping_sort,
101
            }
102
        );
103
104
        my $search_field = Koha::SearchFields->find($search_field_id);
105
        eval {
106
            $marc_mapping->store;
107
            $marc_mapping->add_to_search_fields( { id => $search_field_id } );
108
109
            # This is a bit awkward...
110
            # There is only 1 label for a given search_field, but the interface let the user changes it row by row.
111
            # So for a given search_field, several labels could be defined.
112
            # Here we assign the label if at least 1 has changed, and keep only the first modified.
113
            if ( $search_field->label ne $search_field_label ) {
114
                unless ( exists $already_updated_labels{$search_field_id} ) {
115
                    $already_updated_labels{$search_field_id} = $search_field_label;
116
                    $search_field->label($search_field_label);
117
                    $search_field->store;
118
                }
119
            }
120
        };
121
122
        if ($@) {
123
            $everything_went_fine = 0;
124
            push @messages, {
125
                type => 'error',
126
                code => 'error_on_insert',
127
                values => {
128
                    field_name => $search_field->name,
129
                    marc_field => $mapping_marc_field,
130
                },
131
                message => $@
132
            };
133
        }
134
    }
135
    if ($everything_went_fine) {
136
        push @messages, { type => 'message', code => 'success_on_update' };
137
        $schema->storage->txn_commit;
138
    } else {
139
        $schema->storage->txn_rollback;
140
    }
141
}
142
143
my @indexes;
144
for my $index_name (qw| biblios authorities |) {
145
    my @search_fields;
146
    my $search_fields = $schema->resultset('SearchField')->search;
147
    while ( my $search_field = $search_fields->next ) {
148
        my @mappings = $search_field->search_marc_maps->search( { index_name => $index_name, marc_type => $marc_type } )->all;
149
        next unless @mappings;
150
        push @search_fields,
151
          { id       => $search_field->id,
152
            name     => $search_field->name,
153
            type     => $search_field->type,
154
            label    => $search_field->label,
155
            mappings => \@mappings,
156
          };
157
    }
158
    push @indexes, { index_name => $index_name, search_fields => \@search_fields };
159
}
160
161
my $search_fields = $schema->resultset('SearchField')->search;
162
my @all_search_fields = $search_fields->search( {}, { order_by => ['name'] } );
163
$template->param(
164
    indexes           => \@indexes,
165
    all_search_fields => \@all_search_fields,
166
    messages          => \@messages,
167
);
168
169
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/searchengine/elasticsearch/mappings.tt (-1 / +262 lines)
Line 0 Link Here
0
- 
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Administration &rsaquo; Elastic Search mappings</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.tablednd.js"></script>
5
<script type="text/javascript">
6
    function clean_line( line ) {
7
        $(line).find('input[type="text"]').val("");
8
        $(line).find('select').find('option:first').attr("selected", "selected");
9
    }
10
11
    function clone_line( line ) {
12
        var new_line = $(line).clone();
13
        $(new_line).removeClass("nodrag nodrop");
14
        $(new_line).find('td:last-child>a').removeClass("add").addClass("delete").html(_("Delete"));
15
        $(new_line).find('[data-id]').each( function() {
16
            $(this).attr({ name: $(this).attr('data-id') }).removeAttr('data-id');
17
        } );
18
        $(new_line).find("select").each( function() {
19
            var attr = $(this).attr('name');
20
            var val = $(line).find('[data-id="' + attr + '"]').val();
21
            $(this).find('option[value="' + val + '"]').attr("selected", "selected");
22
        } );
23
        return new_line;
24
    }
25
26
    $(document).ready(function() {
27
        $('.delete').click(function() {
28
            $(this).parents('tr').remove();
29
        });
30
31
        $("table.mappings").tableDnD( {
32
            onDragClass: "dragClass",
33
        } );
34
        $('.add').click(function() {
35
            var table = $(this).closest('table');
36
            var index_name   = $(table).attr('data-index_name');
37
            var line = $(this).closest("tr");
38
            var label        = $(line).find('input[data-id="search_field_label"]').val();
39
            var marc_field = $(line).find('input[data-id="mapping_marc_field"]').val();
40
            if ( marc_field.length > 0 && label.length > 0 ) {
41
                var new_line = clone_line( line );
42
                //$(new_line).find('input[data-id="mapping_marc_field"]').val(marc_field);
43
                new_line.appendTo($('table[data-index_name="'+index_name+'"]>tbody'));
44
                $('.delete').click(function() {
45
                    $(this).parents('tr').remove();
46
                });
47
                clean_line(line);
48
49
                $(table).tableDnD( {
50
                    onDragClass: "dragClass",
51
                } );
52
            }
53
        });
54
    });
55
</script>
56
</head>
57
<body id="admin_searchengine_mappings" class="admin">
58
[% INCLUDE 'header.inc' %]
59
[% INCLUDE 'cat-search.inc' %]
60
61
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; Search engine configuration</div>
62
63
<div id="doc3" class="yui-t1">
64
65
  <div id="bd">
66
    <div id="yui-main">
67
    <div class="yui-b">
68
69
    [% FOR m IN messages %]
70
      <div class="dialog [% m.type %]">
71
        [% SWITCH m.code %]
72
        [% CASE 'error_on_insert' %]
73
          An error occurred when inserting a mapping.
74
          (search field [% m.values.field_name %] with mapping [% m.values.marc_field %].)
75
        [% CASE 'error_on_delete' %]
76
          An error occurred when deleting the existing mappings. Nothing has been changed!
77
          (search field [% m.values.field_name %] with mapping [% m.values.marc_field %].)
78
        [% CASE 'success_on_update' %]
79
          Mapping updated successfully.
80
        [% CASE %]
81
          [% m.code %]
82
        [% END %]
83
      </div>
84
    [% END %]
85
86
    <h1>Search engine configuration</h1>
87
    <div class="warning">
88
        Warning: Any modification in these configurations will need a total reindexation to be fully taken into account !
89
    </div>
90
    [% IF errors %]
91
        <div class="error">
92
        Errors occurred, Modifications does not apply. Please check following values:
93
          <ul>
94
            [% FOREACH e IN errors %]
95
                <li>
96
                    [% IF ( e.type == "malformed_mapping" ) %]
97
                        The value "[% e.value %]" is not supported for mappings
98
                    [% ELSIF ( e.type == "no_mapping" ) %]
99
                        There is no mapping for the index [% e.value %]
100
                    [% END %]
101
                </li>
102
            [% END %]
103
          </ul>
104
        </div>
105
    [% END %]
106
107
    <form method="post">
108
      <input type="hidden" name="op" value="edit" />
109
      [% FOREACH index IN indexes %]
110
        [% SWITCH index.index_name %]
111
            [% CASE 'biblios' %]<h2>Biblios</h2>
112
            [% CASE 'authorities' %]<h2>Authorities</h2>
113
            [% CASE %]<h2>[% index.index_name %]</h2>
114
        [% END %]
115
        <table class="mappings" data-index_name="[% index.index_name%]">
116
          <thead>
117
            <tr class="nodrag nodrop">
118
              <th>Search field</th>
119
              <th>Label</th>
120
              <th>Sortable</th>
121
              <th>Facetable</th>
122
              <th>Suggestible</th>
123
              <th>Mapping</th>
124
              <th></th>
125
            </tr>
126
          </thead>
127
          <tbody>
128
            [% FOREACH search_field IN index.search_fields %]
129
              [% FOREACH mapping IN search_field.mappings %]
130
                <tr>
131
                  <td>
132
                    <input name="index_name" type="hidden" value="[% index.index_name %]" />
133
                    <input name="mapping_id" type="hidden" value="[% mapping.id %]" />
134
                    <select name="search_field_id">
135
                      [% FOREACH f IN all_search_fields %]
136
                        [% IF search_field.id == f.id %]
137
                          <option value="[% f.id %]" selected="selected">[% f.name %][% IF f.type %] ([% f.type %])[% END %]</option>
138
                        [% ELSE %]
139
                          <option value="[% f.id %]">[% f.name %][% IF f.type %] ([% f.type %])[% END %]</option>
140
                        [% END %]
141
                      [% END %]
142
                    </select>
143
                  </td>
144
                  <td><input name="search_field_label" type="text" maxlength="255" value="[% search_field.label %]" /></td>
145
                  <td>
146
                    <select name="mapping_sort">
147
                      [% IF mapping.sort.length == 0 %]
148
                        <option value="undef" selected="selected">Undef</option>
149
                      [% ELSE %]
150
                        <option value="undef">Undef</option>
151
                      [% END %]
152
                      [% IF mapping.sort == 0 %]
153
                        <option value="0" selected="selected">0</option>
154
                      [% ELSE %]
155
                        <option value="0">0</option>
156
                      [% END %]
157
                      [% IF mapping.sort == 1 %]
158
                        <option value="1" selected="selected">1</option>
159
                      [% ELSE %]
160
                        <option value="1">1</option>
161
                      [% END %]
162
                    </select>
163
                  </td>
164
                  <td>
165
                    <select name="mapping_facet">
166
                      [% IF mapping.facet %]
167
                        <option value="0">No</option>
168
                        <option value="1" selected="selected">Yes</option>
169
                      [% ELSE %]
170
                        <option value="0" selected="selected">No</option>
171
                        <option value="1">Yes</option>
172
                      [% END %]
173
                    </selected>
174
                  </td>
175
                  <td>
176
                    <select name="mapping_suggestible">
177
                      [% IF mapping.suggestible %]
178
                        <option value="0">No</option>
179
                        <option value="1" selected="selected">Yes</option>
180
                      [% ELSE %]
181
                        <option value="0" selected="selected">No</option>
182
                        <option value="1">Yes</option>
183
                      [% END %]
184
                    </selected>
185
                  </td>
186
                  <td>
187
                      <input name="mapping_marc_field" type="text" value="[% mapping.marc_field %]" />
188
                  </td>
189
                  <td><a class="delete">Delete</a></td>
190
                </tr>
191
              [% END %]
192
            [% END %]
193
          </tbody>
194
          <tfoot>
195
            <tr class="nodrag nodrop">
196
              <td>
197
                <input data-id="mapping_id" type="hidden" value="" />
198
                <input data-id="index_name" type="hidden" value="[% index.index_name %]" />
199
                <select data-id="search_field_id">
200
                 [% FOREACH f IN all_search_fields %]
201
                   <option value="[% f.id %]">[% f.name %]</option>
202
                 [% END %]
203
                /select>
204
              </td>
205
              <td><input data-id="search_field_label" type="text" maxlength="25" /></td>
206
              <td>
207
                <select data-id="mapping_sort">
208
                  [% IF mapping.sort.length == 0 %]
209
                    <option value="undef" selected="selected">Undef</option>
210
                  [% ELSE %]
211
                    <option value="undef">Undef</option>
212
                  [% END %]
213
                  [% IF mapping.sort == 0 %]
214
                    <option value="0" selected="selected">0</option>
215
                  [% ELSE %]
216
                    <option value="0">0</option>
217
                  [% END %]
218
                  [% IF mapping.sort == 1 %]
219
                    <option value="1" selected="selected">1</option>
220
                  [% ELSE %]
221
                    <option value="1">1</option>
222
                  [% END %]
223
                </select>
224
              </td>
225
              <td>
226
                <select data-id="mapping_facet">
227
                  [% IF mapping.facet %]
228
                    <option value="0">No</option>
229
                    <option value="1" selected="selected">Yes</option>
230
                  [% ELSE %]
231
                    <option value="0" selected="selected">No</option>
232
                    <option value="1">Yes</option>
233
                  [% END %]
234
                </selected>
235
              </td>
236
              <td>
237
                <select data-id="mapping_suggestible">
238
                  [% IF mapping.suggestible %]
239
                    <option value="0">No</option>
240
                    <option value="1" selected="selected">Yes</option>
241
                  [% ELSE %]
242
                    <option value="0" selected="selected">No</option>
243
                    <option value="1">Yes</option>
244
                  [% END %]
245
                </selected>
246
              </td>
247
              <td><input data-id="mapping_marc_field" type="text" /></td>
248
              <td><a class="add">Add</a></td>
249
            </tr>
250
          </tfoot>
251
        </table>
252
      [% END %]
253
      <p><input type="submit" value="Save" /></p>
254
    </form>
255
</div>
256
257
</div>
258
<div class="yui-b">
259
[% INCLUDE 'admin-menu.inc' %]
260
</div>
261
</div>
262
[% INCLUDE 'intranet-bottom.inc' %]

Return to bug 14899