Bug 33111: (QA follow-up) Add more context to breadcrumb parts for easier translation
[koha.git] / koha-tmpl / intranet-tmpl / prog / en / modules / admin / identity_providers.tt
1 [% USE raw %]
2 [% USE Asset %]
3 [% USE Branches %]
4 [% USE Categories %]
5 [% SET footerjs = 1 %]
6 [% INCLUDE 'doc-head-open.inc' %]
7 <title>
8     [% IF op == 'add_form' %]
9         New identity provider &rsaquo; [% ELSIF op == 'edit_form' %]
10         Edit identity provider &rsaquo; [% END %]
11
12     Identity providers &rsaquo; Administration &rsaquo; Koha
13 </title>
14 [% INCLUDE 'doc-head-close.inc' %]
15 </head>
16
17 <body id="admin_identity_providers" class="admin">
18 [% INCLUDE 'header.inc' %]
19 [% INCLUDE 'prefs-admin-search.inc' %]
20
21 [% WRAPPER 'sub-header.inc' %]
22     [% WRAPPER breadcrumbs %]
23         [% WRAPPER breadcrumb_item %]
24             <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
25         [% END %]
26
27         [% IF op == 'add_form' %]
28             [% WRAPPER breadcrumb_item %]
29                 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
30             [% END %]
31             [% WRAPPER breadcrumb_item bc_active= 1 %]
32                 <span>New identity provider</span>
33             [% END %]
34
35         [% ELSIF op == 'edit_form' %]
36             [% WRAPPER breadcrumb_item %]
37                 <a href="/cgi-bin/koha/admin/identity_providers.pl">Identity providers</a>
38             [% END %]
39             [% WRAPPER breadcrumb_item bc_active= 1 %]
40                 <span>Edit identity provider</span>
41             [% END %]
42
43         [% ELSE %]
44             [% WRAPPER breadcrumb_item bc_active= 1 %]
45                 <span>Identity providers</span>
46             [% END %]
47         [% END %]
48     [% END #/ WRAPPER breadcrumbs %]
49 [% END #/ WRAPPER sub-header.inc %]
50
51 <div class="main container-fluid">
52     <div class="row">
53         <div class="col-sm-10 col-sm-push-2">
54             <main>
55
56 [% FOREACH m IN messages %]
57     <div class="dialog [% m.type | html %]" id="identity_provider_action_result_dialog">
58         [% SWITCH m.code %]
59         [% CASE 'error_on_update' %]
60             <span>An error occurred trying to open the identity provider for editing. The passed ID is invalid.</span>
61         [% CASE 'error_on_insert' %]
62             <span>An error occurred when adding a new identity provider.</span>
63         [% CASE 'success_on_update' %]
64             <span>Identity provider updated successfully.</span>
65         [% CASE 'success_on_insert' %]
66             <div>Identity provider added successfully.</div>
67             <div>You will need to restart Koha for the provider to work.</div>
68         [% CASE %]
69             <span>[% m.code | html %]</span>
70         [% END %]
71     </div>
72 [% END %]
73
74     <div class="dialog message" id="identity_provider_delete_success" style="display: none;"></div>
75     <div class="dialog alert"   id="identity_provider_delete_error"   style="display: none;"></div>
76
77 [% IF op == 'add_form' %]
78     <h1>New identity provider</h1>
79     <div class="page-section">
80         <form action="/cgi-bin/koha/admin/identity_providers.pl" id="add" name="add" class="validated" method="post">
81             <input type="hidden" name="op" value="add" />
82             <fieldset class="rows">
83                 <legend id="identity_provider_basic">Basic configuration</legend>
84                 <ol>
85                     <li>
86                         <label for="code" class="required">Code: </label>
87                         <input type="text" name="code" id="code" size="60" class="required" required="required" />
88                         <span class="required">Required</span>
89                         <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
90                     </li>
91                     <li>
92                         <label for="description" class="required">Description: </label>
93                         <input type="text" name="description" id="description" size="60" class="required" required="required" />
94                         <span class="required">Required</span>
95                         <div class="hint">User friendly name of this provider</div>
96                     </li>
97                     <li>
98                         <label for="protocol">Protocol: </label>
99                         <select name="protocol" id="protocol">
100                             <option value="OAuth">OAuth</option>
101                             <option value="OIDC">OIDC</option>
102                             <!-- Not implemented yet
103                             <option value="LDAP">LDAP</option>
104                             <option value="CAS">CAS</option>
105                             -->
106                         </select>
107                         <div class="hint">Choose the protocol this external identity provider uses</div>
108                     </li>
109                 </ol>
110             </fieldset>
111
112             <fieldset class="rows">
113                 <legend id="identity_provider_advanced">Advanced configuration</legend>
114                 <ol>
115                     <li>
116                         <label for="config" class="required json">Configuration: </label>
117                         <textarea name="config" id="config" class="required" cols="75" rows="10"></textarea>
118                         <span class="required">Required</span>
119                         <div class="hint">Provider's main configuration. <button class="more btn btn-ligth" data-target="config"><i class="fa fa-caret-down"></i> More</button></div>
120                         <div class="hint more-config" style="display: none">
121                             <div>This configuration differs for each protocol.</div>
122                             <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
123                         </div>
124                         <div class="hint">
125                             <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default OAuth configuration</button>
126                         </div>
127                     </li>
128                     <li>
129                         <label for="mapping" class="required json">Mapping: </label>
130                         <textarea name="mapping" id="mapping" class="required" cols="75" rows="10"></textarea>
131                         <span class="required">Required</span>
132                         <div class="hint">Map provider's result to Koha patron's fields. <button class="more btn btn-ligth" data-target="mapping"><i class="fa fa-caret-down"></i> More</button></div>
133                         <div class="hint more-mapping" style="display: none">
134                             <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
135                             <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
136                             <div>For nested values in provider's results, you can use dot separation.</div>
137                             <div>For example, <i>firstname: "users.0.name"</i> will match the 'name' attribute of the first object in the array named 'users', and place it in 'firstname' field</div>
138                             <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
139                         </div>
140                         <div class="hint">
141                             <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default OAuth mapping</button>
142                         </div>
143                     </li>
144                     <li>
145                         <label for="matchpoint">Matchpoint: </label>
146                         <select name="matchpoint" id="matchpoint">
147                             <option value="email">Email</option>
148                             <option value="userid">User ID</option>
149                             <option value="cardnumber">Card number</option>
150                         </select>
151                         <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
152                         <div class="hint">It must be present in mapping</div>
153                     </li>
154                     <li>
155                         <label for="icon_url">Icon URL: </label>
156                         <input type="text" name="icon_url" id="icon_url" size="60" />
157                     </li>
158                 </ol>
159             </fieldset>
160
161             <fieldset class="rows">
162                 <legend id="identity_provider_domain">Domain configuration</legend>
163                 <ol>
164                     <li>
165                         <label for="domain" class="required">Domain: </label>
166                         <input type="text" name="domain" id="domain" class="required" size="60" />
167                         <span class="required">Required</span>
168                         <div class="hint">Use &ast; for any domain. You can add new domains later on the dedicated admin page.</div>
169                     </li>
170                     <li>
171                         <label for="default_library_id">Default library: </label>
172                         <select id="default_library_id" name="default_library_id" class="mandatory">
173                             [% PROCESS options_for_libraries libraries => Branches.all( unfiltered => 1, do_not_select_my_library => 1 ) %]
174                         </select>
175                         <span class="required">Required</span>
176                         <div class="hint">Use this library for the patron on auto register</div>
177                     </li>
178                     <li>
179                         <label for="default_category_id">Default category: </label>
180                         [% SET categories = Categories.all() %]
181                         <select name="default_category_id" id="default_category_id" class="mandatory">
182                             [% FOREACH category IN categories %]
183                                 <option value="[% category.categorycode | html %]">[% category.description | html %]</option>
184                             [% END %]
185                         </select>
186                         <span class="required">Required</span>
187                         <div class="hint">Use this category for the patron on auto register</div>
188                     </li>
189                     <li>
190                         <label for="allow_opac">Allow OPAC: </label>
191                         <select name="allow_opac" id="allow_opac">
192                             <option value="1">Yes</option>
193                             <option value="0" selected="selected">No</option>
194                         </select>
195                         <div class="hint">Allow OPAC access to users from this domain to login with this identity provider.</div>
196                     </li>
197                     <li>
198                         <label for="allow_opac">Allow staff: </label>
199                         <select name="allow_staff" id="allow_staff">
200                             <option value="1">Yes</option>
201                             <option value="0" selected="selected">No</option>
202                         </select>
203                         <div class="hint">Allow staff access to users from this domain to login with this identity provider.</div>
204                     </li>
205                     <li>
206                         <label for="auto_register">Auto register: </label>
207                         <select name="auto_register" id="auto_register">
208                             <option value="1">Yes</option>
209                             <option value="0" selected="selected">No</option>
210                         </select>
211                         <div class="hint">Allow users to auto register on login.</div>
212                     </li>
213                     <li>
214                         <label for="update_on_auth">Update on login: </label>
215                         <select name="update_on_auth" id="update_on_auth">
216                             <option value="1">Yes</option>
217                             <option value="0" selected="selected">No</option>
218                         </select>
219                         <div class="hint">Update user data on login.</div>
220                 </ol>
221             </fieldset>
222
223             <fieldset class="action">
224                 <input type="submit" value="Submit" />
225                 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
226             </fieldset>
227         </form>
228     </div>
229 [% END %]
230
231 [% IF op == 'edit_form' %]
232     <h1>Edit identity provider</h1>
233     <div class="page-section">
234         <form action="/cgi-bin/koha/admin/identity_providers.pl" id="edit_save" name="edit_save" class="validated" method="post">
235             <input type="hidden" name="op" value="edit_save" />
236             <input type="hidden" name="identity_provider_id" value="[%- identity_provider.identity_provider_id | html -%]" />
237             <fieldset class="rows">
238                 <legend id="identity_provider_basic">Basic configuration</legend>
239                 <ol>
240                     <li>
241                         <label for="code" class="required">Code: </label>
242                         <input type="text" name="code" id="code" size="60" class="required" required="required" value="[%- identity_provider.code | html -%]"/>
243                         <span class="required">Required</span>
244                         <div class="hint">Code that identifies this provider. Only alphanumeric and "_" characters are allowed</div>
245                     </li>
246                     <li>
247                         <label for="description" class="required">Description: </label>
248                         <input type="text" name="description" id="description" size="60" class="required" required="required" value="[%- identity_provider.description | html -%]"/>
249                         <span class="required">Required</span>
250                         <div class="hint">User friendly name of this provider</div>
251                     </li>
252                     <li>
253                         <label for="protocol">Protocol: </label>
254                         <select name="protocol" id="protocol">
255                         [% IF identity_provider.protocol == 'OAuth' %]
256                             <option value="OAuth" selected="selected">OAuth</option>
257                             <option value="OIDC">OIDC</option>
258                             <!-- Not implemented yet
259                             <option value="LDAP">LDAP</option>
260                             <option value="CAS">CAS</option>
261                             -->
262                         [% ELSE %]
263                             <option value="OAuth">OAuth</option>
264                             <option value="OIDC" selected="selected">OIDC</option>
265                             <!-- Not implemented yet
266                             <option value="LDAP">LDAP</option>
267                             <option value="CAS">CAS</option>
268                             -->
269                         [% END %]
270                         </select>
271                         <div class="hint">Choose the protocol this external identity provider uses</div>
272                     </li>
273                 </ol>
274             </fieldset>
275
276             <fieldset class="rows">
277                 <legend id="identity_provider_advanced">Advanced configuration</legend>
278                 <ol>
279                     <li>
280                         <label for="config" class="required json">Configuration: </label>
281                         <textarea name="config" id="config" class="required" cols="75" rows="10">[%- identity_provider.config | html -%]</textarea>
282                         <span class="required">Required</span>
283                         <div class="hint">Provider's main configuration. <button class="more btn btn-ligth" data-target="config"><i class="fa fa-caret-down"></i> More</button></div>
284                         <div class="hint more-config" style="display: none">
285                             <div>This configuration differs for each protocol.</div>
286                             <div>It is recommended to add the default configuration, and then replace with appropriate values</div>
287                         </div>
288                         <div class="hint">
289                             <button class="btn btn-ligth defaults" data-default-target="config" id="default-config">Add default [%- identity_provider.protocol | html -%] configuration</button>
290                         </div>
291                     </li>
292                     <li>
293                         <label for="mapping" class="required json">Mapping: </label>
294                         <textarea name="mapping" id="mapping" class="required" cols="75" rows="10">[%- identity_provider.mapping | html -%]</textarea>
295                         <span class="required">Required</span>
296                         <div class="hint">Map provider's result to Koha patron's fields. <button class="more btn btn-ligth" data-target="mapping"><i class="fa fa-caret-down"></i> More</button></div>
297                         <div class="hint more-mapping" style="display: none">
298                             <div>It is recommended to add the default mapping, and then modify to suit this provider's response</div>
299                             <div>Keys represent Koha's fields, and values represent the keys in provider's result</div>
300                             <div>For nested values in provider's results, you can use dot separation.</div>
301                             <div>For example, <i>firstname: "users.0.name"</i> will match the 'name' attribute of the first object in the array named 'users', and place it in 'firstname' field</div>
302                             <div>If you plan to use auto register feature, either <i>userid</i> or <i>cardnumber</i> must be present in this mapping</div>
303                         </div>
304                         <div class="hint">
305                             <button class="btn btn-ligth defaults" data-default-target="mapping" id="default-mapping">Add default [%- identity_provider.protocol | html -%] mapping</button>
306                         </div>
307                     </li>
308                     <li>
309                         <label for="matchpoint">Matchpoint: </label>
310                         <select name="matchpoint" id="matchpoint">
311                             [%- IF identity_provider.matchpoint == 'email'      -%]
312                                 <option value="email" selected="selected">Email</option>
313                             [%- ELSE -%]
314                                 <option value="email">Email</option>
315                             [%- END -%]
316                             [%- IF identity_provider.matchpoint == 'userid'     -%]
317                                 <option value="userid" selected="selected">User id</option>
318                             [%- ELSE -%]
319                                 <option value="userid">User id</option>
320                             [%- END -%]
321                             [%- IF identity_provider.matchpoint == 'cardnumber' -%]
322                                 <option value="cardnumber" selected="selected">Card number</option>
323                             [%- ELSE -%]
324                                 <option value="cardnumber">Card number</option>
325                             [%- END -%]
326                         </select>
327                         <div class="hint">Koha patron's field that will be used to match provider's user with Koha's</div>
328                         <div class="hint">It must be present in mapping</div>
329                     </li>
330                     <li>
331                         <label for="icon_url">Icon URL: </label>
332                         <input type="text" name="icon_url" id="icon_url" size="60"  value="[%- identity_provider.icon_url | html -%]"/>
333                     </li>
334                 </ol>
335             </fieldset>
336             <fieldset class="action">
337                 <input type="submit" value="Submit" />
338                 <a class="cancel" href="/cgi-bin/koha/admin/identity_providers.pl">Cancel</a>
339             </fieldset>
340         </form>
341     </div>
342 [% END %]
343
344 [% IF op == 'list' %]
345
346     <div id="toolbar" class="btn-toolbar">
347         <a class="btn btn-default" id="new_identity_provider" href="/cgi-bin/koha/admin/identity_providers.pl?op=add_form"><i class="fa fa-plus"></i> New identity provider</a>
348     </div>
349
350     <h1>Identity providers</h1>
351     <div class="page-section">
352         <table id="identity_providers">
353             <thead>
354                 <tr>
355                     <th>Code</th>
356                     <th>Description</th>
357                     <th>Protocol</th>
358                     <th data-class-name="actions noExport">Actions</th>
359                 </tr>
360             </thead>
361         </table>
362     </div>
363 [% END %]
364
365             <div id="delete_confirm_modal" class="modal" tabindex="-1" role="dialog" aria-labelledby="delete_confirm_modal_label" aria-hidden="true">
366                 <div class="modal-dialog">
367                     <div class="modal-content">
368                         <div class="modal-header">
369                             <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button>
370                             <h3 id="delete_confirm_modal_label">Delete identity provider</h3>
371                         </div>
372                         <div class="modal-body">
373                             <div id="delete_confirm_dialog"></div>
374                         </div>
375                         <div class="modal-footer">
376                             <a href="#" class="btn btn-default" id="delete_confirm_modal_button" role="button" data-toggle="modal">Delete</a>
377                             <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
378                         </div>
379                     </div> <!-- /.modal-content -->
380                 </div> <!-- /.modal-dialog -->
381             </div> <!-- #delete_confirm_modal -->
382
383             </main>
384         </div> <!-- /.col-sm-10.col-sm-push-2 -->
385
386         <div class="col-sm-2 col-sm-pull-10">
387             <aside>
388                 [% INCLUDE 'admin-menu.inc' %]
389             </aside>
390         </div> <!-- /.col-sm-2.col-sm-pull-10 -->
391      </div> <!-- /.row -->
392
393
394 [% MACRO jsinclude BLOCK %]
395     [% Asset.js("js/admin-menu.js") | $raw %]
396     [% INCLUDE 'datatables.inc' %]
397     <script>
398         $(document).ready(function() {
399
400             var identity_providers_url = '/api/v1/auth/identity_providers';
401             window.identity_providers = $("#identity_providers").kohaTable({
402                 "ajax": {
403                     "url": identity_providers_url
404                 },
405                 'language': {
406                     'emptyTable': '<div class="dialog message">'+_("There are no identity providers defined.")+'</div>'
407                 },
408                 "columnDefs": [ {
409                     "targets": [0,1,2],
410                     "render": function (data, type, row, meta) {
411                         if ( type == 'display' ) {
412                             if ( data != null ) {
413                                 return data.escapeHtml();
414                             }
415                             else {
416                                 return "Default";
417                             }
418                         }
419                         return data;
420                     }
421                 } ],
422                 "columns": [
423                     {
424                         "data": "code",
425                         "searchable": true,
426                         "orderable": true
427                     },
428                     {
429                         "data": "description",
430                         "searchable": true,
431                         "orderable": true
432                     },
433                     {
434                         "data": "protocol",
435                         "searchable": true,
436                         "orderable": true
437                     },
438                     {
439                         "data": function( row, type, val, meta ) {
440                             var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?op=edit_form&amp;identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
441                             result += '<a class="btn btn-default btn-xs delete_identity_provider" role="button" href="#" data-toggle="modal" data-target="#delete_confirm_modal" data-auth-provider-id="'+ encodeURIComponent(row.identity_provider_id) +'" data-auth-provider-code="'+ encodeURIComponent(row.code.escapeHtml()) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>'+"\n";
442                             result += '<a class="btn btn-default btn-xs edit_domains" role="button" href="/cgi-bin/koha/admin/identity_providers.pl?domain_ops=1&amp;identity_provider_id='+ encodeURIComponent(row.identity_provider_id) +'"><i class="fa fa-cog" aria-hidden="true"></i> '+_("Manage domains")+'</a>';
443                             return result;
444                         },
445                         "searchable": false,
446                         "orderable": false
447                     }
448                 ],
449                 createdRow: function (row, data, dataIndex) {
450                     if ( data.debug ) {
451                         $(row).addClass('debug');
452                     }
453                 },
454             });
455
456             $('#identity_providers').on( "click", '.delete_identity_provider', function () {
457                 var identity_provider_id   = $(this).data('auth-provider-id');
458                 var identity_provider_code = decodeURIComponent($(this).data('auth-provider-code'));
459
460                 $("#delete_confirm_dialog").html(
461                     _("You are about to delete the '%s' identity provider.").format(identity_provider_code)
462                 );
463                 $("#delete_confirm_modal_button").data('auth-provider-id', identity_provider_id);
464                 $("#delete_confirm_modal_button").data('auth-provider-code', identity_provider_code);
465             });
466
467             $("#delete_confirm_modal_button").on( "click", function () {
468
469                 var identity_provider_id   = $(this).data('auth-provider-id');
470                 var identity_provider_code = $(this).data('auth-provider-code');
471
472                 $.ajax({
473                     method: "DELETE",
474                     url: identity_providers_url+"/"+identity_provider_id
475                 }).success(function() {
476                     window.identity_providers.api().ajax.reload(function (data) {
477                         $("#identity_provider_action_result_dialog").hide();
478                         $("#identity_provider_delete_success").html(_("Server '%s' deleted successfully.").format(identity_provider_code)).show();
479                     });
480                 }).fail(function () {
481                     $("#identity_provider_delete_error").html(_("Error deleting server '%s'. Check the logs.").format(identity_provider_code)).show();
482                 }).done(function () {
483                     $("#delete_confirm_modal").modal('hide');
484                 });
485             });
486
487             $.validator.addMethod('json', function(value, element) {
488                 if (this.optional(element) && value === '') return true;
489                 try {
490                     JSON.parse(value)
491                 } catch (error) {
492                     return false;
493                 }
494                 return true;
495             }, _("Not a valid JSON"));
496
497             $.validator.addMethod('alphanum', function(value, element) {
498                 if (this.optional(element) && value === '') return true;
499                 return /^[a-zA-Z0-9_]+$/.test(value);
500             }, _("Value must have alphanumeric characters or '_'"));
501
502             $('#config, #mapping').each(function() {
503                 $(this).rules('add', {
504                     required: true,
505                     json: true
506                 });
507             });
508
509             $('button.more').on('click', function(event) {
510                 event.preventDefault();
511                 var target = $(this).hide().data('target');
512                 $('.more-'+target).show();
513             });
514
515             $('#code').rules('add', {
516                 alphanum: true,
517                 required: true
518             });
519
520             var defaults = {
521                 OIDC: {
522                     config: {
523                         key: "<enter client id>",
524                         secret: "<enter client secret>",
525                         well_known_url: "<enter openid configuration endpoint>",
526                         scope: "openid email"
527                     },
528                     mapping: {
529                         email: "email",
530                         firstname: "given_name",
531                         surname: "family_name"
532                     }
533                 },
534                 OAuth: {
535                     config: {
536                         key: "<enter client id>",
537                         secret: "<enter client secret>",
538                         authorize_url: "<enter authorization endpoint>",
539                         token_url: "<enter token endpoint>",
540                         userinfo_url: "<enter user info endpoint (optional)>",
541                         scope: "email"
542                     },
543                     mapping: {
544                         email: "email",
545                         firstname: "given_name",
546                         surname: "family_name"
547                     }
548                 }
549             };
550
551             $('#protocol').on('change', function() {
552                 var protocol = $(this).val();
553                 $('#default-config').html(_("Add default %s configuration").format(protocol));
554                 $('#default-mapping').html(_("Add default %s mapping").format(protocol));
555             });
556
557             $('button.defaults').on('click', function(event) {
558                 event.preventDefault();
559                 var target = $(this).data('defaultTarget');
560                 if($('#'+target).val() !== '' && !confirm(_("Are you sure you want to replace current %s contents?").format(target))) {
561                     return;
562                 }
563                 var protocol = $('#protocol').val();
564                 $('#'+target).val(JSON.stringify(defaults[protocol][target], null, 2));
565             })
566         });
567     </script>
568 [% END %]
569
570 [% INCLUDE 'intranet-bottom.inc' %]