summaryrefslogtreecommitdiffstats
path: root/install/ui/src
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2012-11-26 14:28:32 +0100
committerPetr Vobornik <pvoborni@redhat.com>2013-01-18 15:10:36 +0100
commitb9ef6ab0c412913234f05f788b3fcd3c3277eb69 (patch)
tree2af9ef49ce74fd152c4c7b6f0aad543b4793ba59 /install/ui/src
parent8f8e790d9468245c031320d6a506a420f486638f (diff)
downloadfreeipa-b9ef6ab0c412913234f05f788b3fcd3c3277eb69.tar.gz
freeipa-b9ef6ab0c412913234f05f788b3fcd3c3277eb69.tar.xz
freeipa-b9ef6ab0c412913234f05f788b3fcd3c3277eb69.zip
Move of core Web UI files to AMD directory
SSIA https://fedorahosted.org/freeipa/ticket/112
Diffstat (limited to 'install/ui/src')
-rw-r--r--install/ui/src/freeipa/aci.js897
-rw-r--r--install/ui/src/freeipa/add.js207
-rw-r--r--install/ui/src/freeipa/association.js1389
-rw-r--r--install/ui/src/freeipa/automember.js679
-rw-r--r--install/ui/src/freeipa/automount.js354
-rwxr-xr-xinstall/ui/src/freeipa/certificate.js924
-rw-r--r--install/ui/src/freeipa/details.js1239
-rw-r--r--install/ui/src/freeipa/develop.js0
-rw-r--r--install/ui/src/freeipa/dialog.js849
-rw-r--r--install/ui/src/freeipa/dns.js2552
-rw-r--r--install/ui/src/freeipa/entitle.js745
-rw-r--r--install/ui/src/freeipa/entity.js731
-rw-r--r--install/ui/src/freeipa/facet.js2044
-rw-r--r--install/ui/src/freeipa/field.js951
-rw-r--r--install/ui/src/freeipa/group.js259
-rw-r--r--install/ui/src/freeipa/hbac.js553
-rw-r--r--install/ui/src/freeipa/hbactest.js842
-rw-r--r--install/ui/src/freeipa/host.js947
-rw-r--r--install/ui/src/freeipa/hostgroup.js90
-rw-r--r--install/ui/src/freeipa/idrange.js162
-rw-r--r--install/ui/src/freeipa/ipa.js2122
-rw-r--r--install/ui/src/freeipa/navigation.js455
-rw-r--r--install/ui/src/freeipa/net.js394
-rw-r--r--install/ui/src/freeipa/netgroup.js306
-rw-r--r--install/ui/src/freeipa/policy.js122
-rw-r--r--install/ui/src/freeipa/rule.js254
-rw-r--r--install/ui/src/freeipa/search.js491
-rw-r--r--install/ui/src/freeipa/selinux.js315
-rw-r--r--install/ui/src/freeipa/serverconfig.js118
-rw-r--r--install/ui/src/freeipa/service.js467
-rw-r--r--install/ui/src/freeipa/sudo.js930
-rw-r--r--install/ui/src/freeipa/trust.js183
-rw-r--r--install/ui/src/freeipa/user.js663
-rw-r--r--install/ui/src/freeipa/webui.js204
-rw-r--r--install/ui/src/freeipa/widget.js3559
35 files changed, 26997 insertions, 0 deletions
diff --git a/install/ui/src/freeipa/aci.js b/install/ui/src/freeipa/aci.js
new file mode 100644
index 000000000..bd7de19ab
--- /dev/null
+++ b/install/ui/src/freeipa/aci.js
@@ -0,0 +1,897 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Adam Young <ayoung@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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; version 2 only
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.aci = {};
+
+IPA.aci.permission_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups(['settings', 'privilege']).
+ search_facet({
+ columns: [ 'cn' ]
+ }).
+ details_facet({
+ factory: IPA.aci.permission_details_facet,
+ fields: [
+ {
+ name:'cn',
+ widget: 'identity.cn'
+ },
+ {
+ type: 'rights',
+ name: 'permissions',
+ widget: 'rights.permissions'
+ },
+ {
+ type: 'select',
+ name: 'target',
+ widget: 'target.target',
+ enabled: false
+ },
+ {
+ name: 'filter',
+ widget: 'target.filter',
+ enabled: false
+ },
+ {
+ type: 'entity_select',
+ name: 'memberof',
+ widget: 'target.memberof',
+ enabled: false
+ },
+ {
+ name: 'subtree',
+ widget: 'target.subtree',
+ enabled: false
+ },
+ {
+ type: 'entity_select',
+ name: 'targetgroup',
+ widget: 'target.targetgroup',
+ enabled: false
+ },
+ {
+ type: 'select',
+ name: 'type',
+ widget: 'target.type',
+ enabled: false
+ },
+ {
+ name: 'attrs',
+ widget: 'target.attrs',
+ enabled: false
+ },
+ {
+ name: 'attrs_multi',
+ param: 'attrs',
+ type: 'multivalued',
+ widget: 'target.attrs_multi',
+ enabled: false
+ }
+ ],
+ widgets: [
+ {
+ type: 'details_table_section',
+ name: 'identity',
+ label: IPA.messages.objects.permission.identity,
+ widgets: [
+ 'cn'
+ ]
+ },
+ {
+ type: 'details_table_section',
+ name: 'rights',
+ label: IPA.messages.objects.permission.rights,
+ widgets: [
+ {
+ type: 'rights',
+ name: 'permissions'
+ }
+ ]
+ },
+ {
+ type: 'permission_target',
+ container_factory: IPA.details_table_section,
+ label: IPA.messages.objects.permission.target,
+ name: 'target',
+ show_target: false
+ }
+ ],
+ policies: [
+ IPA.permission_target_policy('target')
+ ]
+ }).
+ association_facet({
+ name: 'member_privilege',
+ facet_group: 'privilege'
+ }).
+ adder_dialog({
+ height: 450,
+ fields: [
+ {
+ name:'cn',
+ widget: 'general.cn'
+ },
+ {
+ type: 'rights',
+ name: 'permissions',
+ widget: 'general.permissions'
+ },
+ {
+ type: 'select',
+ name: 'target',
+ widget: 'target.target',
+ enabled: false
+ },
+ {
+ name: 'filter',
+ widget: 'target.filter',
+ enabled: false
+ },
+ {
+ type: 'entity_select',
+ name: 'memberof',
+ widget: 'target.memberof',
+ enabled: false
+ },
+ {
+ name: 'subtree',
+ widget: 'target.subtree',
+ enabled: false
+ },
+ {
+ type: 'entity_select',
+ name: 'targetgroup',
+ widget: 'target.targetgroup',
+ enabled: false
+ },
+ {
+ type: 'select',
+ name: 'type',
+ widget: 'target.type',
+ enabled: false
+ },
+ {
+ name: 'attrs',
+ widget: 'target.attrs',
+ enabled: false
+ },
+ {
+ name: 'attrs_multi',
+ type: 'multivalued',
+ param: 'attrs',
+ widget: 'target.attrs_multi',
+ enabled: false
+ }
+ ],
+ widgets: [
+ {
+ type: 'details_table_section_nc',
+ name: 'general',
+ widgets: [
+ 'cn',
+ {
+ type: 'rights',
+ name: 'permissions'
+ }
+ ]
+ },
+ {
+ type: 'permission_target',
+ name:'target',
+ show_target: true
+ }
+ ],
+ policies: [
+ IPA.permission_target_policy('target')
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.aci.permission_details_facet = function(spec) {
+
+ var that = IPA.details_facet(spec);
+
+ that.get_refresh_command_name = function() {
+ return that.entity.name+'_show_'+that.pkey;
+ };
+
+ return that;
+};
+
+IPA.aci.privilege_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups(['permission', 'settings', 'role']).
+ search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'identity',
+ label: IPA.messages.details.identity,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'member_role',
+ facet_group: 'role',
+ add_method: 'add_privilege',
+ remove_method: 'remove_privilege',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_permission',
+ facet_group: 'permission',
+ add_method: 'add_permission',
+ remove_method: 'remove_permission'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.aci.role_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups(['member', 'privilege', 'settings']).
+ search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'identity',
+ label: IPA.messages.objects.role.identity,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'memberof_privilege',
+ facet_group: 'privilege',
+ add_method: 'add_privilege',
+ remove_method: 'remove_privilege'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.aci.selfservice_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [ 'aciname' ],
+ pagination: false
+ }).
+ details_facet({
+ check_rights: false,
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'aciname',
+ {
+ type: 'attributes',
+ object_type: 'user',
+ name: 'attrs'
+ }
+ ]
+ }
+ ]
+ }).
+ adder_dialog({
+ fields: [
+ 'aciname',
+ {
+ type: 'attributes',
+ object_type: 'user',
+ name: 'attrs'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.aci.delegation_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.group_entity = IPA.get_entity(spec.group_entity || 'group');
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [ 'aciname' ],
+ pagination: false
+ }).
+ details_facet({
+ check_rights: false,
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'aciname',
+ {
+ type: 'checkboxes',
+ name: 'permissions',
+ required: true,
+ options: IPA.create_options(['read', 'write'])
+ },
+ {
+ type: 'entity_select',
+ name: 'group',
+ other_entity: that.group_entity,
+ other_field: 'cn'
+ },
+ {
+ type: 'entity_select',
+ name: 'memberof',
+ other_entity: that.group_entity,
+ other_field: 'cn'
+ },
+ {
+ type: 'attributes',
+ name: 'attrs',
+ object_type: 'user'
+ }
+ ]
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'aciname',
+ {
+ type: 'checkboxes',
+ name: 'permissions',
+ options: IPA.create_options(['read', 'write'])
+ },
+ {
+ type: 'entity_select',
+ name: 'group',
+ other_entity: that.group_entity,
+ other_field: 'cn'
+ },
+ {
+ type: 'entity_select',
+ name: 'memberof',
+ other_entity: that.group_entity,
+ other_field: 'cn'
+ },
+ {
+ type: 'attributes',
+ name: 'attrs',
+ object_type: 'user'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+
+IPA.attributes_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.checkboxes_widget(spec);
+
+ that.object_type = spec.object_type;
+ that.skip_unmatched = spec.skip_unmatched === undefined ? false : spec.skip_unmatched;
+
+ var id = spec.name;
+
+ that.create = function(container) {
+ that.container = container;
+
+ var attr_container = $('<div/>', {
+ 'class': 'aci-attribute-table-container'
+ }).appendTo(container);
+
+ that.table = $('<table/>', {
+ id:id,
+ 'class':'search-table aci-attribute-table scrollable'
+ }).
+ append('<thead/>').
+ append('<tbody/>').
+ appendTo(attr_container);
+
+ var tr = $('<tr></tr>').appendTo($('thead', that.table));
+
+ tr.append($('<th/>', {
+ html: $('<input/>', {
+ type: "checkbox",
+ click: function() {
+ $('.aci-attribute', that.table).
+ prop('checked', $(this).prop('checked'));
+ that.value_changed.notify([], that);
+ }
+ })
+ })).append($('<th/>', {
+ 'class': 'aci-attribute-column',
+ html: IPA.messages.objects.aci.attribute
+ }));
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ if (that.object_type) {
+ that.populate(that.object_type);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.create_options = function(options) {
+ var tbody = $('tbody', that.table);
+
+ for (var i=0; i<options.length ; i++){
+ var value = options[i].toLowerCase();
+ var tr = $('<tr/>').appendTo(tbody);
+
+ var td = $('<td/>').appendTo(tr);
+ td.append($('<input/>',{
+ type: 'checkbox',
+ name: that.name,
+ value: value,
+ 'class': 'aci-attribute',
+ change: function() {
+ that.value_changed.notify([], that);
+ }
+ }));
+ td = $('<td/>').appendTo(tr);
+ td.append($('<label/>',{
+ text: value
+ }));
+ }
+ };
+
+ that.update = function(values) {
+
+ that.values = [];
+
+ values = values || [];
+ for (var i=0; i<values.length; i++) {
+
+ var value = values[i];
+
+ if (!value || value === '') continue;
+
+ value = value.toLowerCase();
+ that.values.push(value);
+ }
+
+ that.populate(that.object_type);
+ that.append();
+ that.checkboxes_update(values);
+ };
+
+ that.populate = function(object_type) {
+
+ $('tbody tr', that.table).remove();
+
+ if (!object_type || object_type === '') return;
+
+ var metadata = IPA.metadata.objects[object_type];
+ if (!metadata) return;
+
+ var aciattrs = metadata.aciattrs;
+
+ that.create_options(aciattrs);
+ };
+
+ that.append = function() {
+
+ if (!that.values) return;
+
+ var unmatched = [];
+
+ for (var i=0; i<that.values.length; i++) {
+ var input = $('input[name="'+that.name+'"]'+
+ '[value="'+that.values[i]+'"]', that.container);
+ if (!input.length) {
+ unmatched.push(that.values[i]);
+ }
+ }
+
+ if (unmatched.length > 0 && !that.skip_unmatched) {
+ that.create_options(unmatched);
+ }
+ };
+
+ that.show_undo = function() {
+ $(that.undo_span).css('display', 'inline-block');
+ };
+
+ return that;
+};
+
+IPA.widget_factories['attributes'] = IPA.attributes_widget;
+IPA.field_factories['attributes'] = IPA.checkboxes_field;
+
+IPA.rights_widget = function(spec) {
+
+ var that = IPA.checkboxes_widget(spec);
+
+ that.rights = ['write', 'add', 'delete'];
+ for (var i=0; i<that.rights.length; i++) {
+ var right = that.rights[i];
+ that.add_option({label: right, value: right});
+ }
+
+ return that;
+};
+
+IPA.widget_factories['rights'] = IPA.rights_widget;
+IPA.field_factories['rights'] = IPA.checkboxes_field;
+
+IPA.permission_target_widget = function(spec) {
+
+ spec = spec || {};
+
+ var factory = spec.container_factory || IPA.details_table_section_nc;
+
+ var that = factory(spec);
+
+ that.group_entity = IPA.get_entity(spec.group_entity || 'group');
+
+ that.targets = [ 'filter', 'subtree', 'targetgroup', 'type' ];
+ that.target = that.targets[0];
+ that.show_target = spec.show_target;
+
+ var init = function() {
+
+ that.target_select = IPA.select_widget({
+ entity: that.entity,
+ name: 'target',
+ label: IPA.messages.objects.permission.target,
+ hidden: !that.show_target
+ });
+
+ for (var i=0; i<that.targets.length; i++) {
+ var target = that.targets[i];
+ var target_param = IPA.get_entity_param('permission', target);
+
+ that.target_select.options.push({
+ label: target_param.label,
+ value: target
+ });
+ }
+
+ that.widgets.add_widget(that.target_select);
+
+
+ that.memberof_select = IPA.entity_select_widget({
+ entity: that.entity,
+ name: 'memberof',
+ other_entity: that.group_entity,
+ other_field: 'cn',
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.memberof_select);
+
+ that.filter_text = IPA.text_widget({
+ entity: that.entity,
+ name: 'filter',
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.filter_text);
+
+ that.subtree_textarea = IPA.textarea_widget({
+ entity: that.entity,
+ name: 'subtree',
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.subtree_textarea);
+
+ that.group_select = IPA.entity_select_widget({
+ entity: that.entity,
+ name: 'targetgroup',
+ other_entity: that.group_entity,
+ other_field: 'cn',
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.group_select);
+
+ that.type_select = IPA.select_widget({
+ entity: that.entity,
+ name: 'type',
+ hidden: true
+ });
+
+ var type_param = IPA.get_entity_param('permission', 'type');
+
+ for (var j=0; j<type_param.values.length; j++) {
+ var type_name = type_param.values[j];
+ var type_label = IPA.metadata.objects[type_name].label_singular;
+
+ that.type_select.options.push({
+ label: type_label,
+ value: type_name
+ });
+ }
+
+ that.widgets.add_widget(that.type_select);
+
+ that.attribute_table = IPA.attributes_widget({
+ entity: that.entity,
+ name: 'attrs',
+ object_type: type_param.values[0],
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.attribute_table);
+
+ that.attribute_multivalued = IPA.multivalued_widget({
+ entity: that.entity,
+ name: 'attrs_multi',
+ hidden: true
+ });
+
+ that.widgets.add_widget(that.attribute_multivalued);
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.permission_target_policy = function (widget_name) {
+
+ var that = IPA.facet_policy();
+
+ that.init = function() {
+
+ that.permission_target = that.container.widgets.get_widget(widget_name);
+ var widgets = that.permission_target.widgets;
+
+ var target_select = widgets.get_widget('target');
+ target_select.value_changed.attach(function() {
+ var target = target_select.save()[0];
+ that.select_target(target);
+ });
+
+ var type_select = widgets.get_widget('type');
+
+ type_select.value_changed.attach(function() {
+ var type = type_select.save()[0];
+ that.set_attrs_type(type, true);
+ });
+
+ type_select.undo_clicked.attach(function() {
+ var type = type_select.save()[0];
+ that.set_attrs_type(type, true);
+ });
+ };
+
+ that.set_attrs_type = function(type, skip_unmatched) {
+ var attribute_field = that.container.fields.get_field('attrs');
+ var attribute_table = that.permission_target.widgets.get_widget('attrs');
+ var skip_unmatched_org = attribute_table.skip_unmatched;
+ attribute_table.object_type = type;
+ // skip values which don't belong to new type. Bug #2617
+ attribute_table.skip_unmatched = skip_unmatched || skip_unmatched_org;
+ attribute_field.reset();
+ // force value_change to update dirty status if some unmatched values were skipped
+ attribute_table.value_changed.notify([], attribute_table);
+ attribute_table.skip_unmatched = skip_unmatched_org;
+ };
+
+ that.update_attrs = function() {
+
+ var type_select = that.permission_target.widgets.get_widget('type');
+ var type = type_select.save()[0];
+ that.set_attrs_type(type, false);
+ };
+
+ that.post_create = function() {
+ that.select_target(that.permission_target.targets[0]);
+ };
+
+ that.post_load = function(data) {
+
+ var displayed_target;
+
+ for (var target in that.target_mapping) {
+
+ if (data.result.result[target]) {
+ displayed_target = target;
+ } else {
+ that.set_target_visible(target, false);
+ }
+ }
+
+ if (displayed_target) {
+ that.permission_target.target = displayed_target;
+ that.set_target_visible(displayed_target, true);
+ }
+ };
+
+ that.select_target = function(target) {
+ that.set_target_visible(that.permission_target.target, false);
+ that.permission_target.target = target;
+ that.set_target_visible(that.permission_target.target, true);
+ };
+
+ that.set_target_visible = function(target, visible) {
+
+ var target_info = that.target_mapping[target];
+ that.set_target_visible_core(target_info, visible);
+ };
+
+ that.set_target_visible_core = function(target_info, visible) {
+ var widget = that.permission_target.widgets.get_widget(target_info.name);
+ var field = that.container.fields.get_field(target_info.name);
+ that.permission_target.set_row_visible(target_info.name, visible);
+ field.enabled = visible;
+ field.set_required(visible && target_info.required);
+ widget.hidden = !visible;
+
+ if (target_info.additional) {
+ for (var i=0; i<target_info.additional.length; i++) {
+ var nested_info = target_info.additional[i];
+ that.set_target_visible_core(nested_info, visible);
+ }
+ }
+
+ if (target_info.action) target_info.action();
+ };
+
+
+ that.target_mapping = {
+ filter: {
+ name: 'filter',
+ required: true,
+ additional: [
+ {
+ name: 'attrs_multi'
+ }
+ ]
+ },
+ subtree: {
+ name: 'subtree',
+ required: true,
+ additional: [
+ {
+ name: 'memberof'
+ },
+ {
+ name: 'attrs_multi'
+ }
+ ]
+ },
+ targetgroup: {
+ name: 'targetgroup',
+ required: true,
+ additional: [
+ {
+ name: 'attrs'
+ }
+ ],
+ action: function() {
+ that.set_attrs_type('group', false);
+ }
+ },
+ type: {
+ name: 'type',
+ additional: [
+ {
+ name: 'memberof'
+ },
+ {
+ name: 'attrs'
+ }
+ ],
+ action: function() {
+ that.update_attrs();
+ }
+ }
+ };
+
+
+ return that;
+};
+
+IPA.widget_factories['permission_target'] = IPA.permission_target_widget;
+
+
+IPA.register('permission', IPA.aci.permission_entity);
+IPA.register('privilege', IPA.aci.privilege_entity);
+IPA.register('role', IPA.aci.role_entity);
+IPA.register('selfservice', IPA.aci.selfservice_entity);
+IPA.register('delegation', IPA.aci.delegation_entity);
diff --git a/install/ui/src/freeipa/add.js b/install/ui/src/freeipa/add.js
new file mode 100644
index 000000000..6d3f454be
--- /dev/null
+++ b/install/ui/src/freeipa/add.js
@@ -0,0 +1,207 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* REQUIRES: ipa.js */
+
+IPA.entity_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'entity_adder_dialog';
+
+ var that = IPA.dialog(spec);
+
+ IPA.confirm_mixin().apply(that);
+
+ that.method = spec.method || 'add';
+ that.on_error = spec.on_error ;
+ that.retry = typeof spec.retry !== 'undefined' ? spec.retry : true;
+ that.command = null;
+ that.added = IPA.observer();
+ that.subject = spec.subject || that.entity.metadata.label_singular;
+
+ that.show_edit_page = spec.show_edit_page || show_edit_page;
+
+ var init = function() {
+ that.create_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ click: function() {
+ that.on_add();
+ }
+ });
+
+ that.create_button({
+ name: 'add_and_add_another',
+ label: IPA.messages.buttons.add_and_add_another,
+ click: function() {
+ that.hide_message();
+ that.add(
+ function(data, text_status, xhr) {
+ that.added.notify();
+ that.show_message(that.get_success_message(data));
+ var facet = IPA.current_entity.get_facet();
+ facet.refresh();
+ that.reset();
+ that.focus_first_element();
+ },
+ that.on_error);
+ }
+ });
+
+ that.create_button({
+ name: 'add_and_edit',
+ label: IPA.messages.buttons.add_and_edit,
+ click: function() {
+ that.hide_message();
+ that.add(
+ function(data, text_status, xhr) {
+ that.added.notify();
+ that.close();
+ var result = data.result.result;
+ that.show_edit_page(that.entity, result);
+ that.notify_success(data);
+ },
+ that.on_error);
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.hide_message();
+ that.close();
+ }
+ });
+ };
+
+ that.on_add = function() {
+
+ that.hide_message();
+ that.add(
+ function(data, text_status, xhr) {
+ that.added.notify();
+ var facet = IPA.current_entity.get_facet();
+ facet.refresh();
+ that.close();
+ that.notify_success(data);
+ },
+ that.on_error);
+ };
+
+ that.on_confirm = function() {
+ that.on_add();
+ };
+
+ that.get_success_message = function(data) {
+ var message = IPA.messages.dialogs.add_confirmation;
+ return message.replace('${entity}', that.subject);
+ };
+
+ that.notify_success = function(data) {
+ IPA.notify_success(that.get_success_message(data));
+ };
+
+ function show_edit_page(entity,result) {
+ var pkey_name = entity.metadata.primary_key;
+ var pkey = result[pkey_name];
+ if (pkey instanceof Array) {
+ pkey = pkey[0];
+ }
+ IPA.nav.show_entity_page(that.entity, 'default', pkey);
+ }
+
+ that.create_add_command = function(record) {
+
+ var pkey_name = that.entity.metadata.primary_key;
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.method,
+ retry: that.retry
+ });
+
+ command.add_args(that.entity.get_primary_key_prefix());
+
+ var fields = that.fields.get_fields();
+ for (var j=0; j<fields.length; j++) {
+ var field = fields[j];
+
+ var values = record[field.param];
+ if (!values || values.length === 0) continue;
+ if (field.flags.indexOf('no_command') > -1) continue;
+
+ if (field.param === pkey_name) {
+ command.add_arg(values[0]);
+ } else if (values.length === 1) {
+ command.set_option(field.param, values[0]);
+ } else {
+ command.set_option(field.param, values);
+ }
+ }
+
+ return command;
+ };
+
+ that.add = function(on_success, on_error) {
+
+ if (!that.validate()) return;
+
+ var record = {};
+ that.save(record);
+
+ that.command = that.create_add_command(record);
+ that.command.on_success = on_success;
+ that.command.on_error = on_error;
+
+ that.command.execute();
+ };
+
+ that.create = function() {
+ that.dialog_create();
+
+ var div = $('<div/>', {
+ }).appendTo(that.container);
+
+ $('<span/>', {
+ 'class': 'required-indicator',
+ text: IPA.required_indicator
+ }).appendTo(div);
+
+ div.append(' ');
+
+ $('<span/>', {
+ text: IPA.messages.widget.validation.required
+ }).appendTo(div);
+ };
+
+ // methods that should be invoked by subclasses
+ that.entity_adder_dialog_create = that.create;
+ that.entity_adder_dialog_create_add_command = that.create_add_command;
+ that.entity_adder_dialog_get_success_message = that.get_success_message;
+
+ init();
+
+ return that;
+};
diff --git a/install/ui/src/freeipa/association.js b/install/ui/src/freeipa/association.js
new file mode 100644
index 000000000..70b8e9f1e
--- /dev/null
+++ b/install/ui/src/freeipa/association.js
@@ -0,0 +1,1389 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Adam Young <ayoung@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* REQUIRES: ipa.js */
+/* CURRENTLY ALSO REQUIRES search.js, because it reuses it's code to create
+ * the AssociationList elements; IT NEEDS IT'S OWN CODE! */
+
+IPA.associator = function (spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.pkey = spec.pkey;
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+ that.values = spec.values;
+
+ that.method = spec.method;
+
+ that.on_success = spec.on_success;
+ that.on_error = spec.on_error;
+
+ that.execute = function() {
+ };
+
+ return that;
+};
+
+
+/**
+ * This associator is built for the case where each association requires a separate rpc
+ */
+IPA.serial_associator = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.associator(spec);
+
+ that.execute = function() {
+
+ if (!that.values || !that.values.length) {
+ that.on_success();
+ return;
+ }
+
+ var batch = IPA.batch_command({
+ on_success: that.on_success,
+ on_error: that.on_error
+ });
+
+ var args, options, command;
+
+ for(var i=0; i < that.values.length; i++) {
+ args = [that.values[i]];
+ options = {};
+ options[that.entity.name] = that.pkey;
+
+ command = IPA.command({
+ entity: that.other_entity.name,
+ method: that.method,
+ args: args,
+ options: options
+ });
+
+ batch.add_command(command);
+ }
+ //alert(JSON.stringify(command.to_json()));
+
+ batch.execute();
+ };
+
+ return that;
+};
+
+/**
+ * This associator is for the common case where all the asociations can be sent
+ * in a single rpc
+ */
+IPA.bulk_associator = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.associator(spec);
+
+ that.execute = function() {
+
+ if (!that.values || !that.values.length) {
+ that.on_success();
+ return;
+ }
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.method,
+ args: [that.pkey],
+ options: { 'all': true },
+ on_success: that.on_success,
+ on_error: that.on_error
+ });
+
+ command.set_option(that.other_entity.name, that.values);
+
+ //alert(JSON.stringify(command.to_json()));
+
+ command.execute();
+ };
+
+ return that;
+};
+
+/**
+ * This dialog is for adding value of multivalued attribute which behaves like
+ * association attribute.
+ */
+IPA.attribute_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'attr_adder_dialog';
+ spec.method = spec.method || 'add_member';
+
+ var metadata = IPA.get_command_option(spec.entity.name+'_'+spec.method, spec.attribute);
+
+ spec.fields = spec.fields || [
+ {
+ name: spec.attribute,
+ metadata: metadata,
+ required: true
+ }
+ ];
+ spec.title = spec.title || IPA.messages.dialogs.add_title.replace('${entity}', metadata.label);
+ spec.subject = metadata.label;
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.create_add_command = function(record) {
+
+ var command = that.entity_adder_dialog_create_add_command(record);
+
+ command.add_args(that.entity.get_primary_key());
+
+ return command;
+ };
+
+ that.create_buttons = function() {
+
+ that.buttons.remove('add_and_edit');
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+/**
+ * This dialog is used for adding associations between two entities.
+ */
+IPA.association_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.adder_dialog(spec);
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.pkey = spec.pkey;
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+ that.attribute_member = spec.attribute_member;
+
+ that.exclude = spec.exclude || [];
+
+ var init = function() {
+ if (!that.get_columns().length) {
+ var pkey_name = that.other_entity.metadata.primary_key;
+ that.create_column({
+ entity: that.entity,
+ name: pkey_name,
+ label: that.other_entity.metadata.label,
+ primary_key: true,
+ width: '600px'
+ });
+ }
+ };
+
+ that.search = function() {
+ function on_success(data, text_status, xhr) {
+
+ that.clear_available_values();
+
+ var pkey_attr = that.other_entity.metadata.primary_key;
+
+ var selected = that.get_selected_values();
+
+ var results = data.result;
+ var same_entity = that.entity === that.other_entity;
+ for (var i=0; i<results.count; i++) {
+ var result = results.result[i];
+ var pkey = result[pkey_attr][0];
+
+ if (same_entity && pkey === that.pkey) continue;
+ if (that.exclude.indexOf(pkey) >= 0) continue;
+ if (selected.indexOf(pkey) >= 0) continue;
+
+ that.add_available_value(result);
+ }
+ }
+
+ var options = { all: true };
+ var relationships = that.other_entity.metadata.relationships;
+
+ /* TODO: better generic handling of different relationships! */
+ var other_attribute_member = '';
+ if (that.attribute_member == 'member')
+ other_attribute_member = 'memberof';
+ else if (that.attribute_member == 'memberuser')
+ other_attribute_member = 'memberof';
+ else if (that.attribute_member == 'memberhost')
+ other_attribute_member = 'memberof';
+ else if (that.attribute_member == 'memberof')
+ other_attribute_member = 'member';
+ else if (that.attribute_member == 'managedby')
+ other_attribute_member = 'managing';
+
+ var relationship = relationships[other_attribute_member];
+ if (relationship) {
+ var param_name = relationship[2] + that.entity.name;
+ var cmd_opt = IPA.get_command_option(that.other_entity.name + '_find',
+ param_name);
+ if (cmd_opt) {
+ options[param_name] = that.pkey;
+ }
+ }
+
+ IPA.command({
+ entity: that.other_entity.name,
+ method: 'find',
+ args: [that.get_filter()],
+ options: options,
+ on_success: on_success
+ }).execute();
+ };
+
+ init();
+
+ return that;
+};
+
+
+/**
+ * This dialog is used for removing associations between two entities.
+ */
+IPA.association_deleter_dialog = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.deleter_dialog(spec);
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.pkey = spec.pkey;
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+ that.values = spec.values;
+
+ that.associator = spec.associator;
+ that.method = spec.method || 'remove_member';
+
+ that.on_success = spec.on_success;
+ that.on_error = spec.on_error;
+
+ that.execute = function() {
+
+ var associator = that.associator({
+ entity: that.entity,
+ pkey: that.pkey,
+ other_entity: that.other_entity,
+ values: that.values,
+ method: that.method,
+ on_success: that.on_success,
+ on_error: that.on_error
+ });
+
+ associator.execute();
+ };
+
+ return that;
+};
+
+
+IPA.association_config = function (spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.associator = spec.associator;
+ that.add_method = spec.add_method;
+ that.remove_method = spec.remove_method;
+
+ return that;
+};
+
+IPA.association_table_widget = function (spec) {
+
+ spec = spec || {};
+
+ var index = spec.name.indexOf('_');
+ spec.attribute_member = spec.attribute_member || spec.name.substring(0, index);
+ spec.other_entity = spec.other_entity || spec.name.substring(index+1);
+
+ spec.managed_entity = IPA.get_entity(spec.other_entity);
+
+ var that = IPA.table_widget(spec);
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+ that.attribute_member = spec.attribute_member;
+
+ that.associator = spec.associator || IPA.bulk_associator;
+ that.add_method = spec.add_method || 'add_member';
+ that.remove_method = spec.remove_method || 'remove_member';
+
+ that.add_title = spec.add_title || IPA.messages.association.add.member;
+ that.remove_title = spec.remove_title || IPA.messages.association.remove.member;
+
+ that.adder_columns = $.ordered_map();
+
+ that.needs_refresh = IPA.observer();
+
+ that.get_adder_column = function(name) {
+ return that.adder_columns.get(name);
+ };
+
+ that.add_adder_column = function(column) {
+ that.adder_columns.put(column.name, column);
+ };
+
+ that.create_adder_column = function(spec) {
+ spec.entity = that.other_entity;
+ var column = IPA.column(spec);
+ that.add_adder_column(column);
+ return column;
+ };
+
+ that.create_columns = function() {
+ // create a column if none defined
+ if (!that.columns.length) {
+ that.create_column({
+ name: that.name,
+ label: that.label,
+ entity: that.other_entity,
+ primary_key: true,
+ link: true
+ });
+ }
+ };
+
+ that.init_columns = function() {
+ var column;
+ var columns = that.columns.values;
+ for (var i=0; i<columns.length; i++) {
+ column = columns[i];
+ column.entity = that.other_entity;
+
+ if (column.link) {
+ column.link_handler = function(value) {
+ IPA.nav.show_page(that.other_entity.name, 'default', value);
+ return false;
+ };
+ }
+ }
+ };
+
+ that.init_adder_columns = function() {
+ var column;
+ var adder_columns = that.adder_columns.values;
+ for (var j=0; j<adder_columns.length; j++) {
+ column = adder_columns[j];
+ column.entity = that.other_entity;
+ }
+ };
+
+ that.init = function() {
+
+ that.create_columns();
+ that.init_columns();
+ that.init_adder_columns();
+ };
+
+ that.create = function(container) {
+
+ that.init();
+
+ that.table_create(container);
+
+ that.remove_button = IPA.action_button({
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon',
+ 'class': 'action-button-disabled',
+ click: function() {
+ if (!that.remove_button.hasClass('action-button-disabled')) {
+ that.remove_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.buttons);
+
+ that.add_button = IPA.action_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon',
+ click: function() {
+ if (!that.add_button.hasClass('action-button-disabled')) {
+ that.add_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.buttons);
+ };
+
+ that.add_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_add_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_add_dialog();
+ }
+ };
+
+ that.remove_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_remove_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_remove_dialog();
+ }
+ };
+
+ that.set_enabled = function(enabled) {
+ that.table_set_enabled(enabled);
+ if (enabled) {
+ if(that.add_button) {
+ that.add_button.removeClass('action-button-disabled');
+ }
+ } else {
+ $('.action-button', that.table).addClass('action-button-disabled');
+ that.unselect_all();
+ }
+ that.enabled = enabled;
+ };
+
+ that.select_changed = function() {
+
+ var values = that.get_selected_values();
+
+ if (that.remove_button) {
+ if (values.length === 0) {
+ that.remove_button.addClass('action-button-disabled');
+ } else {
+ that.remove_button.removeClass('action-button-disabled');
+ }
+ }
+ };
+
+ that.load = function(result) {
+ that.values = result[that.name] || [];
+ that.update();
+ that.unselect_all();
+ };
+
+ that.update = function(values) {
+
+ if (values) that.values = values;
+
+ that.empty();
+
+ var i;
+ var columns = that.columns.values;
+ if (columns.length == 1) { // show pkey only
+ var name = columns[0].name;
+ for (i=0; i<that.values.length; i++) {
+ var record = {};
+ record[name] = that.values[i];
+ that.add_record(record);
+ }
+ } else {
+ for (i=0; i<that.values.length; i++) {
+ that.add_record(that.values[i]);
+ }
+ }
+ };
+
+ that.create_add_dialog = function() {
+
+ var entity_label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var other_entity_label = that.other_entity.metadata.label;
+
+ var title = that.add_title;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', pkey);
+ title = title.replace('${other_entity}', other_entity_label);
+
+ return IPA.association_adder_dialog({
+ title: title,
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ attribute_member: that.attribute_member,
+ method: that.add_method,
+ exclude: that.values
+ });
+ };
+
+ that.show_add_dialog = function() {
+
+ var dialog = that.create_add_dialog({entity:that.entity});
+
+ var columns = that.adder_columns.values;
+ if (columns.length) {
+ dialog.set_columns(columns);
+ }
+
+ dialog.execute = function() {
+ that.add(
+ dialog.get_selected_values(),
+ function() {
+ that.refresh();
+ dialog.close();
+ IPA.notify_success(IPA.messages.association.added);
+ },
+ function() {
+ that.refresh();
+ dialog.close();
+ }
+ );
+ };
+
+ dialog.open(that.container);
+ };
+
+ that.add = function(values, on_success, on_error) {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.add_method,
+ args: [pkey],
+ on_success: on_success,
+ on_error: on_error
+ });
+ command.set_option(that.other_entity.name, values);
+
+ command.execute();
+ };
+
+ that.show_remove_dialog = function() {
+
+ var selected_values = that.get_selected_values();
+
+ if (!selected_values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return;
+ }
+
+ var entity_label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var other_entity_label = that.other_entity.metadata.label;
+
+ var title = that.remove_title;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', pkey);
+ title = title.replace('${other_entity}', other_entity_label);
+
+ var dialog = IPA.association_deleter_dialog({
+ title: title,
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ values: selected_values,
+ method: that.remove_method
+ });
+
+ dialog.execute = function() {
+ that.remove(
+ selected_values,
+ function() {
+ that.refresh();
+ IPA.notify_success(IPA.messages.association.removed);
+ },
+ function() {
+ that.refresh();
+ }
+ );
+ };
+
+
+ dialog.open(that.container);
+ };
+
+ that.remove = function(values, on_success, on_error) {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.remove_method,
+ args: [pkey],
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.set_option(that.other_entity.name, values);
+
+ command.execute();
+ };
+
+ that.refresh = function() {
+
+ that.needs_refresh.notify([], that);
+ };
+
+ /*initialization code*/
+ /*this is duplicated in the facet... should be unified*/
+ var i;
+ if (spec.columns){
+ for (i = 0; i < spec.columns.length; i+= 1){
+ spec.columns[i].entity = spec.columns[i].entity || that.other_entity;
+ that.create_column(spec.columns[i]);
+ }
+ }
+ if (spec.adder_columns){
+ for (i = 0; i < spec.adder_columns.length; i+= 1){
+ that.create_adder_column(spec.adder_columns[i]);
+ }
+ }
+
+ // methods that should be invoked by subclasses
+ that.association_table_widget_create_columns = that.create_columns;
+ that.association_table_widget_show_add_dialog = that.show_add_dialog;
+ that.association_table_widget_show_remove_dialog = that.show_remove_dialog;
+
+ return that;
+};
+
+IPA.association_table_field = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.refresh = function() {
+
+ function on_success(data, text_status, xhr) {
+ that.load(data.result.result);
+ }
+
+ function on_error(xhr, text_status, error_thrown) {
+ that.widget.summary.text(error_thrown.name+': '+error_thrown.message);
+ }
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ IPA.command({
+ entity: that.entity.name,
+ method: 'show',
+ args: [pkey],
+ options: { all: true, rights: true },
+ on_success: on_success,
+ on_error: on_error
+ }).execute();
+ };
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ that.widget.needs_refresh.attach(that.refresh);
+ };
+
+ return that;
+};
+
+IPA.widget_factories['association_table'] = IPA.association_table_widget;
+IPA.field_factories['association_table'] = IPA.association_table_field;
+
+
+IPA.association_facet = function (spec, no_init) {
+
+ spec = spec || {};
+
+ /*
+ Link parameter is used to turn off the links in selfservice mode.
+ Default it to true if not set so that facets that would not otherwise
+ link by default get links set.
+
+ link must be set before the call to the base class, to affect the table.
+ */
+ spec.link = spec.link === undefined ? true : spec.link;
+ spec.managed_entity = IPA.get_entity(spec.other_entity);
+
+
+ //default buttons and their actions
+ spec.actions = spec.actions || [];
+ spec.actions.unshift(
+ IPA.refresh_action,
+ {
+ name: 'remove',
+ hide_cond: ['read-only'],
+ show_cond: ['direct'],
+ enable_cond: ['item-selected'],
+ handler: function(facet) {
+ facet.show_remove_dialog();
+ }
+ },
+ {
+ name: 'add',
+ hide_cond: ['read-only'],
+ show_cond: ['direct'],
+ handler: function(facet) {
+ facet.show_add_dialog();
+ }
+ }
+ );
+
+ spec.control_buttons = spec.control_buttons || [];
+ spec.control_buttons.unshift(
+ {
+ name: 'refresh',
+ label: IPA.messages.buttons.refresh,
+ icon: 'reset-icon'
+ },
+ {
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon'
+ },
+ {
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon'
+ });
+
+ spec.state = spec.state || {};
+ spec.state.evaluators = spec.state.evaluators || [];
+ spec.state.evaluators.push(
+ IPA.selected_state_evaluator,
+ IPA.association_type_state_evaluator,
+ IPA.read_only_state_evaluator);
+
+ var that = IPA.table_facet(spec, true);
+
+ that.attribute_member = spec.attribute_member;
+ that.indirect_attribute_member = spec.indirect_attribute_member;
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+
+ that.association_type = 'direct';
+ that.facet_group = spec.facet_group;
+
+ that.read_only = spec.read_only;
+
+ that.associator = spec.associator || IPA.bulk_associator;
+ that.add_method = spec.add_method || 'add_member';
+ that.remove_method = spec.remove_method || 'remove_member';
+
+ that.add_title = spec.add_title || IPA.messages.association.add.member;
+ that.remove_title = spec.remove_title || IPA.messages.association.remove.member;
+
+ that.adder_columns = $.ordered_map();
+
+ that.get_adder_column = function(name) {
+ return that.adder_columns.get(name);
+ };
+
+ that.add_adder_column = function(column) {
+ column.entity = that.other_entity;
+ that.adder_columns.put(column.name, column);
+ };
+
+ /*TODO try to reuse the association_table_widget in association_facet*/
+ that.create_adder_column = function(spec) {
+ var column;
+ var factory;
+ if (spec instanceof Object) {
+ factory = spec.factory || IPA.column;
+ } else {
+ factory = IPA.column;
+ spec = { name: spec };
+ }
+ spec.entity = that.other_entity;
+ column = factory(spec);
+ that.add_adder_column(column);
+ return column;
+ };
+
+ var init = function() {
+
+ var column;
+ var i;
+
+ var pkey_name;
+ if (that.other_entity) {
+ pkey_name = that.other_entity.metadata.primary_key;
+ }
+
+ if (!that.columns.length){
+ that.create_column({
+ name: pkey_name
+ });
+ }
+
+ var columns = that.columns.values;
+ for (i=0; i<columns.length; i++) {
+ column = columns[i];
+ column.link = spec.link;
+ }
+
+ that.init_table(that.other_entity);
+
+ var adder_columns = spec.adder_columns || [];
+ for (i=0; i<adder_columns.length; i++) {
+ that.create_adder_column(adder_columns[i]);
+ }
+
+ if (!that.adder_columns.length) {
+ that.create_adder_column({
+ name: pkey_name,
+ primary_key: true
+ });
+ }
+
+ adder_columns = that.adder_columns.values;
+ for (i=0; i<adder_columns.length; i++) {
+ column = adder_columns[i];
+ column.entity = that.other_entity;
+ }
+ };
+
+ that.get_records_command_name = function() {
+ return that.entity.name+'_'+that.get_attribute_name();
+ };
+
+ that.create_header = function(container) {
+
+ that.facet_create_header(container);
+
+ if (that.indirect_attribute_member) {
+
+ var div = $('<div/>', {
+ 'class': 'right-aligned-facet-controls'
+ }).appendTo(that.controls);
+
+ div.append(IPA.messages.association.show_results);
+ div.append(' ');
+
+ var name = that.entity.name+'-'+that.attribute_member+'-'+that.other_entity.name+'-type-radio';
+ var direct_id = name + '-direct';
+
+ that.direct_radio = $('<input/>', {
+ id: direct_id,
+ type: 'radio',
+ name: name,
+ value: 'direct',
+ click: function() {
+ that.association_type = $(this).val();
+ that.refresh();
+ return true;
+ }
+ }).appendTo(div);
+
+ $('<label/>', {
+ text: IPA.messages.association.direct_membership,
+ 'for': direct_id
+ }).appendTo(div);
+
+ div.append(' ');
+
+ var indirect_id = name + '-indirect';
+
+ that.indirect_radio = $('<input/>', {
+ id: indirect_id,
+ type: 'radio',
+ name: name,
+ value: 'indirect',
+ click: function() {
+ that.association_type = $(this).val();
+ that.refresh();
+ return true;
+ }
+ }).appendTo(div);
+
+ $('<label/>', {
+ text: IPA.messages.association.indirect_membership,
+ 'for': indirect_id
+ }).appendTo(div);
+ }
+
+ that.create_control_buttons(that.controls);
+ };
+
+ that.get_attribute_name = function() {
+ if (that.association_type == 'direct') {
+ return that.attribute_member+'_'+that.other_entity.name;
+ } else {
+ return that.indirect_attribute_member+'_'+that.other_entity.name;
+ }
+ };
+
+ that.show = function() {
+ that.facet_show();
+
+ that.pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ that.header.set_pkey(that.pkey);
+ };
+
+ that.show_add_dialog = function() {
+
+ var entity_label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var other_entity_label = that.other_entity.metadata.label;
+
+ var title = that.add_title;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', pkey);
+ title = title.replace('${other_entity}', other_entity_label);
+
+ var pkeys = that.data.result.result[that.get_attribute_name()];
+
+ var dialog = IPA.association_adder_dialog({
+ title: title,
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ attribute_member: that.attribute_member,
+ exclude: pkeys
+ });
+
+ var adder_columns = that.adder_columns.values;
+ if (adder_columns.length) {
+ dialog.set_columns(adder_columns);
+ }
+
+ dialog.execute = function() {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var associator = that.associator({
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ values: dialog.get_selected_values(),
+ method: that.add_method,
+ on_success: function() {
+ that.refresh();
+ dialog.close();
+ IPA.notify_success(IPA.messages.association.added);
+ },
+ on_error: function() {
+ that.refresh();
+ dialog.close();
+ }
+ });
+
+ associator.execute();
+ };
+
+ dialog.open(that.container);
+ };
+
+ that.show_remove_dialog = function() {
+
+ var values = that.table.get_selected_values();
+
+ if (!values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return;
+ }
+
+ var entity_label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var other_entity_label = that.other_entity.metadata.label;
+
+ var title = that.remove_title;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', pkey);
+ title = title.replace('${other_entity}', other_entity_label);
+
+ var dialog = IPA.association_deleter_dialog({
+ title: title,
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ values: values
+ });
+
+ dialog.execute = function() {
+
+ var associator = that.associator({
+ entity: that.entity,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ values: values,
+ method: that.remove_method,
+ on_success: function() {
+ that.refresh();
+ IPA.notify_success(IPA.messages.association.removed);
+ },
+ on_error: function() {
+ that.refresh();
+ }
+ });
+
+ associator.execute();
+ };
+
+ dialog.open(that.container);
+ };
+
+ that.get_records_map = function(data) {
+
+ var records_map = $.ordered_map();
+ var association_name = that.get_attribute_name();
+ var pkey_name = that.managed_entity.metadata.primary_key;
+
+ var pkeys = data.result.result[association_name];
+ for (var i=0; pkeys && i<pkeys.length; i++) {
+ var pkey = pkeys[i];
+ var record = {};
+ record[pkey_name] = pkey;
+ records_map.put(pkey, record);
+ }
+
+ return records_map;
+ };
+
+ that.refresh = function() {
+
+ if (that.association_type == 'direct') {
+ if (that.direct_radio) that.direct_radio.prop('checked', true);
+ } else {
+ if (that.indirect_radio) that.indirect_radio.prop('checked', true);
+ }
+
+ var pkey = that.entity.get_primary_key();
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: 'show',
+ args: pkey
+ });
+
+ command.on_success = function(data, text_status, xhr) {
+ that.load(data);
+ that.show_content();
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.redirect_error(error_thrown);
+ that.report_error(error_thrown);
+ };
+
+ command.execute();
+ };
+
+ that.clear = function() {
+ that.header.clear();
+ that.table.clear();
+ };
+
+ that.needs_update = function() {
+ if (that._needs_update !== undefined) return that._needs_update;
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ if (that.pkey !== pkey) return true;
+
+ var page = parseInt(IPA.nav.get_state(that.entity.name+'-page'), 10) || 1;
+ if (that.table.current_page !== page) return true;
+
+ return that.facet_needs_update();
+ };
+
+ that.init_association_facet = function() {
+
+ that.init_facet();
+ that.init_table_columns();
+ init();
+ };
+
+ if (!no_init) that.init_association_facet();
+
+
+ return that;
+};
+
+IPA.attribute_facet = function(spec, no_init) {
+
+ spec = spec || {};
+
+ //default buttons and their actions
+ spec.actions = spec.actions || [];
+ spec.actions.unshift(
+ IPA.refresh_action,
+ {
+ name: 'remove',
+ hide_cond: ['read-only'],
+ enable_cond: ['item-selected'],
+ handler: function(facet) {
+ facet.show_remove_dialog();
+ }
+ },
+ {
+ name: 'add',
+ hide_cond: ['read-only'],
+ handler: function(facet) {
+ facet.show_add_dialog();
+ }
+ }
+ );
+
+ spec.control_buttons = spec.control_buttons || [];
+ spec.control_buttons.unshift(
+ {
+ name: 'refresh',
+ label: IPA.messages.buttons.refresh,
+ icon: 'reset-icon'
+ },
+ {
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon'
+ },
+ {
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon'
+ });
+
+ spec.state = spec.state || {};
+ spec.state.evaluators = spec.state.evaluators || [];
+ spec.state.evaluators.push(
+ IPA.selected_state_evaluator,
+ IPA.read_only_state_evaluator,
+ {
+ factory: IPA.attr_read_only_evaluator,
+ attribute: spec.attribute
+ });
+
+ spec.columns = spec.columns || [ spec.attribute ];
+ spec.table_name = spec.table_name || spec.attribute;
+
+ var that = IPA.table_facet(spec, true);
+
+ that.attribute = spec.attribute;
+
+ that.add_method = spec.add_method || 'add_member';
+ that.remove_method = spec.remove_method || 'remove_member';
+
+ that.create_header = function(container) {
+
+ that.facet_create_header(container);
+ that.create_control_buttons(that.controls);
+ };
+
+ that.show = function() {
+ that.facet_show();
+
+ that.pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ that.header.set_pkey(that.pkey);
+ };
+
+ that.get_records_map = function(data) {
+
+ var records_map = $.ordered_map();
+ var pkeys = data.result.result[that.attribute];
+
+ for (var i=0; pkeys && i<pkeys.length; i++) {
+ var pkey = pkeys[i];
+ var record = {};
+ record[that.attribute] = pkey;
+ records_map.put(pkey, record);
+ }
+
+ return records_map;
+ };
+
+ that.refresh = function() {
+
+ var pkey = that.entity.get_primary_key();
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: 'show',
+ args: pkey
+ });
+
+ if (command.check_option('all')) {
+ command.set_option('all', true);
+ }
+ if (command.check_option('rights')) {
+ command.set_option('rights', true);
+ }
+
+ command.on_success = function(data, text_status, xhr) {
+ that.load(data);
+ that.show_content();
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.redirect_error(error_thrown);
+ that.report_error(error_thrown);
+ };
+
+ command.execute();
+ };
+
+ that.clear = function() {
+ that.header.clear();
+ that.table.clear();
+ };
+
+ that.needs_update = function() {
+ if (that._needs_update !== undefined) return that._needs_update;
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ if (that.pkey !== pkey) return true;
+
+ var page = parseInt(IPA.nav.get_state(that.entity.name+'-page'), 10) || 1;
+ if (that.table.current_page !== page) return true;
+
+ return that.facet_needs_update();
+ };
+
+ that.show_add_dialog = function() {
+
+ var dialog = IPA.attribute_adder_dialog({
+ attribute: spec.attribute,
+ entity: that.entity
+ });
+
+ dialog.open(that.container);
+ };
+
+ that.show_remove_dialog = function() {
+
+ var selected_values = that.get_selected_values();
+
+ if (!selected_values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return;
+ }
+
+ var dialog = IPA.deleter_dialog({
+ entity: that.entity,
+ values: selected_values
+ });
+
+ dialog.execute = function() {
+ that.remove(
+ selected_values,
+ function(data) {
+ that.load(data);
+ that.show_content();
+ IPA.notify_success(IPA.messages.association.removed);
+ },
+ function() {
+ that.refresh();
+ }
+ );
+ };
+
+
+ dialog.open(that.container);
+ };
+
+ that.remove = function(values, on_success, on_error) {
+
+ var pkey = that.entity.get_primary_key();
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.remove_method,
+ args: pkey,
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.set_option(that.attribute, values);
+
+ if (command.check_option('all')) {
+ command.set_option('all', true);
+ }
+ if (command.check_option('rights')) {
+ command.set_option('rights', true);
+ }
+
+ command.execute();
+ };
+
+
+ that.init_attribute_facet = function() {
+
+ that.init_facet();
+ that.init_table_columns();
+ that.init_table(that.entity);
+ };
+
+ if (!no_init) that.init_attribute_facet();
+
+ return that;
+};
+
+IPA.attr_read_only_evaluator = function(spec) {
+
+ spec.name = spec.name || 'attr_read_only_evaluator';
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+ that.attribute = spec.attribute;
+
+ that.on_event = function(data) {
+
+ var old_state, record, rights, i, state;
+
+ old_state = that.state;
+ record = data.result.result;
+
+ // ignore loads without --rights
+ if (!record.attributelevelrights) return;
+
+ that.state = [];
+
+ rights = record.attributelevelrights[that.attribute];
+
+ if (!rights || rights.indexOf('w') === -1) {
+ that.state.push('read-only');
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+}; \ No newline at end of file
diff --git a/install/ui/src/freeipa/automember.js b/install/ui/src/freeipa/automember.js
new file mode 100644
index 000000000..6f8eba956
--- /dev/null
+++ b/install/ui/src/freeipa/automember.js
@@ -0,0 +1,679 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.automember = {};
+
+IPA.automember.entity = function(spec) {
+
+ //HACK: Automember takes_params is missing a cn attribute. This hack
+ //copies cn from mod command. Also it is set as pkey.
+ var pkey_attr = IPA.metadata.commands.automember_mod.takes_args[0];
+ pkey_attr.primary_key = true;
+ IPA.metadata.objects.automember.takes_params.push(pkey_attr);
+ IPA.metadata.objects.automember.primary_key = pkey_attr.name;
+
+ spec = spec || {};
+
+ spec.policies = spec.policies || [
+ IPA.facet_update_policy({
+ source_facet: 'usergrouprule',
+ dest_facet: 'searchgroup'
+ }),
+ IPA.facet_update_policy({
+ source_facet: 'hostgrouprule',
+ dest_facet: 'searchhostgroup'
+ })
+ ];
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+
+ that.entity_init();
+
+ that.builder.search_facet({
+ factory: IPA.automember.rule_search_facet,
+ name: 'searchgroup',
+ group_type: 'group',
+ label: IPA.messages.objects.automember.usergrouprules,
+ details_facet: 'usergrouprule',
+ pagination: false,
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ search_facet({
+ factory: IPA.automember.rule_search_facet,
+ name: 'searchhostgroup',
+ group_type: 'hostgroup',
+ label: IPA.messages.objects.automember.hostgrouprules,
+ details_facet: 'hostgrouprule',
+ pagination: false,
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ factory: IPA.automember.rule_details_facet,
+ name: 'usergrouprule',
+ group_type: 'group',
+ label: IPA.messages.objects.automember.usergrouprule,
+ disable_facet_tabs: true,
+ check_rights: false,
+ redirect_info: { tab: 'amgroup' }
+ }).
+ details_facet({
+ factory: IPA.automember.rule_details_facet,
+ name: 'hostgrouprule',
+ group_type: 'hostgroup',
+ label: IPA.messages.objects.automember.hostgrouprule,
+ disable_facet_tabs: true,
+ check_rights: false,
+ redirect_info: { tab: 'amhostgroup' }
+ }).
+ adder_dialog({
+ factory: IPA.automember.rule_adder_dialog,
+ title: IPA.messages.objects.automember.add_rule,
+ fields: [
+ {
+ type: 'entity_select',
+ name: 'cn',
+ other_entity: 'group',
+ other_field: 'cn'
+ }
+ ],
+ height: '300'
+ }).
+ deleter_dialog({
+ factory: IPA.automember.rule_deleter_dialog
+ });
+ };
+
+ return that;
+};
+
+
+IPA.automember.rule_search_facet = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.search_facet(spec);
+
+ that.group_type = spec.group_type;
+
+ var init = function() {
+
+ that.default_group_widget = IPA.automember.default_group_widget({
+ entity: that.entity,
+ group_type: that.group_type
+ });
+ };
+
+ that.refresh = function() {
+
+ that.search_facet_refresh();
+ that.default_group_widget.refresh();
+ };
+
+
+ that.get_records_command_name = function() {
+ return that.managed_entity.name + that.group_type+'_get_records';
+ };
+
+ that.get_search_command_name = function() {
+ var name = that.managed_entity.name + that.group_type + '_find';
+ if (that.pagination && !that.search_all_entries) {
+ name += '_pkeys';
+ }
+ return name;
+ };
+
+ that.create_get_records_command = function(pkeys, on_success, on_error) {
+
+ var batch = that.table_facet_create_get_records_command(pkeys, on_success, on_error);
+
+ for (var i=0; i<batch.commands.length; i++) {
+ var command = batch.commands[i];
+ command.set_option('type', that.group_type);
+ }
+
+ return batch;
+ };
+
+ that.create_refresh_command = function() {
+
+ var command = that.search_facet_create_refresh_command();
+
+ command.set_option('type', that.group_type);
+
+ return command;
+ };
+
+ that.create_content = function(container) {
+
+ var header = $('<div/>', {
+ 'class': 'automember-header'
+ }).appendTo(container);
+
+ var content = $('<div/>', {
+ 'class': 'automember-content'
+ }).appendTo(container);
+
+ that.default_group_widget.create(header);
+ that.table.create(content);
+
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.automember.rule_details_facet = function(spec) {
+
+ spec = spec || {};
+
+ spec.fields = [
+ {
+ name: 'cn',
+ widget: 'general.cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description',
+ widget: 'general.description'
+ },
+ {
+ type: 'automember_condition',
+ name: 'automemberinclusiveregex',
+ widget: 'inclusive.automemberinclusiveregex'
+ },
+ {
+ type: 'automember_condition',
+ name: 'automemberexclusiveregex',
+ widget: 'exclusive.automemberexclusiveregex'
+ }
+ ];
+
+ spec.widgets = [
+ {
+ type: 'details_table_section',
+ name: 'general',
+ label: IPA.messages.details.general,
+ widgets: [
+ {
+ name: 'cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ },
+ {
+ factory: IPA.collapsible_section,
+ name: 'inclusive',
+ label: IPA.messages.objects.automember.inclusive,
+ widgets: [
+ {
+ type: 'automember_condition',
+ name: 'automemberinclusiveregex',
+ group_type: spec.group_type,
+ add_command: 'add_condition',
+ remove_command: 'remove_condition',
+ adder_dialog: {
+ title: IPA.messages.objects.automember.add_condition,
+ fields: [
+ {
+ name: 'key',
+ type: 'select',
+ options: IPA.automember.get_condition_attributes(spec.group_type),
+ label: IPA.messages.objects.automember.attribute
+ },
+ {
+ name: 'automemberinclusiveregex',
+ label: IPA.messages.objects.automember.expression
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ factory: IPA.collapsible_section,
+ name: 'exclusive',
+ label: IPA.messages.objects.automember.exclusive,
+ widgets: [
+ {
+ type: 'automember_condition',
+ name: 'automemberexclusiveregex',
+ group_type: spec.group_type,
+ add_command: 'add_condition',
+ remove_command: 'remove_condition',
+ adder_dialog: {
+ title: IPA.messages.objects.automember.add_condition,
+ fields: [
+ {
+ name: 'key',
+ type: 'select',
+ options: IPA.automember.get_condition_attributes(spec.group_type),
+ label: IPA.messages.objects.automember.attribute
+ },
+ {
+ name: 'automemberexclusiveregex',
+ label: IPA.messages.objects.automember.expression
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ];
+
+ var that = IPA.details_facet(spec);
+
+ that.group_type = spec.group_type;
+
+ that.get_refresh_command_name = function() {
+ return that.entity.name+that.group_type+'_show';
+ };
+
+ that.create_refresh_command = function() {
+
+ var command = that.details_facet_create_refresh_command();
+ command.set_option('type', that.group_type);
+
+ return command;
+ };
+
+ that.create_update_command = function() {
+
+ var command = that.details_facet_create_update_command();
+ command.set_option('type', that.group_type);
+
+ return command;
+ };
+
+ return that;
+};
+
+IPA.automember.rule_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.show_edit_page = function (entity,result) {
+ var pkey_name = entity.metadata.primary_key;
+ var pkey = result[pkey_name];
+ if (pkey instanceof Array) {
+ pkey = pkey[0];
+ }
+ var facet = IPA.current_entity.get_facet();
+ var facetname = facet.group_type === 'group' ? 'usergrouprule' :
+ 'hostgrouprule';
+
+ IPA.nav.show_entity_page(that.entity, facetname, pkey);
+ };
+
+ that.reset = function() {
+
+ var field = that.fields.get_field('cn');
+ var facet = IPA.current_entity.get_facet();
+
+ field.widget.other_entity = IPA.get_entity(facet.group_type);
+
+ that.dialog_reset();
+ };
+
+ that.create_add_command = function(record) {
+
+ var facet = IPA.current_entity.get_facet();
+ var command = that.entity_adder_dialog_create_add_command(record);
+ command.name = that.entity.name+facet.group_type+'_show';
+ command.set_option('type', facet.group_type);
+
+ return command;
+ };
+
+
+ return that;
+};
+
+IPA.automember.rule_deleter_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.search_deleter_dialog(spec);
+
+ that.create_command = function() {
+
+ var facet = IPA.current_entity.get_facet();
+
+ var batch = that.search_deleter_dialog_create_command();
+
+ for (var i=0; i<batch.commands.length; i++) {
+ var command = batch.commands[i];
+ command.set_option('type', facet.group_type);
+ }
+
+ return batch;
+ };
+
+ return that;
+};
+
+IPA.automember.get_condition_attributes = function(type) {
+ var options = [];
+
+ if (type === 'group') {
+ options = IPA.metadata.objects.user.aciattrs;
+ } else if (type === 'hostgroup') {
+ options = IPA.metadata.objects.host.aciattrs;
+ }
+
+ var list_options = IPA.create_options(options);
+ return list_options;
+};
+
+IPA.automember.parse_condition_regex = function(regex) {
+
+ var delimeter_index = regex.indexOf('=');
+ var condition = {
+ condition: regex,
+ attribute: regex.substring(0, delimeter_index),
+ expression: regex.substring(delimeter_index+1)
+ };
+
+ return condition;
+};
+
+IPA.automember.condition_field = function(spec) {
+
+ spec = spec || {};
+ var that = IPA.field(spec);
+
+ that.attr_name = spec.attribute || that.name;
+
+ that.load = function(record) {
+
+ var regexes = record[that.attr_name];
+ that.values = [];
+
+ if (regexes) {
+ for (var i=0, j=0; i<regexes.length; i++) {
+ var condition = IPA.automember.parse_condition_regex(regexes[i]);
+ that.values.push(condition);
+ }
+ }
+
+ that.load_writable(record);
+ that.reset();
+ };
+
+ return that;
+};
+
+IPA.field_factories['automember_condition'] = IPA.automember.condition_field;
+
+IPA.automember.condition_widget = function(spec) {
+
+ spec = spec || {};
+
+ spec.columns = $.merge(spec.columns || [], [
+ {
+ name: 'attribute',
+ label: IPA.messages.objects.automember.attribute
+ },
+ {
+ name: 'expression',
+ label: IPA.messages.objects.automember.expression
+ }
+ ]);
+
+ spec.value_attribute = 'condition';
+
+ var that = IPA.attribute_table_widget(spec);
+
+ that.group_type = spec.group_type;
+
+ that.get_additional_options = function() {
+ return [
+ {
+ name: 'type',
+ value: that.group_type
+ }
+ ];
+ };
+
+ that.on_add = function(data) {
+
+ if (data.result.completed === 0) {
+ that.refresh_facet();
+ } else {
+ that.reload_facet(data);
+ }
+ };
+
+ that.on_remove = function(data) {
+
+ var results = data.result.results;
+
+ var i = results.length - 1;
+ while (i >= 0) {
+ if (results[i].completed === 1){
+ that.reload_facet({ result: results[i] });
+ return;
+ }
+ i--;
+ }
+
+ that.refresh_facet();
+ };
+
+ that.create_remove_command = function(values, on_success, on_error) {
+
+ var batch = IPA.batch_command({
+ name: 'automember_remove_condition',
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ var pkeys = that.get_pkeys();
+
+ for (var i=0; i<values.length; i++) {
+ var condition = IPA.automember.parse_condition_regex(values[i]);
+
+ var command = that.attribute_table_create_remove_command([]);
+ command.set_option('key', condition.attribute);
+ command.set_option(that.attribute_name, condition.expression);
+
+ batch.add_command(command);
+ }
+
+ return batch;
+ };
+
+ return that;
+};
+
+IPA.widget_factories['automember_condition'] = IPA.automember.condition_widget;
+
+IPA.automember.default_group_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+ that.group_type = spec.group_type;
+ that.group = '';
+
+ var init = function() {
+
+ that.group_select = IPA.entity_select_widget({
+ name: 'automemberdefaultgroup',
+ other_entity: that.group_type,
+ other_field: 'cn',
+ show_undo: false
+ });
+
+ that.group_select.value_changed.attach(that.group_changed);
+ };
+
+ that.get_group = function() {
+
+ var group = that.group_select.save();
+ group = group.length === 0 ? '' : group[0];
+ return group;
+ };
+
+ that.set_group = function(group) {
+
+ if (group === that.group) return;
+
+ that.group = group;
+ that.group_select.update([group]);
+ };
+
+ that.group_changed = function() {
+
+ var group = that.get_group();
+
+ if (group === that.group) return;
+
+ if (group === '') {
+ that.remove_default_group();
+ } else {
+ that.set_default_group(group);
+ }
+ };
+
+ that.load = function(data) {
+
+ var group = data.result.result.automemberdefaultgroup;
+
+ if (group) group = group[0];
+
+ if (!group || group.indexOf('cn=') === -1) {
+ group = '';
+ } else {
+ //extract from dn
+ var i1 = group.indexOf('=');
+ var i2 = group.indexOf(',');
+ if (i1 > -1 && i2 > -1) {
+ group = group.substring(i1 + 1,i2);
+ }
+ }
+
+ that.update(group);
+ };
+
+ that.update = function(group) {
+
+ group = group || '';
+
+ that.set_group(group);
+ };
+
+ that.create_command = function(method) {
+
+ method = 'default_group_' + method;
+ var command_name = that.entity.name + that.group_type + '_' + method;
+
+ var command = IPA.command({
+ name: command_name,
+ entity: that.entity.name,
+ method: method,
+ options: {
+ type: that.group_type
+ }
+ });
+
+ return command;
+ };
+
+ that.refresh = function() {
+
+ var command = that.create_command('show');
+ command.on_success = that.load;
+
+ command.execute();
+ };
+
+ that.remove_default_group = function() {
+
+ var command = that.create_command('remove');
+
+ command.on_success = function() {
+ that.update('');
+ };
+ command.on_error = that.refresh;
+
+ command.execute();
+ };
+
+ that.set_default_group = function(group) {
+
+ var command = that.create_command('set');
+ command.on_success = that.load;
+ command.on_error = that.refresh;
+ command.set_option('automemberdefaultgroup', group);
+
+ command.execute();
+ };
+
+
+ that.create = function(container) {
+
+ var title = that.get_title();
+
+ var default_group = $('<div />', {
+ 'class': 'default_group'
+ }).appendTo(container);
+
+ that.header = $('<h2/>', {
+ name: 'header',
+ text: title,
+ title: title
+ }).appendTo(default_group);
+
+ that.group_select.create(default_group);
+ };
+
+ that.get_title = function() {
+ if (that.group_type === 'group') {
+ return IPA.messages.objects.automember.default_user_group;
+ } else {
+ return IPA.messages.objects.automember.default_host_group;
+ }
+ };
+
+ init();
+
+ return that;
+};
+
+
+IPA.register('automember', IPA.automember.entity); \ No newline at end of file
diff --git a/install/ui/src/freeipa/automount.js b/install/ui/src/freeipa/automount.js
new file mode 100644
index 000000000..3a4491d8b
--- /dev/null
+++ b/install/ui/src/freeipa/automount.js
@@ -0,0 +1,354 @@
+/*jsl:import ipa.js */
+/*jsl:import search.js */
+
+/* Authors:
+ * Adam Young <ayoung@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.automount = {};
+
+IPA.automount.location_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups([ 'automountmap', 'settings' ]).
+ search_facet({
+ title: IPA.metadata.objects.automountlocation.label,
+ columns:['cn']
+ }).
+ nested_search_facet({
+ facet_group: 'automountmap',
+ nested_entity: 'automountmap',
+ label: IPA.metadata.objects.automountmap.label,
+ tab_label: IPA.metadata.objects.automountmap.label,
+ name: 'maps',
+ columns: [ 'automountmapname' ]
+ }).
+ details_facet({
+ sections:[
+ {
+ name: 'identity',
+ label: IPA.messages.details.identity,
+ fields: [ 'cn' ]
+ }
+ ]
+ }).
+ adder_dialog({
+ fields: [ 'cn' ]
+ });
+ };
+
+ return that;
+};
+
+IPA.automount.map_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.containing_entity('automountlocation').
+ facet_groups([ 'automountkey', 'settings' ]).
+ nested_search_facet({
+ factory: IPA.automount.key_search_facet,
+ facet_group: 'automountkey',
+ nested_entity: 'automountkey',
+ search_all_entries: true,
+ label: IPA.metadata.objects.automountkey.label,
+ tab_label: IPA.metadata.objects.automountkey.label,
+ name: 'keys',
+ columns: [
+ {
+ factory: IPA.automount_key_column,
+ name: 'automountkey',
+ label: IPA.get_entity_param('automountkey', 'automountkey').label
+ },
+ 'automountinformation'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'identity',
+ label: IPA.messages.details.identity,
+ fields: [
+ 'automountmapname',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ adder_dialog({
+ factory: IPA.automountmap_adder_dialog,
+ sections: [
+ {
+ name: 'general',
+ fields: [
+ {
+ type: 'radio',
+ name: 'method',
+ enabled: false, //don't use value in add command
+ label: IPA.messages.objects.automountmap.map_type,
+ options: [
+ {
+ value: 'add',
+ label: IPA.messages.objects.automountmap.direct
+ },
+ {
+ value: 'add_indirect',
+ label: IPA.messages.objects.automountmap.indirect
+ }
+ ]
+ },
+ 'automountmapname',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ },
+ {
+ name: 'indirect',
+ fields: [
+ {
+ name: 'key',
+ label: IPA.get_command_option(
+ 'automountmap_add_indirect', 'key').label
+ },
+ {
+ name: 'parentmap',
+ label: IPA.get_command_option(
+ 'automountmap_add_indirect', 'parentmap').label
+ }
+ ]
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.automount.key_entity = function(spec) {
+
+ spec = spec || {};
+
+ spec.policies = spec.policies || [
+ IPA.facet_update_policy({
+ source_facet: 'details',
+ dest_entity: 'automountmap',
+ dest_facet: 'keys'
+ })
+ ];
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.containing_entity('automountmap').
+ details_facet({
+ factory: IPA.automount.key_details_facet,
+ sections: [
+ {
+ name:'identity',
+ label: IPA.messages.details.identity,
+ fields: [
+ {
+ name: 'automountkey',
+ read_only: true
+ },
+ 'automountinformation'
+ ]
+ }
+ ],
+ disable_breadcrumb: false
+ }).
+ adder_dialog({
+ show_edit_page : function(entity, result){
+ var key = result.automountkey[0];
+ var info = result.automountinformation[0];
+ var state = IPA.nav.get_path_state(entity.name);
+ state[entity.name + '-facet'] = 'default';
+ state[entity.name + '-info'] = info;
+ state[entity.name + '-pkey'] = key;
+ IPA.nav.push_state(state);
+ return false;
+ },
+ fields:['automountkey','automountinformation']
+ });
+ };
+
+ return that;
+};
+
+IPA.automount.key_details_facet = function(spec) {
+
+ var that = IPA.details_facet(spec);
+
+ that.create_update_command = function() {
+
+ var command = that.details_facet_create_update_command();
+
+ command.args.pop();
+
+ var key = IPA.nav.get_state(that.entity.name + '-pkey');
+ var info = IPA.nav.get_state(that.entity.name + '-info');
+
+ command.options.newautomountinformation = command.options.automountinformation;
+ command.options.automountkey = key;
+ command.options.automountinformation = info;
+
+ return command;
+ };
+
+ that.create_refresh_command = function() {
+
+ var command = that.details_facet_create_refresh_command();
+
+ command.args.pop();
+
+ var key = IPA.nav.get_state(that.entity.name + '-pkey');
+ var info = IPA.nav.get_state(that.entity.name + '-info');
+
+ command.options.automountkey = key;
+ command.options.automountinformation = info;
+
+ return command;
+ };
+
+ return that;
+};
+
+IPA.automount_key_column = function(spec) {
+
+ var that = IPA.column(spec);
+
+ that.setup = function(container, record) {
+
+ container.empty();
+
+ var key = record.automountkey;
+ if (key instanceof Array) key = key[0];
+ var info = record.automountinformation;
+ if (info instanceof Array) info = info[0];
+
+ $('<a/>', {
+ href: '#'+key,
+ text: key,
+ click: function() {
+ var state = IPA.nav.get_path_state(that.entity.name);
+ state[that.entity.name + '-facet'] = 'default';
+ state[that.entity.name + '-info'] = info;
+ state[that.entity.name + '-pkey'] = key;
+ IPA.nav.push_state(state);
+ return false;
+ }
+ }).appendTo(container);
+
+ };
+
+ return that;
+};
+
+IPA.automountmap_adder_dialog = function(spec) {
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.create = function() {
+ that.entity_adder_dialog_create();
+
+ var method_widget = that.widgets.get_widget('general.method');
+ var indirect_section = that.widgets.get_widget('indirect');
+ var key_field = that.fields.get_field('key');
+ var parentmap_field = that.fields.get_field('parentmap');
+
+ var direct_input = $('input[value="add"]', method_widget.container);
+ direct_input.change(function() {
+ that.method = 'add';
+
+ key_field.set_enabled(false);
+ parentmap_field.set_enabled(false);
+
+ key_field.set_required(false);
+ indirect_section.set_visible(false);
+ });
+
+ var indirect_input = $('input[value="add_indirect"]', method_widget.container);
+ indirect_input.change(function() {
+ that.method = 'add_indirect';
+
+ key_field.set_enabled(true);
+ parentmap_field.set_enabled(true);
+
+ key_field.set_required(true);
+ indirect_section.set_visible(true);
+ });
+
+ direct_input.click();
+ };
+
+ that.reset = function() {
+ that.dialog_reset();
+
+ var method_widget = that.widgets.get_widget('general.method');
+
+ var direct_input = $('input[value="add"]', method_widget.container);
+ direct_input.click();
+ };
+
+ return that;
+};
+
+IPA.automount.key_search_facet = function(spec) {
+
+ var that = IPA.nested_search_facet(spec);
+
+ that.get_selected_values = function() {
+
+ var values = [];
+
+ $('input[name="description"]:checked', that.table.tbody).each(function() {
+ var value = {};
+ $('div', $(this).parent().parent()).each(function() {
+ var div = $(this);
+ var name = div.attr('name');
+ value[name] = div.text();
+ });
+ values.push(value);
+ });
+
+ return values;
+ };
+
+ return that;
+};
+
+IPA.register('automountlocation', IPA.automount.location_entity);
+IPA.register('automountmap', IPA.automount.map_entity);
+IPA.register('automountkey', IPA.automount.key_entity);
diff --git a/install/ui/src/freeipa/certificate.js b/install/ui/src/freeipa/certificate.js
new file mode 100755
index 000000000..782033db1
--- /dev/null
+++ b/install/ui/src/freeipa/certificate.js
@@ -0,0 +1,924 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+IPA.cert = {};
+
+IPA.cert.BEGIN_CERTIFICATE = '-----BEGIN CERTIFICATE-----';
+IPA.cert.END_CERTIFICATE = '-----END CERTIFICATE-----';
+
+IPA.cert.BEGIN_CERTIFICATE_REQUEST = '-----BEGIN CERTIFICATE REQUEST-----';
+IPA.cert.END_CERTIFICATE_REQUEST = '-----END CERTIFICATE REQUEST-----';
+
+/*
+ * Pre-compiled regular expression to match a PEM cert.
+ *
+ * regexp group 1: entire canonical cert (delimiters plus base64)
+ * regexp group 2: base64 data inside PEM delimiters
+ */
+IPA.cert.PEM_CERT_REGEXP = RegExp('(-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----)');
+
+/*
+ * Pre-compiled regular expression to match a CSR (Certificate Signing Request).
+ * The delimiter "CERTIFICATE REQUEST" is the cononical standard, however some legacy
+ * software will produce a delimiter with "NEW" in it, i.e. "NEW CERTIFICATE REQUEST"
+ * This regexp will work with either form.
+ *
+ * regexp group 1: entire canonical CSR (delimiters plus base64)
+ * regexp group 2: base64 data inside canonical CSR delimiters
+ * regexp group 3: entire legacy CSR (delimiters plus base64)
+ * regexp group 4: base64 data inside legacy CSR delimiters
+ */
+IPA.cert.PEM_CSR_REGEXP = RegExp('(-----BEGIN CERTIFICATE REQUEST-----([^-]*)-----END CERTIFICATE REQUEST-----)|(-----BEGIN NEW CERTIFICATE REQUEST-----([^-]*)-----END NEW CERTIFICATE REQUEST-----)');
+
+IPA.cert.CERTIFICATE_STATUS_MISSING = 0;
+IPA.cert.CERTIFICATE_STATUS_VALID = 1;
+IPA.cert.CERTIFICATE_STATUS_REVOKED = 2;
+
+IPA.cert.CRL_REASON = [
+ 'unspecified',
+ 'key_compromise',
+ 'ca_compromise',
+ 'affiliation_changed',
+ 'superseded',
+ 'cessation_of_operation',
+ 'certificate_hold',
+ null,
+ 'remove_from_crl',
+ 'privilege_withdrawn',
+ 'aa_compromise'
+];
+
+IPA.cert.parse_dn = function(dn) {
+
+ var result = {};
+ if (!dn) return result;
+
+ // TODO: Use proper LDAP DN parser
+ var rdns = dn.split(',');
+ for (var i=0; i<rdns.length; i++) {
+ var rdn = rdns[i];
+ if (!rdn) continue;
+
+ var parts = rdn.split('=');
+ var name = $.trim(parts[0].toLowerCase());
+ var value = $.trim(parts[1]);
+
+ var old_value = result[name];
+ if (!old_value) {
+ result[name] = value;
+ } else if (typeof old_value == "string") {
+ result[name] = [old_value, value];
+ } else {
+ result[name].push(value);
+ }
+ }
+
+ return result;
+};
+
+IPA.cert.pem_format_base64 = function(text) {
+ /*
+ * Input is assumed to be base64 possibly with embedded whitespace.
+ * Format the base64 text such that it conforms to PEM, which is a
+ * sequence of 64 character lines, except for the last line which
+ * may be less than 64 characters. The last line does NOT have a
+ * new line appended to it.
+ */
+ var formatted = "";
+
+ /* Strip out any whitespace including line endings */
+ text = text.replace(/\s*/g,"");
+
+ /*
+ * Break up into lines with 64 chars each.
+ * Do not add a newline to final line.
+ */
+ for (var i = 0; i < text.length; i+=64) {
+ formatted += text.substring(i, i+64);
+ if (i+64 < text.length) {
+ formatted += "\n";
+ }
+ }
+ return (formatted);
+};
+
+IPA.cert.pem_cert_format = function(text) {
+ /*
+ * Input is assumed to be either PEM formated data or the
+ * base64 encoding of DER binary certificate data. Return data
+ * in PEM format. The function checks if the input text is PEM
+ * formatted, if so it just returns the input text. Otherwise
+ * the input is treated as base64 which is formatted to be PEM>
+ */
+
+ /*
+ * Does the text already have the PEM delimiters?
+ * If so just return the text unmodified.
+ */
+ if (text.match(IPA.cert.PEM_CERT_REGEXP)) {
+ return text;
+ }
+ /* No PEM delimiters so format the base64 & add the delimiters. */
+ return IPA.cert.BEGIN_CERTIFICATE + "\n" +
+ IPA.cert.pem_format_base64(text) + "\n" +
+ IPA.cert.END_CERTIFICATE;
+};
+
+IPA.cert.pem_csr_format = function(text) {
+ /*
+ * Input is assumed to be either PEM formated data or the base64
+ * encoding of DER binary certificate request (csr) data. Return
+ * data in PEM format. The function checks if the input text is
+ * PEM formatted, if so it just returns the input text. Otherwise
+ * the input is treated as base64 which is formatted to be PEM>
+ */
+
+ /*
+ * Does the text already have the PEM delimiters?
+ * If so just return the text unmodified.
+ */
+ if (text.match(IPA.cert.PEM_CSR_REGEXP)) {
+ return text;
+ }
+
+ /* No PEM delimiters so format the base64 & add the delimiters. */
+ return IPA.cert.BEGIN_CERTIFICATE_REQUEST + "\n" +
+ IPA.cert.pem_format_base64(text) + "\n" +
+ IPA.cert.END_CERTIFICATE_REQUEST;
+};
+
+IPA.cert.download_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.width = spec.width || 500;
+ that.height = spec.height || 380;
+ that.add_pem_delimiters = typeof spec.add_pem_delimiters == 'undefined' ? true : spec.add_pem_delimiters;
+
+ that.certificate = spec.certificate || '';
+
+ that.create_button({
+ name: 'close',
+ label: IPA.messages.buttons.close,
+ click: function() {
+ that.close();
+ }
+ });
+
+ that.create = function() {
+ var textarea = $('<textarea/>', {
+ 'class': 'certificate',
+ readonly: 'yes'
+ }).appendTo(that.container);
+
+ var certificate = that.certificate;
+
+ if (that.add_pem_delimiters) {
+ certificate = IPA.cert.pem_cert_format(that.certificate);
+ }
+
+ textarea.val(certificate);
+ };
+
+ return that;
+};
+
+IPA.cert.revoke_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.width = spec.width || 500;
+ spec.ok_label = spec.ok_label || IPA.messages.buttons.revoke;
+
+ var that = IPA.confirm_dialog(spec);
+
+ that.get_reason = function() {
+ return that.select.val();
+ };
+
+ that.create = function() {
+
+ var table = $('<table/>').appendTo(that.container);
+
+ var tr = $('<tr/>').appendTo(table);
+
+ var td = $('<td/>').appendTo(tr);
+ td.append(IPA.messages.objects.cert.note+':');
+
+ td = $('<td/>').appendTo(tr);
+ td.append(IPA.messages.objects.cert.revoke_confirmation);
+
+ tr = $('<tr/>').appendTo(table);
+
+ td = $('<td/>').appendTo(tr);
+ td.append(IPA.messages.objects.cert.reason+':');
+
+ td = $('<td/>').appendTo(tr);
+
+ that.select = $('<select/>').appendTo(td);
+ for (var i=0; i<IPA.cert.CRL_REASON.length; i++) {
+ var reason = IPA.cert.CRL_REASON[i];
+ if (!reason) continue;
+ $('<option/>', {
+ 'value': i,
+ 'html': IPA.messages.objects.cert[reason]
+ }).appendTo(that.select);
+ }
+ };
+
+ return that;
+};
+
+IPA.cert.view_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.width = spec.width || 600;
+ that.height = spec.height || 500;
+
+ that.subject = IPA.cert.parse_dn(spec.certificate.subject);
+ that.serial_number = spec.certificate.serial_number || '';
+ that.serial_number_hex = spec.certificate.serial_number_hex || '';
+ that.issuer = IPA.cert.parse_dn(spec.certificate.issuer);
+ that.issued_on = spec.certificate.valid_not_before || '';
+ that.expires_on = spec.certificate.valid_not_after || '';
+ that.md5_fingerprint = spec.certificate.md5_fingerprint || '';
+ that.sha1_fingerprint = spec.certificate.sha1_fingerprint || '';
+
+ that.create_button({
+ name: 'close',
+ label: IPA.messages.buttons.close,
+ click: function() {
+ that.close();
+ }
+ });
+
+ that.create = function() {
+
+ var table = $('<table/>').appendTo(that.container);
+
+ var tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>'+IPA.messages.objects.cert.issued_to+'</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.common_name+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.subject.cn
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.organization+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.subject.o
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.organizational_unit+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.subject.ou
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.serial_number+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.serial_number
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.serial_number_hex+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.serial_number_hex
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>'+IPA.messages.objects.cert.issued_by+'</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.common_name+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.issuer.cn
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.organization+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.issuer.o
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.organizational_unit+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.issuer.ou
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>'+IPA.messages.objects.cert.validity+'</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.issued_on+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.issued_on
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.expires_on+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.expires_on
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td/>', {
+ 'colspan': 2,
+ 'html': '<h3>'+IPA.messages.objects.cert.fingerprints+'</h3>'
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.sha1_fingerprint+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.sha1_fingerprint
+ }).appendTo(tr);
+
+ tr = $('<tr/>').appendTo(table);
+ $('<td>'+IPA.messages.objects.cert.md5_fingerprint+':</td>').appendTo(tr);
+ $('<td/>', {
+ text: that.md5_fingerprint
+ }).appendTo(tr);
+ };
+
+ return that;
+};
+
+IPA.cert.request_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.width = spec.width || 600;
+ that.height = spec.height || 480;
+ that.message = spec.message;
+
+ that.request = spec.request;
+
+ that.create_button({
+ name: 'issue',
+ label: IPA.messages.buttons.issue,
+ click: function() {
+ var values = {};
+ var request = $.trim(that.textarea.val());
+ values.request = IPA.cert.pem_csr_format(request);
+ if (that.request) {
+ that.request(values);
+ }
+ that.close();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ that.create = function() {
+ that.container.append(that.message);
+
+ that.textarea = $('<textarea/>', {
+ 'class': 'certificate'
+ }).appendTo(that.container);
+ };
+
+ return that;
+};
+
+IPA.cert.loader = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+ that.get_pkey = spec.get_pkey;
+ that.get_name = spec.get_name;
+ that.get_principal = spec.get_principal;
+ that.get_hostname = spec.get_hostname;
+
+ that.load = function (result) {
+
+ var certificate = {
+ issuer: result.issuer,
+ certificate: result.certificate,
+ md5_fingerprint: result.md5_fingerprint,
+ revocation_reason: result.revocation_reason,
+ serial_number: result.serial_number,
+ serial_number_hex: result.serial_number_hex,
+ sha1_fingerprint: result.sha1_fingerprint,
+ subject: result.subject,
+ valid_not_after: result.valid_not_after,
+ valid_not_before: result.valid_not_before
+ };
+
+ if (that.get_entity_certificate) {
+ certificate.certificate = that.get_entity_certificate(result);
+ } else if (!certificate.certificate && result.usercertificate) {
+ // default method of storing certificate for object commands
+ // which include certificate
+ certificate.certificate = result.usercertificate[0].__base64__;
+ }
+
+ var info = {};
+
+ if (that.get_pkey) info.pkey = that.get_pkey(result);
+ if (that.get_name) info.name = that.get_name(result);
+ if (that.get_principal) info.principal = that.get_principal(result);
+ if (that.get_hostname) info.hostname = that.get_hostname(result);
+
+ certificate.entity_info = info;
+
+ return certificate;
+ };
+
+ return that;
+};
+
+IPA.cert.load_policy = function(spec) {
+
+ spec = spec || {};
+ spec.loader = spec.loader || {
+ factory: IPA.cert.loader,
+ get_pkey: spec.get_pkey,
+ get_name: spec.get_name,
+ get_principal: spec.get_principal,
+ get_hostname: spec.get_hostname
+ };
+
+ var that = IPA.facet_policy();
+ that.loader = IPA.build(spec.loader);
+
+ that.post_load = function(data) {
+
+ // update cert info in facet (show at least something)
+ var certificate = that.loader.load(data.result.result);
+
+ //store cert directly to facet. FIXME: introduce concept of models
+ that.container.certificate = certificate;
+ that.notify_loaded();
+
+ // initialize another load of certificate because current entity
+ // show commands don't contain revocation_reason so previous data
+ // might be slightly incorrect
+ if (certificate && certificate.certificate && !IPA.cert.is_selfsign()) {
+ that.load_revocation_reason(certificate.serial_number);
+ }
+ };
+
+ that.load_revocation_reason = function(serial_number) {
+ IPA.command({
+ entity: 'cert',
+ method: 'show',
+ args: [serial_number],
+ on_success: function(data, text_status, xhr) {
+ var cert = that.container.certificate;
+ cert.revocation_reason = data.result.result.revocation_reason;
+ that.notify_loaded();
+ }
+ }).execute();
+ };
+
+ that.notify_loaded = function() {
+ if (that.container.certificate_loaded) {
+ that.container.certificate_loaded.notify(
+ [that.container.certificate], that.container);
+ }
+ };
+
+ return that;
+};
+
+IPA.cert.is_selfsign = function() {
+ return IPA.env.ra_plugin == 'selfsign';
+};
+
+IPA.cert.view_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'view_cert';
+ spec.label = spec.label || IPA.messages.buttons.view;
+ spec.enable_cond = spec.enable_cond || ['has_certificate'];
+
+ var that = IPA.action(spec);
+ that.entity_label = spec.entity_label;
+
+ that.execute_action = function(facet) {
+
+ var certificate = facet.certificate;
+ if (!certificate) that.facet.refresh();
+
+ var entity_label = that.entity_label || facet.entity.metadata.label_singular;
+ var entity_name = certificate.entity_info.name;
+
+ var title = IPA.messages.objects.cert.view_certificate;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', entity_name);
+
+ var dialog = IPA.cert.view_dialog({
+ title: title,
+ certificate: certificate
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.cert.get_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'get_cert';
+ spec.label = spec.label || IPA.messages.buttons.get;
+ spec.enable_cond = spec.enable_cond || ['has_certificate'];
+
+ var that = IPA.action(spec);
+ that.entity_label = spec.entity_label;
+
+ that.execute_action = function(facet) {
+
+ var certificate = facet.certificate;
+ if (!certificate) that.facet.refresh();
+
+ var entity_label = that.entity_label || facet.entity.metadata.label_singular;
+ var entity_name = certificate.entity_info.name;
+
+ var title = IPA.messages.objects.cert.view_certificate;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', entity_name);
+
+ var dialog = IPA.cert.download_dialog({
+ title: title,
+ certificate: certificate.certificate
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.cert.request_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'request_cert';
+ spec.label = spec.label || IPA.messages.objects.cert.new_certificate;
+
+ var that = IPA.action(spec);
+ that.entity_label = spec.entity_label;
+
+ that.execute_action = function(facet) {
+
+ var certificate = facet.certificate;
+ if (!certificate) facet.refresh();
+
+ var entity_principal = certificate.entity_info.principal;
+ var entity_label = that.entity_label || facet.entity.metadata.label_singular;
+ var entity_name = certificate.entity_info.name;
+ var hostname = certificate.entity_info.hostname;
+
+ var title = IPA.messages.objects.cert.issue_certificate;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', entity_name);
+
+ var request_message = IPA.messages.objects.cert.request_message;
+ request_message = request_message.replace(/\$\{hostname\}/g, hostname);
+ request_message = request_message.replace(/\$\{realm\}/g, IPA.env.realm);
+
+ var dialog = IPA.cert.request_dialog({
+ title: title,
+ message: request_message,
+ request: function(values) {
+
+ IPA.command({
+ entity: 'cert',
+ method: 'request',
+ args: [values.request],
+ options: {
+ 'principal': entity_principal
+ },
+ on_success: function(data, text_status, xhr) {
+ facet.refresh();
+ IPA.notify_success(IPA.messages.objects.cert.requested);
+ }
+ }).execute();
+ }
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.cert.revoke_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'revoke_cert';
+ spec.label = spec.label || IPA.messages.buttons.revoke;
+ spec.enable_cond = spec.enable_cond || ['has_certificate'];
+ spec.disable_cond = spec.disable_cond || ['certificate_revoked'];
+ spec.hide_cond = spec.hide_cond || ['selfsign'];
+ spec.confirm_dialog = spec.confirm_dialog || IPA.cert.revoke_dialog;
+ spec.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : true;
+
+ var that = IPA.action(spec);
+ that.entity_label = spec.entity_label;
+ that.confirm_msg = spec.request_message;
+
+ that.update_confirm_dialog = function(facet) {
+
+ var certificate = facet.certificate;
+
+ var entity_label = that.entity_label || facet.entity.metadata.label_singular;
+ var entity_name = certificate.entity_info.name;
+
+ var title = IPA.messages.objects.cert.revoke_certificate;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', entity_name);
+
+ that.dialog.title = title;
+ that.dialog.message = that.get_confirm_message(facet);
+ };
+
+ that.execute_action = function(facet) {
+
+ var certificate = facet.certificate;
+
+ IPA.command({
+ entity: 'cert',
+ method: 'revoke',
+ args: [certificate.serial_number],
+ options: {
+ 'revocation_reason': that.dialog.get_reason()
+ },
+ on_success: function(data, text_status, xhr) {
+ facet.refresh();
+ IPA.notify_success(IPA.messages.objects.cert.revoked);
+ }
+ }).execute();
+ };
+
+ return that;
+};
+
+IPA.cert.restore_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'restore_cert';
+ spec.label = spec.label || IPA.messages.buttons.restore;
+ spec.enable_cond = spec.enable_cond || ['has_certificate', 'certificate_hold'];
+ spec.hide_cond = spec.hide_cond || ['selfsign'];
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.objects.cert.restore_confirmation;
+ spec.confirm_dialog = spec.confirm_dialog || {
+ factory: IPA.confirm_dialog,
+ ok_label: IPA.messages.buttons.restore
+ };
+ spec.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : true;
+
+ var that = IPA.action(spec);
+ that.entity_label = spec.entity_label;
+
+ that.update_confirm_dialog = function(facet) {
+
+ var certificate = facet.certificate;
+
+ var entity_label = that.entity_label || facet.entity.metadata.label_singular;
+ var entity_name = certificate.entity_info.name;
+
+ var title = IPA.messages.objects.cert.restore_certificate;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', entity_name);
+
+ that.dialog.title = title;
+ that.dialog.message = that.get_confirm_message(facet);
+ };
+
+ that.execute_action = function(facet) {
+
+ var certificate = facet.certificate;
+
+ IPA.command({
+ entity: 'cert',
+ method: 'remove_hold',
+ args: [certificate.serial_number],
+ on_success: function(data, text_status, xhr) {
+ facet.refresh();
+ IPA.notify_success(IPA.messages.objects.cert.restored);
+ }
+ }).execute();
+ };
+
+ return that;
+};
+
+IPA.cert.certificate_evaluator = function(spec) {
+
+ spec.name = spec.name || 'has_certificate_evaluator';
+ spec.event = spec.event || 'certificate_loaded';
+
+ var that = IPA.state_evaluator(spec);
+
+ that.on_event = function(certificate) {
+
+ var old_state, record, state, value, loaded_value;
+
+ old_state = that.state;
+ that.state = [];
+
+ if (certificate && certificate.certificate) {
+ that.state.push('has_certificate');
+
+ if (certificate.revocation_reason !== undefined) {
+ that.state.push('certificate_revoked');
+
+ if (certificate.revocation_reason === 6) {
+ that.state.push('certificate_hold');
+ }
+ }
+ }
+
+ if (IPA.cert.is_selfsign()) {
+ that.state.push('selfsign');
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+
+IPA.cert.status_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.status_valid = $('<div/>', {
+ name: 'certificate-valid',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/check-icon.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(that.status_valid);
+
+ var content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(that.status_valid);
+
+ content_div.append('<b>'+IPA.messages.objects.cert.valid+'</b>');
+
+ that.status_revoked = $('<div/>', {
+ name: 'certificate-revoked',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/caution-icon.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(that.status_revoked);
+
+ content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(that.status_revoked);
+
+ content_div.append('<b>'+IPA.messages.objects.cert.revoked+'</b>');
+ content_div.append(' ');
+ that.revocation_reason = $('<span/>', {
+ 'name': 'revocation_reason'
+ }).appendTo(content_div);
+
+ that.status_missing = $('<div/>', {
+ name: 'certificate-missing',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/caution-icon.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(that.status_missing);
+
+ content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(that.status_missing);
+
+ content_div.append('<b>'+IPA.messages.objects.cert.missing+'</b>');
+ };
+
+ that.update = function(certificate) {
+
+ certificate = certificate || {};
+
+ var selfsign = IPA.cert.is_selfsign();
+ var has_certificate = certificate.certificate;
+ var revoked = certificate.revocation_reason !== undefined;
+ var status = IPA.cert.CERTIFICATE_STATUS_MISSING;
+
+ if (has_certificate && (selfsign || !revoked)) {
+ status = IPA.cert.CERTIFICATE_STATUS_VALID;
+ } else if (has_certificate) {
+ status = IPA.cert.CERTIFICATE_STATUS_REVOKED;
+ }
+ that.set_status(status, certificate.revocation_reason);
+ };
+
+ that.clear = function() {
+ that.status_valid.css('display', 'none');
+ that.status_missing.css('display', 'none');
+ that.status_revoked.css('display', 'none');
+ that.revocation_reason.text('');
+ };
+
+ that.set_status = function(status, revocation_reason) {
+ that.status_valid.css('display', status === IPA.cert.CERTIFICATE_STATUS_VALID ? '' : 'none');
+ that.status_missing.css('display', status === IPA.cert.CERTIFICATE_STATUS_MISSING ? '' : 'none');
+
+ if (!IPA.cert.is_selfsign()) {
+ that.status_revoked.css('display', status === IPA.cert.CERTIFICATE_STATUS_REVOKED ? '' : 'none');
+
+ var reason = IPA.cert.CRL_REASON[revocation_reason];
+ that.revocation_reason.html(revocation_reason === undefined || reason === null ? '' : IPA.messages.objects.cert[reason]);
+ }
+ };
+
+ return that;
+};
+
+IPA.cert.status_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+ that.registered = false;
+
+ that.load = function(result) {
+ that.register_listener();
+ that.reset();
+ };
+
+ that.set_certificate = function(certificate) {
+ that.values = certificate;
+ that.reset();
+ };
+
+ that.register_listener = function() {
+ if (!that.registered) {
+ that.registered = true;
+ that.container.certificate_loaded.attach(that.set_certificate);
+ }
+ };
+
+ return that;
+};
+
+IPA.widget_factories['certificate_status'] = IPA.cert.status_widget;
+IPA.field_factories['certificate_status'] = IPA.cert.status_field; \ No newline at end of file
diff --git a/install/ui/src/freeipa/details.js b/install/ui/src/freeipa/details.js
new file mode 100644
index 000000000..c3e84e434
--- /dev/null
+++ b/install/ui/src/freeipa/details.js
@@ -0,0 +1,1239 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* IPA Object Details - populating definiton lists from entry data */
+
+/* REQUIRES: ipa.js */
+
+IPA.expanded_icon = 'expanded-icon';
+IPA.collapsed_icon = 'collapsed-icon';
+
+IPA.details_builder = function(spec) {
+
+ var that = {};
+
+ that.widgets = spec.container.widgets;
+ that.fields = spec.container.fields;
+
+ that.widget_builder = spec.widget_builder || IPA.widget_builder();
+ that.field_builder = spec.field_builder || IPA.field_builder();
+ that.section_builder = spec.section_builder || IPA.section_builder();
+
+ that.build_widget = function(spec) {
+
+ if (!spec) return;
+
+ that.widget_builder.build_widget(spec, that.widgets);
+ };
+
+ that.build_widgets = function(specs) {
+
+ if (!specs) return;
+
+ that.widget_builder.build_widgets(specs, that.widgets);
+ };
+
+ that.build_field = function(spec) {
+
+ if (!spec) return;
+
+ that.field_builder.build_field(spec, that.fields);
+ };
+
+ that.build_fields = function(specs) {
+
+ if (!specs) return;
+
+ that.field_builder.build_fields(specs, that.fields);
+ };
+
+ that.build_sections = function(specs) {
+
+ if (!specs) return;
+
+ that.section_builder.build_sections(specs);
+ };
+
+ that.build = function(spec) {
+
+ if (spec.sections) {
+ that.build_sections(spec.sections);
+
+ } else if (spec.fields && !spec.widgets) {
+
+ var sections = [
+ {
+ fields: spec.fields
+ }
+ ];
+
+ that.build_sections(sections);
+
+ } else {
+ that.build_fields(spec.fields);
+ that.build_widgets(spec.widgets);
+ }
+ };
+
+ return that;
+};
+
+IPA.section_builder = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.container = spec.container;
+ that.section_factory = spec.section_factory || IPA.details_table_section;
+
+ that.field_builder = spec.field_builder;
+ that.widget_builder = spec.widget_builder;
+
+ that.build_sections = function(sections) {
+
+ if(!sections) return;
+
+ for (var i=0; i < sections.length; i++) {
+ that.build_section(sections[i], i);
+ }
+ };
+
+ that.build_section = function(section_spec, index) {
+ section_spec.entity = that.container.entity;
+ section_spec.facet = that.container;
+
+ if (!section_spec.label && section_spec.name && that.container.entity) {
+ var obj_messages = IPA.messages.objects[that.container.entity.name];
+ section_spec.label = obj_messages[section_spec.name];
+ }
+
+ if(!section_spec.name) section_spec.name = 'section'+index;
+
+ section_spec.factory = section_spec.factory || that.section_factory;
+ var section = section_spec.factory(section_spec);
+
+ that.container.widgets.add_widget(section);
+
+ that.create_fields(section, section_spec.fields);
+ };
+
+ that.create_fields = function(section, fields_spec) {
+
+ for (var i=0; i < fields_spec.length; i++) {
+ that.create_field(section, fields_spec[i]);
+ }
+ };
+
+ that.create_field = function(section, field_spec) {
+
+ var widget = that.widget_builder.build_widget(field_spec, section.widgets);
+
+ //spec.factory refers to widget factory
+ if(field_spec.factory) delete field_spec.factory;
+
+ var field = that.field_builder.build_field(field_spec, that.container.fields);
+
+ if(widget && field) {
+ field.widget_name = section.name+'.'+widget.name;
+ }
+ };
+
+ return that;
+};
+
+IPA.facet_policy = function() {
+
+ var that = {};
+
+ that.init = function() {
+ };
+
+ that.post_create = function() {
+ };
+
+ that.post_load = function(data) {
+ };
+
+ return that;
+};
+
+IPA.facet_policies = function(spec) {
+
+ var that = {};
+
+ that.container = spec.container;
+ that.policies = [];
+
+ that.add_policy = function(policy) {
+
+ policy.container = that.container;
+ that.policies.push(policy);
+ };
+
+ that.add_policies = function(policies) {
+
+ if (!policies) return;
+
+ for (var i=0; i<policies.length; i++) {
+ that.add_policy(policies[i]);
+ }
+ };
+
+ that.init = function() {
+
+ for (var i=0; i<that.policies.length; i++) {
+ that.policies[i].init();
+ }
+ };
+
+ that.post_create = function() {
+
+ for (var i=0; i<that.policies.length; i++) {
+ that.policies[i].post_create();
+ }
+ };
+
+ that.post_load = function(data) {
+
+ for (var i=0; i<that.policies.length; i++) {
+ that.policies[i].post_load(data);
+ }
+ };
+
+ that.add_policies(spec.policies);
+
+ return that;
+};
+
+IPA.details_facet = function(spec, no_init) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'details';
+
+ spec.actions = spec.actions || [];
+ spec.actions.unshift(
+ IPA.refresh_action,
+ IPA.reset_action,
+ IPA.update_action);
+
+ spec.control_buttons = spec.control_buttons || [];
+ spec.control_buttons.unshift(
+ {
+ name: 'refresh',
+ label: IPA.messages.buttons.refresh,
+ icon: 'reset-icon'
+ },
+ {
+ name: 'reset',
+ label: IPA.messages.buttons.reset,
+ icon: 'reset-icon'
+ },
+ {
+ name: 'update',
+ label: IPA.messages.buttons.update,
+ icon: 'update-icon'
+ });
+
+ spec.state = spec.state || {};
+ spec.state.evaluators = spec.state.evaluators || [];
+ spec.state.evaluators.push(IPA.dirty_state_evaluator);
+
+ var that = IPA.facet(spec, true);
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.update_command_name = spec.update_command_name || 'mod';
+ that.command_mode = spec.command_mode || 'save'; // [save, info]
+ that.check_rights = spec.check_rights !== undefined ? spec.check_rights : true;
+
+ that.label = spec.label || IPA.messages && IPA.messages.facets && IPA.messages.facets.details;
+ that.facet_group = spec.facet_group || 'settings';
+
+ that.widgets = IPA.widget_container();
+ that.fields = IPA.field_container({ container: that });
+ that.policies = IPA.facet_policies({
+ container: that,
+ policies: spec.policies
+ });
+
+ that.fields.add_field = function(field) {
+
+ if (field.dirty_changed) {
+ field.dirty_changed.attach(that.field_dirty_changed);
+ }
+ that.fields.container_add_field(field);
+ };
+
+ that.dirty = false;
+ that.dirty_changed = IPA.observer();
+
+ /* the primary key used for show and update is built as an array.
+ for most entities, this will be a single element long, but for some
+ it requires the containing entities primary keys as well.*/
+ that.get_primary_key = function(from_url) {
+
+ var pkey = that.entity.get_primary_key_prefix();
+
+ if (from_url) {
+ pkey.push(that.pkey);
+ } else {
+ var pkey_name = that.entity.metadata.primary_key;
+ if (!pkey_name){
+ return pkey;
+ }
+ var pkey_val = that.data.result.result[pkey_name];
+ if (pkey_val instanceof Array) {
+ pkey.push(pkey_val[0]);
+ } else {
+ pkey.push(pkey_val);
+ }
+ }
+
+ return pkey;
+ };
+
+ that.create = function(container) {
+ if (that.entity.facets.length == 1) {
+ if (that.disable_breadcrumb === undefined) {
+ that.disable_breadcrumb = true;
+ }
+ if (that.disable_facet_tabs === undefined) {
+ that.disable_facet_tabs = true;
+ }
+ }
+
+ that.facet_create(container);
+ that.policies.post_create();
+ };
+
+ that.create_controls = function() {
+
+ that.create_control_buttons(that.controls);
+ };
+
+ that.create_header = function(container) {
+
+ that.facet_create_header(container);
+
+ that.create_controls();
+
+ that.expand_button = IPA.action_button({
+ name: 'expand_all',
+ href: 'expand_all',
+ label: IPA.messages.details.expand_all,
+ 'class': 'right-aligned-facet-controls',
+ style: 'display: none;',
+ click: function() {
+ that.expand_button.css('display', 'none');
+ that.collapse_button.css('display', 'inline-block');
+
+ var widgets = that.widgets.get_widgets();
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+ if(widget.toggle) {
+ widget.toggle(true);
+ }
+ }
+ return false;
+ }
+ }).appendTo(that.controls);
+
+ that.collapse_button = IPA.action_button({
+ name: 'collapse_all',
+ href: 'collapse_all',
+ label: IPA.messages.details.collapse_all,
+ 'class': 'right-aligned-facet-controls',
+ click: function() {
+ that.expand_button.css('display', 'inline-block');
+ that.collapse_button.css('display', 'none');
+
+ var widgets = that.widgets.get_widgets();
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+ if(widget.toggle) {
+ widget.toggle(false);
+ }
+ }
+ return false;
+ }
+ }).appendTo(that.controls);
+ };
+
+ that.widgets.create_widget_delimiter = function(container) {
+ container.append('<hr/>');
+ };
+
+ that.create_content = function(container) {
+
+ that.content = $('<div/>', {
+ 'class': 'details-content'
+ }).appendTo(container);
+
+ that.widgets.create(that.content);
+
+ $('<span/>', {
+ name: 'summary',
+ 'class': 'details-summary'
+ }).appendTo(container);
+ };
+
+ that.show = function() {
+ that.facet_show();
+
+ that.pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ that.old_key_prefix = that.entity.get_primary_key_prefix();
+ that.header.set_pkey(that.pkey);
+ };
+
+ that.needs_update = function() {
+ if (that._needs_update !== undefined) return that._needs_update;
+
+ var needs_update = that.facet_needs_update();
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var key_prefix = that.entity.get_primary_key_prefix();
+
+ needs_update = needs_update || pkey !== that.pkey;
+ needs_update = needs_update || IPA.array_diff(key_prefix, that.old_key_prefix);
+
+ return needs_update;
+ };
+
+ that.field_dirty_changed = function(dirty) {
+
+ var old_dirty = that.dirty;
+
+ if (dirty) {
+ that.dirty = true;
+ } else {
+ that.dirty = that.is_dirty();
+ }
+
+ if (old_dirty !== that.dirty) {
+ that.dirty_changed.notify([that.dirty]);
+ }
+ };
+
+ that.is_dirty = function() {
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ if (fields[i].is_dirty()) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ that.load = function(data) {
+ that.facet_load(data);
+
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ field.load(data.result.result);
+ }
+ that.policies.post_load(data);
+ that.post_load.notify([data], that);
+ that.clear_expired_flag();
+ };
+
+ that.save = function(record) {
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ field.save(record);
+ }
+ };
+
+ that.save_as_update_info = function(only_dirty, require_value) {
+
+ var record = {};
+ var update_info = IPA.update_info_builder.new_update_info();
+ var fields = that.fields.get_fields();
+
+ that.save(record);
+
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+
+ if (only_dirty && !field.is_dirty()) continue;
+
+ var values = record[field.param];
+ if (require_value && !values) continue;
+
+ update_info.append_field(field, values);
+ }
+
+ return update_info;
+ };
+
+ that.reset = function() {
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ field.reset();
+ }
+ };
+
+
+ that.validate = function() {
+ var valid = true;
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ valid = field.validate() && field.validate_required() && valid;
+ }
+ return valid;
+ };
+
+ that.nofify_update_success = function() {
+ var msg = IPA.messages.details.updated;
+ var key = that.get_primary_key();
+ key = key[key.length -1] || '';
+ msg = msg.replace('${entity}', that.entity.metadata.label_singular);
+ msg = msg.replace('${primary_key}', key);
+ IPA.notify_success(msg);
+ };
+
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.load(data);
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ };
+
+ that.add_fields_to_command = function(update_info, command) {
+
+ for (var i=0; i < update_info.fields.length; i++) {
+ var field_info = update_info.fields[i];
+ if (field_info.field.flags.indexOf('no_command') > -1) continue;
+ var values = field_info.field.save();
+ IPA.command_builder.add_field_option(
+ command,
+ field_info.field,
+ values);
+ }
+ };
+
+ that.create_fields_update_command = function(update_info) {
+
+ var args = that.get_primary_key();
+
+ var options = { all: true };
+ if (that.check_rights) options.rights = true;
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.update_command_name,
+ args: args,
+ options: options
+ });
+
+ //set command options
+ that.add_fields_to_command(update_info, command);
+
+ return command;
+ };
+
+ that.create_batch_update_command = function(update_info) {
+
+ var batch = IPA.batch_command({
+ name: that.entity.name + '_details_update'
+ });
+
+ var new_update_info = IPA.update_info_builder.copy(update_info);
+
+ if (update_info.fields.length > 0) {
+ var command = that.create_fields_update_command(update_info);
+ new_update_info.append_command(command, IPA.config.default_priority);
+ }
+
+ new_update_info.commands.sort(function(a, b) {
+ return a.priority - b.priority;
+ });
+
+ for (var i=0; i < new_update_info.commands.length; i++) {
+ batch.add_command(new_update_info.commands[i].command);
+ }
+
+ return batch;
+ };
+
+ that.show_validation_error = function() {
+ var dialog = IPA.message_dialog({
+ name: 'validation_error',
+ title: IPA.messages.dialogs.validation_title,
+ message: IPA.messages.dialogs.validation_message
+ });
+ dialog.open();
+ };
+
+ that.create_update_command = function() {
+
+ var command, update_info;
+
+ if (that.command_mode === 'info') {
+ update_info = that.get_update_info();
+ } else {
+ update_info = that.save_as_update_info(true, true);
+ }
+
+ if (update_info.commands.length <= 0) {
+ //normal command
+ command = that.create_fields_update_command(update_info);
+ } else {
+ //batch command
+ command = that.create_batch_update_command(update_info);
+ }
+
+ return command;
+ };
+
+ that.update = function(on_success, on_error) {
+
+ var command = that.create_update_command();
+
+ command.on_success = function(data, text_status, xhr) {
+ that.update_on_success(data, text_status, xhr);
+ if (on_success) on_success.call(this, data, text_status, xhr);
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.update_on_error(xhr, text_status, error_thrown);
+ if (on_error) on_error.call(this, xhr, text_status, error_thrown);
+ };
+
+ command.execute();
+ };
+
+ that.get_refresh_command_name = function() {
+ return that.entity.name+'_show';
+ };
+
+ that.create_refresh_command = function() {
+
+ var options = { all: true };
+ if (that.check_rights) options.rights = true;
+
+ var command = IPA.command({
+ name: that.get_refresh_command_name(),
+ entity: that.entity.name,
+ method: 'show',
+ options: options
+ });
+
+ if (that.pkey) {
+ command.args = that.get_primary_key(true);
+ }
+
+ return command;
+ };
+
+ that.refresh_on_success = function(data, text_status, xhr) {
+ that.load(data);
+ that.show_content();
+ };
+
+ that.refresh_on_error = function(xhr, text_status, error_thrown) {
+ that.redirect_error(error_thrown);
+ that.report_error(error_thrown);
+ };
+
+ that.refresh = function(on_success, on_error) {
+
+ that.pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ if (!that.pkey && that.entity.redirect_facet) {
+ that.redirect();
+ return;
+ }
+
+ var command = that.create_refresh_command();
+
+ command.on_success = function(data, text_status, xhr) {
+ that.refresh_on_success(data, text_status, xhr);
+ if (on_success) on_success.call(this, data, text_status, xhr);
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.refresh_on_error(xhr, text_status, error_thrown);
+ if (on_error) on_error.call(this, xhr, text_status, error_thrown);
+ };
+
+ command.execute();
+ };
+
+ that.clear = function() {
+ that.header.clear();
+
+ that.widgets.clear();
+ };
+
+ that.get_update_info = function() {
+
+ var update_info = IPA.update_info_builder.new_update_info();
+
+ var fields = that.fields.get_fields();
+ for (var i = 0; i < fields.length; i++) {
+ var field = fields[i];
+ if (field.get_update_info) {
+ var ui = field.get_update_info();
+ update_info = IPA.update_info_builder.merge(update_info, ui);
+ }
+ }
+
+ return update_info;
+ };
+
+ that.create_builder = function() {
+
+ var widget_builder = IPA.widget_builder({
+ widget_options: {
+ entity: that.entity,
+ facet: that
+ }
+ });
+ var field_builder = IPA.field_builder({
+ field_options: {
+ entity: that.entity
+ }
+ });
+ var section_builder = IPA.section_builder({
+ container: that,
+ widget_builder: widget_builder,
+ field_builder: field_builder
+ });
+
+ that.builder = IPA.details_builder({
+ container: that,
+ widget_builder: widget_builder,
+ field_builder: field_builder,
+ section_builder: section_builder
+ });
+ };
+
+ that.init_details_facet = function() {
+
+ that.init_facet();
+ that.create_builder();
+ that.builder.build(spec);
+ that.fields.widgets_created();
+ that.policies.init();
+ };
+
+ if (!no_init) that.init_details_facet();
+
+ // methods that should be invoked by subclasses
+ that.details_facet_create_update_command = that.create_update_command;
+ that.details_facet_create_refresh_command = that.create_refresh_command;
+ that.details_facet_refresh_on_success = that.refresh_on_success;
+ that.details_facet_load = that.load;
+
+ return that;
+};
+
+IPA.update_info = function(spec) {
+
+ var that = {};
+
+ that.fields = spec.fields || [];
+ that.commands = spec.commands || [];
+
+ that.append_field = function(field, value) {
+ var field_info = IPA.update_info_builder.new_field_info(field, value);
+ that.fields.push(field_info);
+ };
+
+ that.append_command = function (command, priority) {
+ var command_info = IPA.update_info_builder.new_command_info(command, priority);
+ that.commands.push(command_info);
+ };
+
+ return that;
+};
+
+IPA.command_info = function(spec) {
+
+ var that = {};
+
+ that.command = spec.command;
+ that.priority = spec.priority || IPA.config.default_priority;
+
+ return that;
+};
+
+IPA.field_info = function(spec) {
+
+ var that = {};
+
+ that.field = spec.field;
+ that.value = spec.value;
+
+ return that;
+};
+
+IPA.update_info_builder = function() {
+
+ var that = {};
+
+ that.new_update_info = function (fields, commands) {
+ return IPA.update_info({
+ fields: fields,
+ commands: commands
+ });
+ };
+
+ that.new_field_info = function(field, value) {
+ return IPA.field_info({
+ field: field,
+ value: value
+ });
+ };
+
+ that.new_command_info = function(command, priority) {
+ return IPA.command_info({
+ command: command,
+ priority: priority
+ });
+ };
+
+ that.merge = function(a, b) {
+ return that.new_update_info(
+ a.fields.concat(b.fields),
+ a.commands.concat(b.commands));
+ };
+
+ that.copy = function(original) {
+ return that.new_update_info(
+ original.fields.concat([]),
+ original.commands.concat([]));
+ };
+
+ return that;
+}();
+
+IPA.command_builder = function() {
+
+ var that = {};
+
+ that.add_field_option = function(command, field, values) {
+ if (!field || !values) return;
+
+ var name = field.param;
+
+ if (field.metadata) {
+ if (field.metadata.primary_key) return;
+ if (values.length === 1) {
+ command.set_option(name, values[0]);
+ } else {
+ command.set_option(name, values);
+ }
+ } else {
+ if (values.length) {
+ command.add_option('setattr', name+'='+values[0]);
+ } else {
+ command.add_option('setattr', name+'=');
+ }
+ for (var k=1; k<values.length; k++) {
+ command.add_option('addattr', name+'='+values[k]);
+ }
+ }
+ };
+
+ return that;
+}();
+
+IPA.select_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'select_action';
+ spec.label = spec.label || '-- select action --';
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+ };
+
+ return that;
+};
+
+IPA.refresh_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'refresh';
+ spec.label = spec.label || IPA.messages.buttons.refresh;
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+ facet.refresh();
+ };
+
+ return that;
+};
+
+IPA.reset_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'reset';
+ spec.label = spec.label || IPA.messages.buttons.reset;
+ spec.enable_cond = spec.enable_cond || ['dirty'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+ facet.reset();
+ };
+
+ return that;
+};
+
+IPA.update_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'update';
+ spec.label = spec.label || IPA.messages.buttons.update;
+ spec.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : false;
+ spec.enable_cond = spec.enable_cond || ['dirty'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ if (!facet.validate()) {
+ facet.show_validation_error();
+ return;
+ }
+
+ facet.update();
+ };
+
+ return that;
+};
+
+IPA.boolean_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+
+ that.name = spec.name || 'boolean_state_evaluator';
+ that.field = spec.field;
+ that.true_state = spec.true_state || that.field_name + '-true';
+ that.false_state = spec.false_state || that.field_name + '-false';
+ that.invert_value = spec.invert_value;
+ that.parser = IPA.build({
+ factory: spec.parser || IPA.boolean_formatter,
+ invert_value: that.invert_value
+ });
+
+ that.on_event = function(data) {
+
+ var old_state = that.state;
+ var record = data.result.result;
+ that.state = [];
+
+ var value = that.parser.parse(record[that.field]);
+
+ if (value === true) {
+ that.state.push(that.true_state);
+ } else {
+ that.state.push(that.false_state);
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.enable_state_evaluator = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'enable_state_evaluator';
+ spec.true_state = spec.true_state || 'enabled';
+ spec.false_state = spec.false_state || 'disabled';
+
+ var that = IPA.boolean_state_evaluator(spec);
+
+ return that;
+};
+
+IPA.acl_state_evaluator = function(spec) {
+
+ spec.name = spec.name || 'acl_state_evaluator';
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+ that.attribute = spec.attribute;
+
+ that.on_event = function(data) {
+
+ var old_state, record, rights, i, state;
+
+ old_state = that.state;
+ record = data.result.result;
+
+ that.state = [];
+
+ if (record.attributelevelrights) {
+ rights = record.attributelevelrights[that.attribute];
+ }
+
+ // Full rights if we don't know the rights. Better to allow action and
+ // then to show error dialog than not be able to do something.
+ rights = rights || 'rscwo';
+
+ for (i=0; i<rights.length; i++) {
+ state = that.attribute + '_' + rights.charAt(i);
+ that.state.push(state);
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.value_state_evaluator = function(spec) {
+
+ spec.name = spec.name || 'value_state_evaluator';
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+ that.attribute = spec.attribute;
+ that.value = spec.value;
+ that.representation = spec.representation;
+
+ that.on_event = function(data) {
+
+ var old_state, record, state, value, loaded_value;
+
+ old_state = that.state;
+ record = data.result.result;
+ value = that.normalize_value(that.value);
+ loaded_value = record[that.attribute];
+ loaded_value = that.normalize_value(loaded_value);
+
+ that.state = [];
+
+ if (!IPA.array_diff(value, loaded_value)) {
+ that.state.push(that.get_state_text());
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ that.normalize_value = function(original) {
+
+ var value = original;
+
+ if (!(value instanceof Array)) {
+ value = [value];
+ }
+ return value;
+ };
+
+ that.get_state_text = function() {
+
+ var representation, value;
+
+ representation = that.representation;
+
+ if (!representation) {
+ value = that.normalize_value(that.value);
+ representation = that.attribute + '_' + value[0];
+ }
+
+ return representation;
+ };
+
+ return that;
+};
+
+IPA.object_class_evaluator = function(spec) {
+
+ spec.name = spec.name || 'object_class_evaluator';
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+
+
+ that.on_event = function(data) {
+
+ var old_state, classes, i;
+
+ old_state = that.state;
+ classes = data.result.result.objectclass;
+
+ that.state = [];
+
+ for (i=0; i<classes.length; i++) {
+ that.state.push('oc_'+classes[i]);
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.object_action = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.action(spec);
+
+ that.method = spec.method;
+ that.confirm_msg = spec.confirm_msg || IPA.messages.actions.confirm;
+ that.options = spec.options || {};
+
+ that.execute_action = function(facet, on_success, on_error) {
+
+ var entity_name = facet.entity.name;
+ var pkey = IPA.nav.get_state(entity_name+'-pkey');
+
+ IPA.command({
+ entity: entity_name,
+ method: that.method,
+ args: [pkey],
+ options: that.options,
+ on_success: that.get_on_success(facet, on_success),
+ on_error: that.get_on_error(facet, on_error)
+ }).execute();
+ };
+
+ that.on_success = function(facet, data, text_status, xhr) {
+
+ IPA.notify_success(data.result.summary);
+ facet.on_update.notify();
+ };
+
+ that.on_error = function(facet, xhr, text_status, error_thrown) {
+ };
+
+ that.get_on_success = function(facet, on_success) {
+ return function(data, text_status, xhr) {
+ that.on_success(facet, data, text_status, xhr);
+ if (on_success) on_success.call(this, data, text_status, xhr);
+ };
+ };
+
+ that.get_on_error = function(facet, on_error) {
+ return function(xhr, text_status, error_thrown) {
+ that.on_error(facet, xhr, text_status, error_thrown);
+ if (on_error) on_error.call(this, xhr, text_status, error_thrown);
+ };
+ };
+
+ that.get_confirm_message = function(facet) {
+ var pkey = IPA.nav.get_state(facet.entity.name+'-pkey');
+ var msg = that.confirm_msg.replace('${object}', pkey);
+ return msg;
+ };
+
+ that.object_execute_action = that.execute_action;
+
+ return that;
+};
+
+IPA.enable_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'enable';
+ spec.method = spec.method || 'enable';
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.actions.enable_confirm;
+ spec.label = spec.label || IPA.messages.buttons.enable;
+ spec.disable_cond = spec.disable_cond || ['enabled'];
+
+ var that = IPA.object_action(spec);
+
+ return that;
+};
+
+IPA.disable_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'disable';
+ spec.method = spec.method || 'disable';
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.actions.disable_confirm;
+ spec.label = spec.label || IPA.messages.buttons.disable;
+ spec.enable_cond = spec.enable_cond || ['enabled'];
+
+ var that = IPA.object_action(spec);
+
+ return that;
+};
+
+IPA.delete_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'delete';
+ spec.method = spec.method || 'del';
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.actions.delete_confirm;
+ spec.label = spec.label || IPA.messages.buttons.remove;
+
+ var that = IPA.object_action(spec);
+
+ that.execute_action = function(facet, on_success, on_error) {
+
+ if (facet.is_dirty()) facet.reset();
+
+ that.object_execute_action(facet, on_success, on_error);
+ };
+
+ that.on_success = function(facet, data, text_status, xhr) {
+
+ IPA.notify_success(data.result.summary);
+ facet.on_update.notify();
+ facet.redirect();
+ };
+
+ return that;
+};
+
+
+IPA.enabled_summary_cond = function() {
+ return {
+ pos: ['enabled'],
+ neg: [],
+ description: IPA.messages.status.enabled,
+ state: ['enabled']
+ };
+};
+
+IPA.disabled_summary_cond = function() {
+ return {
+ pos: [],
+ neg: ['enabled'],
+ description: IPA.messages.status.disabled,
+ state: ['disabled']
+ };
+};
diff --git a/install/ui/src/freeipa/develop.js b/install/ui/src/freeipa/develop.js
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/install/ui/src/freeipa/develop.js
diff --git a/install/ui/src/freeipa/dialog.js b/install/ui/src/freeipa/dialog.js
new file mode 100644
index 000000000..4e603155a
--- /dev/null
+++ b/install/ui/src/freeipa/dialog.js
@@ -0,0 +1,849 @@
+/*jsl:import ipa.js */
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: widget.js, details.js */
+
+IPA.opened_dialogs = {
+
+ dialogs: [],
+
+ top_dialog: function() {
+ var top = null;
+ if (this.dialogs.length) top = this.dialogs[this.dialogs.length - 1];
+ return top;
+ },
+
+ focus_top: function() {
+ var top = this.top_dialog();
+ if (top) {
+ top.container.dialog('moveToTop'); //make sure the last dialog is top dialog
+ top.focus_first_element();
+ }
+ },
+
+ add_dialog: function(dialog) {
+ this.dialogs.push(dialog);
+ },
+
+ remove_dialog: function(dialog) {
+ var index = this.dialogs.indexOf(dialog);
+ if (index > -1) this.dialogs.splice(index, 1);
+ }
+};
+
+IPA.dialog_button = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.label = spec.label || spec.name;
+ that.click = spec.click || click;
+ that.visible = spec.visible !== undefined ? spec.visible : true;
+
+ function click() {
+ }
+
+ that.set_enabled = function(enabled) {
+ if (enabled) {
+ that.element.removeClass('ui-state-disabled');
+ } else {
+ that.element.addClass('ui-state-disabled');
+ }
+ };
+
+ that.is_enabled = function() {
+ return !that.element.hasClass('ui-state-disabled');
+ };
+
+ return that;
+};
+
+/**
+ * This is a base class for dialog boxes.
+ */
+IPA.dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.name = spec.name || 'dialog';
+ that.id = spec.id;
+ that.title = spec.title;
+ that.width = spec.width || 500;
+ that.height = spec.height;
+ that.close_on_escape = spec.close_on_escape !== undefined ?
+ spec.close_on_escape : true;
+
+ that.widgets = IPA.widget_container();
+ that.fields = IPA.field_container({ container: that });
+ that.buttons = $.ordered_map();
+ that.policies = IPA.facet_policies({
+ container: that,
+ policies: spec.policies
+ });
+
+ that.create_button = function(spec) {
+ var factory = spec.factory || IPA.dialog_button;
+ var button = factory(spec);
+ that.add_button(button);
+ return button;
+ };
+
+ that.add_button = function(button) {
+ that.buttons.put(button.name, button);
+ };
+
+ that.get_button = function(name) {
+ return that.buttons.get(name);
+ };
+
+ that.field = function(field) {
+ that.fields.add_field(field);
+ return that;
+ };
+
+ that.validate = function() {
+ var valid = true;
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ valid = field.validate() && field.validate_required() && valid;
+ }
+ return valid;
+ };
+
+ that.get_id = function() {
+ if (that.id) return that.id;
+ if (that.name) return that.name;
+ return null;
+ };
+
+
+ /**
+ * Create content layout
+ */
+ that.create = function() {
+
+ that.message_container = $('<div/>', {
+ style: 'display: none',
+ 'class': 'dialog-message ui-state-highlight ui-corner-all'
+ }).appendTo(that.container);
+
+ var widgets = that.widgets.get_widgets();
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+
+ var div = $('<div/>', {
+ name: widget.name,
+ 'class': 'dialog-section'
+ }).appendTo(that.container);
+
+ widget.create(div);
+ }
+
+ that.policies.post_create();
+ };
+
+ that.show_message = function(message) {
+ that.message_container.text(message);
+ that.message_container.css('display', '');
+ };
+
+ that.hide_message = function() {
+ that.message_container.css('display', 'none');
+ };
+
+ /**
+ * Open dialog
+ */
+ that.open = function(container) {
+
+ that.container = $('<div/>', {
+ id : that.get_id(),
+ 'data-name': that.name
+ });
+
+ if (container) {
+ container.append(that.container);
+ }
+
+ that.create();
+ that.reset();
+
+ that.container.dialog({
+ title: that.title,
+ modal: true,
+ closeOnEscape: that.close_on_escape,
+ width: that.width,
+ minWidth: that.width,
+ height: that.height,
+ minHeight: that.height,
+ close: function(event, ui) {
+ that.close();
+ }
+ });
+
+ that.set_buttons();
+ that.register_listeners();
+ IPA.opened_dialogs.add_dialog(that);
+ that.focus_first_element();
+ };
+
+ that.focus_first_element = function() {
+ // set focus to the first tabbable element in the content area or the first button
+ // if there are no tabbable elements, set focus on the dialog itself
+
+ var element = that.container;
+ var ui_dialog = that.container.parent('.ui-dialog'); // jq dialog div
+
+ // code taken from jquery dialog source code
+ $(element.find(':tabbable').get().concat(
+ ui_dialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
+ ui_dialog.get()))).eq(0).focus();
+ };
+
+ that.option = function(name, value) {
+ that.container.dialog('option', name, value);
+ };
+
+ that.set_buttons = function() {
+
+ // create a map of button labels and handlers
+ var dialog_buttons = {};
+ for (var i=0; i<that.buttons.values.length; i++) {
+ var button = that.buttons.values[i];
+ if (!button.visible) continue;
+ dialog_buttons[button.label] = button.click;
+ }
+
+ //set buttons to dialog
+ that.option('buttons', dialog_buttons);
+
+ // find button elements
+ var parent = that.container.parent();
+ var buttons = $('.ui-dialog-buttonpane .ui-dialog-buttonset button', parent);
+
+ buttons.each(function(index) {
+ var button = that.buttons.values[index];
+ button.element = $(this);
+ });
+ };
+
+ that.display_buttons = function(names) {
+
+ for (var i=0; i<that.buttons.values.length; i++) {
+ var button = that.buttons.values[i];
+
+ button.visible = names.indexOf(button.name) > -1;
+ }
+ that.set_buttons();
+ };
+
+ that.save = function(record) {
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ field.save(record);
+ }
+ };
+
+ that.close = function() {
+ that.container.dialog('destroy');
+ that.container.remove();
+ that.remove_listeners();
+ IPA.opened_dialogs.remove_dialog(that);
+ IPA.opened_dialogs.focus_top();
+ };
+
+ that.reset = function() {
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ fields[i].reset();
+ }
+ };
+
+ that.register_listeners = function() {};
+ that.remove_listeners = function() {};
+
+ that.create_builder = function() {
+
+ var widget_builder = IPA.widget_builder({
+ widget_options: {
+ entity: that.entity,
+ facet: that
+ }
+ });
+ var field_builder = IPA.field_builder({
+ field_options: {
+ undo: false,
+ entity: that.entity,
+ facet: that
+ }
+ });
+ var section_builder = IPA.section_builder({
+ container: that,
+ section_factory: IPA.details_table_section_nc,
+ widget_builder: widget_builder,
+ field_builder: field_builder
+ });
+
+ that.builder = IPA.details_builder({
+ container: that,
+ widget_builder: widget_builder,
+ field_builder: field_builder,
+ section_builder: section_builder
+ });
+ };
+
+ that.init = function() {
+
+ that.create_builder();
+ that.builder.build(spec);
+ that.fields.widgets_created();
+ that.policies.init();
+ };
+
+ that.init();
+
+ that.dialog_create = that.create;
+ that.dialog_open = that.open;
+ that.dialog_close = that.close;
+ that.dialog_save = that.save;
+ that.dialog_reset = that.reset;
+ that.dialog_validate = that.validate;
+
+ return that;
+};
+
+/**
+ * This dialog provides an interface for searching and selecting
+ * values from the available results.
+ */
+IPA.adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'adder_dialog';
+
+ var that = IPA.dialog(spec);
+
+ IPA.confirm_mixin().apply(that);
+
+ that.external = spec.external;
+ that.width = spec.width || 600;
+ that.height = spec.height || 360;
+
+ if (!that.entity) {
+ var except = {
+ expected: false,
+ message:'Adder dialog created without entity.'
+ };
+ throw except;
+ }
+
+ var init = function() {
+ that.available_table = IPA.table_widget({
+ entity: that.entity,
+ name: 'available',
+ scrollable: true
+ });
+
+ that.selected_table = IPA.table_widget({
+ entity: that.entity,
+ name: 'selected',
+ scrollable: true
+ });
+
+ if (spec.columns) {
+ for (var i=0; i<spec.columns.length; i++) {
+ that.create_column(spec.columns[i]);
+ }
+ }
+ };
+
+ that.get_column = function(name) {
+ return that.available_table.get_column(name);
+ };
+
+ that.get_columns = function() {
+ return that.available_table.get_columns();
+ };
+
+ that.add_column = function(column) {
+ that.available_table.add_column(column);
+ that.selected_table.add_column(column);
+ };
+
+ that.set_columns = function(columns) {
+ that.clear_columns();
+ for (var i=0; i<columns.length; i++) {
+ that.add_column(columns[i]);
+ }
+ };
+
+ that.clear_columns = function() {
+ that.available_table.clear_columns();
+ that.selected_table.clear_columns();
+ };
+
+ that.create_column = function(spec) {
+ spec.entity = that.entity;
+ var column = IPA.column(spec);
+ that.add_column(column);
+ return column;
+ };
+
+ that.create = function() {
+
+ // do not call that.dialog_create();
+
+ var container = $('<div/>', {
+ 'class': 'adder-dialog'
+ }).appendTo(that.container);
+
+ var top_panel = $('<div/>', {
+ 'class': 'adder-dialog-top'
+ }).appendTo(container);
+
+ $('<input/>', {
+ type: 'text',
+ name: 'filter',
+ keyup: function(event) {
+ if (event.keyCode === $.ui.keyCode.ENTER) {
+ that.search();
+ return false;
+ }
+ }
+ }).appendTo(top_panel);
+
+ top_panel.append(' ');
+
+ that.find_button = IPA.button({
+ name: 'find',
+ label: IPA.messages.buttons.find,
+ click: function() {
+ that.search();
+ return false;
+ }
+ }).appendTo(top_panel);
+
+ top_panel.append(IPA.create_network_spinner());
+
+ var left_panel = $('<div/>', {
+ 'class': 'adder-dialog-left'
+ }).appendTo(container);
+
+ var available_panel = $('<div/>', {
+ name: 'available',
+ 'class': 'adder-dialog-available'
+ }).appendTo(left_panel);
+
+ $('<div/>', {
+ html: IPA.messages.dialogs.available,
+ 'class': 'adder-dialog-header ui-widget-header'
+ }).appendTo(available_panel);
+
+ var available_content = $('<div/>', {
+ 'class': 'adder-dialog-content'
+ }).appendTo(available_panel);
+
+ that.available_table.create(available_content);
+
+
+ var right_panel = $('<div/>', {
+ 'class': 'adder-dialog-right'
+ }).appendTo(container);
+
+ var selected_panel = $('<div/>', {
+ name: 'selected',
+ 'class': 'adder-dialog-selected'
+ }).appendTo(right_panel);
+
+ $('<div/>', {
+ html: IPA.messages.dialogs.prospective,
+ 'class': 'adder-dialog-header ui-widget-header'
+ }).appendTo(selected_panel);
+
+ var selected_content = $('<div/>', {
+ 'class': 'adder-dialog-content'
+ }).appendTo(selected_panel);
+
+ that.selected_table.create(selected_content);
+
+
+ var buttons_panel = $('<div/>', {
+ name: 'buttons',
+ 'class': 'adder-dialog-buttons'
+ }).appendTo(container);
+
+ var div = $('<div/>').appendTo(buttons_panel);
+ IPA.button({
+ name: 'add',
+ label: '>>',
+ click: function() {
+ that.add();
+ that.update_buttons();
+ return false;
+ }
+ }).appendTo(div);
+
+ div = $('<div/>').appendTo(buttons_panel);
+ IPA.button({
+ name: 'remove',
+ label: '<<',
+ click: function() {
+ that.remove();
+ that.update_buttons();
+ return false;
+ }
+ }).appendTo(div);
+
+ that.filter_field = $('input[name=filter]', that.container);
+
+ if (that.external) {
+ container.addClass('adder-dialog-with-external');
+
+ var external_panel = $('<div/>', {
+ name: 'external',
+ 'class': 'adder-dialog-external'
+ }).appendTo(left_panel);
+
+ $('<div/>', {
+ html: IPA.messages.objects.sudorule.external,
+ 'class': 'adder-dialog-header ui-widget-header'
+ }).appendTo(external_panel);
+
+ var external_content = $('<div/>', {
+ 'class': 'adder-dialog-content'
+ }).appendTo(external_panel);
+
+ that.external_field = $('<input/>', {
+ type: 'text',
+ name: 'external'
+ }).appendTo(external_content);
+ }
+
+ that.search();
+ };
+
+ that.open = function(container) {
+
+ var add_button = that.create_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ click: function() {
+ if (!add_button.is_enabled()) return;
+ that.execute();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ that.dialog_open(container);
+
+ that.update_buttons();
+ };
+
+ that.add = function() {
+ var rows = that.available_table.remove_selected_rows();
+ that.selected_table.add_rows(rows);
+ };
+
+ that.remove = function() {
+ var rows = that.selected_table.remove_selected_rows();
+ that.available_table.add_rows(rows);
+ };
+
+ that.update_buttons = function() {
+
+ var values = that.selected_table.save();
+
+ var button = that.get_button('add');
+ button.set_enabled(values && values.length);
+ };
+
+ that.get_filter = function() {
+ return that.filter_field.val();
+ };
+
+ that.clear_available_values = function() {
+ that.available_table.empty();
+ };
+
+ that.clear_selected_values = function() {
+ that.selected_table.empty();
+ };
+
+ that.add_available_value = function(record) {
+ that.available_table.add_record(record);
+ };
+
+ that.get_selected_values = function() {
+ return that.selected_table.save();
+ };
+
+ that.execute = function() {
+ };
+
+ that.on_confirm = function() {
+
+ var add_button = that.get_button('add');
+ if (add_button.is_enabled()) {
+ that.execute();
+ }
+ };
+
+ init();
+
+ that.adder_dialog_create = that.create;
+
+ return that;
+};
+
+/**
+ * This dialog displays the values to be deleted.
+ */
+IPA.deleter_dialog = function (spec) {
+
+ spec = spec || {};
+
+ spec.title = spec.title || IPA.messages.buttons.remove;
+ spec.name = spec.name || 'deleter_dialog';
+ spec.message = spec.message || IPA.messages.search.delete_confirm;
+ spec.ok_label = spec.ok_label || IPA.messages.buttons.remove;
+
+ var that = IPA.confirm_dialog(spec);
+ that.values = spec.values || [];
+ that.on_ok = spec.on_ok || function() {
+ that.execute();
+ };
+
+ that.add_value = function(value) {
+ that.values.push(value);
+ };
+
+ that.set_values = function(values) {
+ that.values = values;
+ };
+
+ that.create = function() {
+
+ $('<p/>', {
+ 'text': that.message
+ }).appendTo(that.container);
+
+ var div = $('<div/>', {
+ style: 'overflow:auto; max-height: 100px'
+ }).appendTo(that.container);
+
+ var ul = $('<ul/>');
+ ul.appendTo(div);
+
+ for (var i=0; i<that.values.length; i++) {
+ var value = that.values[i];
+ if (value instanceof Object){
+ var first = true;
+ var str_value = "";
+ for (var key in value){
+ if (value.hasOwnProperty(key)){
+ if (!first){
+ str_value += ',';
+ }
+ str_value += (key + ':' +value[key]);
+ first = false;
+ }
+ }
+ value = str_value;
+ }
+
+ $('<li/>',{
+ 'text': value
+ }).appendTo(ul);
+ }
+ };
+
+ that.deleter_dialog_create = that.create;
+
+ return that;
+};
+
+IPA.message_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'message_dialog';
+
+ var that = IPA.confirm_dialog(spec);
+
+ that.open = function(container) {
+
+ that.confirm_dialog_open(container);
+ that.confirmed = true; // there are no options to confirm
+ };
+
+ that.buttons.remove('cancel');
+
+ that.message_dialog_create = that.create;
+
+ return that;
+};
+
+IPA.confirm_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'confirm_dialog';
+ spec.title = spec.title || IPA.messages.dialogs.confirmation;
+
+ var that = IPA.dialog(spec);
+ IPA.confirm_mixin().apply(that);
+
+ that.message = spec.message || '';
+ that.on_ok = spec.on_ok;
+ that.on_cancel = spec.on_cancel;
+ that.ok_label = spec.ok_label || IPA.messages.buttons.ok;
+ that.cancel_label = spec.cancel_label || IPA.messages.buttons.cancel;
+ that.confirmed = false;
+ that.confirm_on_enter = spec.confirm_on_enter !== undefined ? spec.confirm_on_enter : true;
+
+ that.create = function() {
+ $('<p/>', {
+ 'text': that.message
+ }).appendTo(that.container);
+ };
+
+ that.close = function() {
+
+ that.dialog_close();
+
+ if (that.confirmed) {
+ if (that.on_ok) {
+ that.on_ok();
+ }
+ } else {
+ if (that.on_cancel) {
+ that.on_cancel();
+ }
+ }
+ };
+
+ that.open = function(container) {
+
+ that.confirmed = false;
+ that.dialog_open(container);
+ };
+
+ that.on_confirm = function() {
+ that.confirmed = true;
+ that.close();
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'ok',
+ label: that.ok_label,
+ click: function() {
+ that.confirmed = true;
+ that.close();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: that.cancel_label,
+ click: function() {
+ that.confirmed = false;
+ that.close();
+ }
+ });
+ };
+
+ that.create_buttons();
+
+ that.confirm_dialog_close = that.close;
+ that.confirm_dialog_open = that.open;
+
+ return that;
+};
+
+IPA.confirm_mixin = function() {
+
+ return {
+ mixin: {
+
+ ignore_enter_rules: {
+ src_elements: ['a', 'button'],
+ src_types: ['textarea', 'select-one']
+ },
+
+ test_ignore: function(event) {
+
+ var ir = this.ignore_enter_rules,
+ t = event.target,
+
+ ignore = ir.src_elements.indexOf(t.tagName.toLowerCase()) > -1 ||
+ ir.src_types.indexOf(t.type) > -1;
+
+ return ignore;
+ },
+
+ register_listeners: function() {
+ var self = this;
+ this._on_key_up_listener = function(e) { self.on_key_up(e); };
+ var dialog_container = this.container.parent('.ui-dialog');
+ dialog_container.bind('keyup', this._on_key_up_listener);
+ },
+
+ remove_listeners: function() {
+ var dialog_container = this.container.parent('.ui-dialog');
+ dialog_container.unbind('keyup', this._on_key_up_listener);
+ },
+
+ on_key_up: function(event) {
+ if (event.keyCode === $.ui.keyCode.ENTER &&
+ !this.test_ignore(event) &&
+ !!this.on_confirm) {
+ event.preventDefault();
+ this.on_confirm();
+ } else if (event.keyCode === $.ui.keyCode.ESCAPE &&
+ !!this.on_cancel) {
+ event.preventDefault();
+ this.on_cancel();
+ }
+ }
+ },
+
+ apply: function(obj) {
+ $.extend(obj, this.mixin);
+ }
+ };
+};
diff --git a/install/ui/src/freeipa/dns.js b/install/ui/src/freeipa/dns.js
new file mode 100644
index 000000000..d08f4140b
--- /dev/null
+++ b/install/ui/src/freeipa/dns.js
@@ -0,0 +1,2552 @@
+/*jsl:import ipa.js */
+/*jsl:import search.js */
+/*jsl:import net.js */
+
+/* Authors:
+ * Adam Young <ayoung@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js,
+ * net.js, widget.js */
+
+IPA.dns = {
+ zone_permission_name: 'Manage DNS zone ${dnszone}'
+};
+
+IPA.dns.config_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+
+ if (!IPA.dns_enabled) {
+ throw {
+ expected: true
+ };
+ }
+
+ that.entity_init();
+
+ that.builder.details_facet({
+ title: IPA.metadata.objects.config.label,
+ sections: [
+ {
+ name: 'options',
+ label: IPA.messages.objects.dnsconfig.options,
+ fields: [
+ {
+ type: 'checkbox',
+ name: 'idnsallowsyncptr'
+ },
+ {
+ type: 'multivalued',
+ name: 'idnsforwarders',
+ validators: [IPA.dnsforwarder_validator()]
+ },
+ {
+ type: 'radio',
+ name: 'idnsforwardpolicy',
+ default_value: 'first',
+ options: [
+ {
+ value: 'first',
+ label: IPA.messages.objects.dnsconfig.forward_first
+ },
+ {
+ value: 'only',
+ label: IPA.messages.objects.dnsconfig.forward_only
+ },
+ {
+ value: 'none',
+ label: IPA.messages.objects.dnsconfig.forward_none
+ }
+ ]
+ },
+ 'idnszonerefresh'
+ ]
+ }
+ ],
+ needs_update: true
+ });
+ };
+
+ return that;
+};
+
+IPA.dns.zone_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+
+ if (!IPA.dns_enabled) {
+ throw {
+ expected: true
+ };
+ }
+
+ that.entity_init();
+
+ that.builder.facet_groups([ 'dnsrecord', 'settings' ]).
+ search_facet({
+ row_enabled_attribute: 'idnszoneactive',
+ title: IPA.metadata.objects.dnszone.label,
+ columns: [
+ 'idnsname',
+ {
+ name: 'idnszoneactive',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ }
+ ],
+ actions: [
+ IPA.batch_disable_action,
+ IPA.batch_enable_action
+ ],
+ control_buttons: [
+ {
+ name: 'disable',
+ label: IPA.messages.buttons.disable,
+ icon: 'disabled-icon'
+ },
+ {
+ name: 'enable',
+ label: IPA.messages.buttons.enable,
+ icon: 'enabled-icon'
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.dnszone_details_facet,
+ command_mode: 'info',
+ sections: [
+ {
+ name: 'identity',
+ fields: [
+ 'idnsname',
+ 'idnssoamname',
+ 'idnssoarname',
+ 'idnssoaserial',
+ 'idnssoarefresh',
+ 'idnssoaretry',
+ 'idnssoaexpire',
+ 'idnssoaminimum',
+ 'dnsttl',
+ {
+ type: 'combobox',
+ name: 'dnsclass',
+ options: [
+ 'IN', 'CS', 'CH', 'HS'
+ ]
+ },
+ {
+ type: 'radio',
+ name: 'idnsallowdynupdate',
+ options: [
+ { value: 'TRUE', label: IPA.get_message('true') },
+ { value: 'FALSE', label: IPA.get_message('false') }
+ ]
+ },
+ {
+ type: 'textarea',
+ name: 'idnsupdatepolicy'
+ },
+ {
+ type: 'netaddr',
+ name: 'idnsallowquery',
+ validators: [
+ IPA.network_validator({
+ specials: ['any', 'none', 'localhost', 'localnets'],
+ allow_negation: true,
+ allow_host_address: true
+ })]
+ },
+ {
+ type: 'netaddr',
+ name: 'idnsallowtransfer',
+ validators: [
+ IPA.network_validator({
+ specials: ['any', 'none', 'localhost', 'localnets'],
+ allow_negation: true,
+ allow_host_address: true
+ })]
+ },
+ {
+ type: 'multivalued',
+ name: 'idnsforwarders',
+ validators: [IPA.dnsforwarder_validator()]
+ },
+ {
+ type: 'radio',
+ name: 'idnsforwardpolicy',
+ default_value: 'first',
+ options: [
+ {
+ value: 'first',
+ label: IPA.messages.objects.dnsconfig.forward_first
+ },
+ {
+ value: 'only',
+ label: IPA.messages.objects.dnsconfig.forward_only
+ },
+ {
+ value: 'none',
+ label: IPA.messages.objects.dnsconfig.forward_none
+ }
+ ]
+ },
+ {
+ type: 'checkbox',
+ name: 'idnsallowsyncptr'
+ }
+ ]
+ }],
+ actions: [
+ IPA.select_action,
+ IPA.enable_action,
+ IPA.disable_action,
+ IPA.delete_action,
+ IPA.dns.add_permission_action,
+ IPA.dns.remove_permission_action
+ ],
+ header_actions: ['select_action', 'enable', 'disable', 'delete',
+ 'add_permission', 'remove_permission'],
+ state: {
+ evaluators: [
+ {
+ factory: IPA.enable_state_evaluator,
+ field: 'idnszoneactive'
+ },
+ {
+ factory: IPA.acl_state_evaluator,
+ attribute: 'managedby'
+ },
+ IPA.dns.zone_has_permission_evaluator
+ ],
+ summary_conditions: [
+ IPA.enabled_summary_cond(),
+ IPA.disabled_summary_cond()
+ ]
+ }
+ }).
+ nested_search_facet({
+ factory: IPA.dns.record_search_facet,
+ facet_group: 'dnsrecord',
+ nested_entity : 'dnsrecord',
+ name: 'records',
+ deleter_dialog: IPA.dns.record_search_deleter_dialog,
+ title: IPA.metadata.objects.dnszone.label_singular,
+ label: IPA.metadata.objects.dnsrecord.label,
+ tab_label: IPA.metadata.objects.dnsrecord.label,
+ columns: [
+ {
+ name: 'idnsname',
+ label: IPA.get_entity_param('dnsrecord', 'idnsname').label,
+ primary_key: true
+ },
+ {
+ name: 'type',
+ label: IPA.messages.objects.dnsrecord.type
+ },
+ {
+ name: 'data',
+ label: IPA.messages.objects.dnsrecord.data
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ factory: IPA.dnszone_adder_dialog,
+ height: 300,
+ sections: [
+ {
+ factory: IPA.dnszone_name_section,
+ name: 'name',
+ fields: [
+ {
+ type: 'dnszone_name',
+ name: 'idnsname',
+ required: false,
+ radio_name: 'dnszone_name_type'
+ },
+ {
+ type: 'dnszone_name',
+ name: 'name_from_ip',
+ radio_name: 'dnszone_name_type',
+ validators: [IPA.network_validator()]
+ }
+ ]
+ },
+ {
+ name: 'other',
+ fields: [
+ 'idnssoamname',
+ {
+ name: 'idnssoarname',
+ required: false
+ },
+ {
+ type: 'force_dnszone_add_checkbox',
+ name: 'force',
+ metadata: IPA.get_command_option('dnszone_add', 'force')
+ }
+ ]
+ }
+ ],
+ policies: [
+ IPA.add_dns_zone_name_policy()
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.dnszone_details_facet = function(spec, no_init) {
+
+ spec = spec || {};
+
+ var that = IPA.details_facet(spec, true);
+ that.permission_load = IPA.observer();
+ that.permission_status = 'unknown'; // [unknown, set, none]
+
+ that.refresh_on_success = function(data, text_status, xhr) {
+ // do not load data from batch
+
+ that.show_content();
+ };
+
+ that.create_refresh_command = function() {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var batch = IPA.batch_command({
+ name: 'dnszone_details_refresh'
+ });
+
+ var dnszone_command = that.details_facet_create_refresh_command();
+
+ dnszone_command.on_success = function(data, text_status, xhr) {
+ // create data that mimics dnszone-show output
+ var dnszone_data = {};
+ dnszone_data.result = data;
+ that.load(dnszone_data);
+ };
+
+ batch.add_command(dnszone_command);
+
+ var permission_name = IPA.dns.zone_permission_name.replace('${dnszone}', pkey);
+
+ var permission_command = IPA.command({
+ entity: 'permission',
+ method: 'show',
+ args: [permission_name],
+ options: {},
+ retry: false
+ });
+
+ permission_command.on_success = function(data, text_status, xhr) {
+ that.permission_status = 'set';
+ that.permission_load.notify([that.permission_status], that);
+ };
+
+ permission_command.on_error = function(xhr, text_status, error_thrown) {
+ if (error_thrown && error_thrown.code === 4001) {
+ //NotFound error
+ that.permission_status = 'none';
+ } else {
+ that.permission_status = 'unknown';
+ }
+
+ that.permission_load.notify([that.permission_status], that);
+ };
+
+ batch.add_command(permission_command);
+
+ return batch;
+ };
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.refresh();
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ that.refresh();
+ };
+
+ if (!no_init) that.init_details_facet();
+
+ return that;
+};
+
+IPA.dnszone_name_section = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.details_table_section(spec);
+
+ that.create = function(container) {
+ that.container = container;
+
+ that.message_container = $('<div/>', {
+ style: 'display: none',
+ 'class': 'dialog-message ui-state-highlight ui-corner-all'
+ }).appendTo(that.container);
+
+ var table = $('<table/>', {
+ 'class': 'section-table'
+ }).appendTo(that.container);
+
+ var idnsname = that.widgets.get_widget('idnsname');
+
+ var tr = $('<tr/>').appendTo(table);
+
+ var td = $('<td/>', {
+ 'class': 'section-cell-label',
+ title: idnsname.label
+ }).appendTo(tr);
+
+ var label = $('<label/>', {
+ name: 'idnsname',
+ 'class': 'field-label',
+ 'for': idnsname.radio_id
+ }).appendTo(td);
+
+ idnsname.create_radio(label);
+
+ label.append(idnsname.label+':');
+
+ idnsname.create_required(td);
+
+ td = $('<td/>', {
+ 'class': 'section-cell-field',
+ title: idnsname.label
+ }).appendTo(tr);
+
+ var span = $('<span/>', {
+ name: 'idnsname',
+ 'class': 'field'
+ }).appendTo(td);
+
+ idnsname.create(span);
+
+ var idnsname_input = $('input', span);
+
+ var name_from_ip = that.widgets.get_widget('name_from_ip');
+
+ tr = $('<tr/>').appendTo(table);
+
+ td = $('<td/>', {
+ 'class': 'section-cell-label',
+ title: name_from_ip.label
+ }).appendTo(tr);
+
+ label = $('<label/>', {
+ name: 'name_from_ip',
+ 'class': 'field-label',
+ 'for': name_from_ip.radio_id
+ }).appendTo(td);
+
+ name_from_ip.create_radio(label);
+
+ label.append(name_from_ip.label+':');
+
+ name_from_ip.create_required(td);
+
+ td = $('<td/>', {
+ 'class': 'section-cell-field',
+ title: name_from_ip.label
+ }).appendTo(tr);
+
+ span = $('<span/>', {
+ name: 'name_from_ip',
+ 'class': 'field'
+ }).appendTo(td);
+
+ name_from_ip.create(span);
+
+ idnsname.radio.click();
+ };
+
+
+ return that;
+};
+
+IPA.add_dns_zone_name_policy = function() {
+
+ var that = IPA.facet_policy();
+
+ that.init = function() {
+ var idnsname_w = this.container.widgets.get_widget('name.idnsname');
+ var name_from_ip_w = this.container.widgets.get_widget('name.name_from_ip');
+
+ var idnsname_f = this.container.fields.get_field('idnsname');
+ var name_from_ip_f = this.container.fields.get_field('name_from_ip');
+
+ idnsname_w.radio_clicked.attach(function() {
+ idnsname_w.input.prop('disabled', false);
+ name_from_ip_w.input.prop('disabled', true);
+
+ idnsname_f.set_required(true);
+ name_from_ip_f.set_required(false);
+
+ name_from_ip_f.reset();
+ });
+
+ name_from_ip_w.radio_clicked.attach(function() {
+ idnsname_w.input.prop('disabled', true);
+ name_from_ip_w.input.prop('disabled', false);
+
+ idnsname_f.set_required(false);
+ name_from_ip_f.set_required(true);
+
+ idnsname_f.reset();
+ });
+ };
+
+ return that;
+};
+
+IPA.dnszone_name_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.text_widget(spec);
+
+ that.radio_name = spec.radio_name;
+ that.radio_clicked = IPA.observer();
+ that.text_save = that.save;
+ that.radio_id = IPA.html_util.get_next_id(that.radio_name);
+
+ that.save = function() {
+
+ var values = [];
+
+ if (that.radio.is(':checked')) {
+ values = that.text_save();
+ }
+ return values;
+ };
+
+ that.create_radio = function(container) {
+
+ that.radio = $('<input/>', {
+ type: 'radio',
+ id: that.radio_id,
+ name: that.radio_name,
+ value: that.name,
+ click: function() {
+ that.radio_clicked.notify([], that);
+ }
+ }).appendTo(container);
+ };
+
+ return that;
+};
+
+IPA.widget_factories['dnszone_name'] = IPA.dnszone_name_widget;
+
+IPA.force_dnszone_add_checkbox_widget = function(spec) {
+ var metadata = IPA.get_command_option('dnszone_add', spec.name);
+ spec.label = metadata.label;
+ spec.tooltip = metadata.doc;
+ return IPA.checkbox_widget(spec);
+};
+
+IPA.widget_factories['force_dnszone_add_checkbox'] = IPA.force_dnszone_add_checkbox_widget;
+IPA.field_factories['force_dnszone_add_checkbox'] = IPA.checkbox_field;
+
+IPA.dnszone_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.create = function() {
+ that.entity_adder_dialog_create();
+ that.container.addClass('dnszone-adder-dialog');
+ };
+
+ return that;
+};
+
+IPA.dns.add_permission_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'add_permission';
+ spec.label = spec.label || IPA.messages.objects.dnszone.add_permission;
+ spec.enable_cond = spec.enable_cond || ['permission-none', 'managedby_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var pkey = IPA.nav.get_state('dnszone-pkey');
+
+ var command = IPA.command({
+ entity: 'dnszone',
+ method: 'add_permission',
+ args: [pkey],
+ options: {},
+ on_success: function(data, text_status, xhr) {
+ facet.refresh();
+ IPA.notify_success(data.result.summary);
+ }
+ });
+
+ command.execute();
+ };
+
+ return that;
+};
+
+IPA.dns.remove_permission_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'remove_permission';
+ spec.label = spec.label || IPA.messages.objects.dnszone.remove_permission;
+ spec.enable_cond = spec.enable_cond || ['permission-set', 'managedby_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var pkey = IPA.nav.get_state('dnszone-pkey');
+
+ var command = IPA.command({
+ entity: 'dnszone',
+ method: 'remove_permission',
+ args: [pkey],
+ options: {},
+ on_success: function(data, text_status, xhr) {
+ facet.refresh();
+ IPA.notify_success(data.result.summary);
+ }
+ });
+
+ command.execute();
+ };
+
+ return that;
+};
+
+IPA.dns.zone_has_permission_evaluator = function(spec) {
+ spec = spec || {};
+
+ spec.event = spec.event || 'permission_load';
+
+ var that = IPA.state_evaluator(spec);
+
+ that.on_event = function(permission_status) {
+
+ var old_state = that.state;
+ that.state = [
+ 'permission-'+permission_status
+ ];
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.dns.record_search_facet = function(spec) {
+
+ var that = IPA.nested_search_facet(spec);
+
+ that.get_records = function(pkeys, on_success, on_error) {
+
+ var batch = IPA.batch_command({
+ name: that.get_records_command_name(),
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ var zone = IPA.nav.get_state('dnszone-pkey');
+
+ for (var i=0; i<pkeys.length; i++) {
+ var pkey = pkeys[i];
+
+ var command = IPA.command({
+ entity: that.table.entity.name,
+ method: 'show',
+ args: [zone, pkey],
+ options: { all: true }
+ });
+
+ batch.add_command(command);
+ }
+
+ batch.execute();
+ };
+
+
+ that.load_records = function(records) {
+ that.table.empty();
+
+ var types = IPA.dns_record_types();
+
+ for (var i=0; i<records.length; i++) {
+
+ var original = records[i];
+ var record = {
+ idnsname: original.idnsname,
+ values: []
+ };
+
+ for (var j=0; j<types.length; j++) {
+ var type = types[j];
+ if (!original[type.value]) continue;
+
+ var values = original[type.value];
+ for (var k=0; k<values.length; k++) {
+ record.values.push({
+ type: type.label,
+ data: values[k]
+ });
+ }
+ }
+
+ that.add_record(record);
+ }
+ that.table.set_values(that.selected_values);
+ };
+
+ that.add_record = function(record) {
+
+ for (var i=0; i<record.values.length; i++) {
+
+ var value = record.values[i];
+
+ if (i === 0) {
+ value.idnsname = record.idnsname;
+ }
+
+ var tr = that.table.add_record(value);
+
+ if (i > 0) {
+ $('input[name="'+that.table.name+'"]', tr).remove();
+ }
+ }
+ };
+
+ return that;
+};
+
+IPA.dns.record_search_deleter_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.search_deleter_dialog(spec);
+
+ that.create_command = function() {
+
+ var batch = that.search_deleter_dialog_create_command();
+
+ for (var i=0; i<batch.commands.length; i++) {
+ var command = batch.commands[i];
+ command.set_option('del_all', true);
+ }
+
+ return batch;
+ };
+
+ return that;
+};
+
+IPA.dns.record_metadata = null;
+IPA.dns.get_record_metadata = function() {
+
+ if (IPA.dns.record_metadata === null) {
+
+ IPA.dns.record_metadata = [
+ {
+ name: 'arecord',
+ attributes: [
+ {
+ name: 'a_part_ip_address',
+ validators: [IPA.ip_v4_address_validator()]
+ },
+ {
+ type: 'checkbox',
+ name: 'a_extra_create_reverse'
+ }
+ ],
+ columns: [
+ {
+ factory: IPA.dns.ptr_redirection_column,
+ name: 'a_part_ip_address'
+ }
+ ]
+ },
+ {
+ name: 'aaaarecord',
+ attributes: [
+ {
+ name:'aaaa_part_ip_address',
+ validators: [IPA.ip_v6_address_validator()]
+ },
+ {
+ type: 'checkbox',
+ name: 'aaaa_extra_create_reverse'
+ }
+ ],
+ columns: [
+ {
+ factory: IPA.dns.ptr_redirection_column,
+ name: 'aaaa_part_ip_address'
+ }
+ ]
+ },
+ {
+ name: 'a6record',
+ attributes: [
+ 'a6_part_data'
+ ],
+ columns: ['a6_part_data']
+ },
+ {
+ name: 'afsdbrecord',
+ attributes: [
+ 'afsdb_part_subtype',
+ 'afsdb_part_hostname'
+ ],
+ columns: ['afsdb_part_subtype', 'afsdb_part_hostname']
+ },
+ {
+ name: 'certrecord',
+ attributes: [
+ 'cert_part_type',
+ 'cert_part_key_tag',
+ 'cert_part_algorithm',
+ {
+ name: 'cert_part_certificate_or_crl',
+ type: 'textarea'
+ }
+ ],
+ columns: ['cert_part_type','cert_part_key_tag','cert_part_algorithm']
+ },
+ {
+ name: 'cnamerecord',
+ attributes: [
+ 'cname_part_hostname'
+ ],
+ columns: ['cname_part_hostname']
+ },
+ {
+ name: 'dnamerecord',
+ attributes: [
+ 'dname_part_target'
+ ],
+ columns: ['dname_part_target']
+ },
+ {
+ name: 'dsrecord',
+ attributes: [
+ 'ds_part_key_tag',
+ 'ds_part_algorithm',
+ 'ds_part_digest_type',
+ {
+ name: 'ds_part_digest',
+ type: 'textarea'
+ }
+ ],
+ columns: ['ds_part_key_tag', 'ds_part_algorithm',
+ 'ds_part_digest_type']
+ },
+ {
+ name: 'keyrecord',
+ attributes: [
+ 'key_part_flags',
+ 'key_part_protocol',
+ 'key_part_algorithm',
+ {
+ name: 'key_part_public_key',
+ type: 'textarea'
+ }
+ ],
+ columns: ['key_part_flags', 'key_part_protocol',
+ 'key_part_algorithm']
+ },
+ {
+ name: 'kxrecord',
+ attributes: [
+ 'kx_part_preference',
+ 'kx_part_exchanger'
+ ],
+ columns: ['kx_part_preference', 'kx_part_exchanger']
+ },
+ {
+ name: 'locrecord',
+ attributes: [
+ 'loc_part_lat_deg',
+ 'loc_part_lat_min',
+ 'loc_part_lat_sec',
+ {
+ name: 'loc_part_lat_dir',
+ options: IPA.create_options(['N','S']),
+ type: 'radio',
+ widget_opt: {
+ default_value: 'N'
+ }
+ },
+ 'loc_part_lon_deg',
+ 'loc_part_lon_min',
+ 'loc_part_lon_sec',
+ {
+ name: 'loc_part_lon_dir',
+ options: IPA.create_options(['E','W']),
+ type: 'radio',
+ widget_opt: {
+ default_value: 'E'
+ }
+ },
+ 'loc_part_altitude',
+ 'loc_part_size',
+ 'loc_part_h_precision',
+ 'loc_part_v_precision'
+ ],
+ columns: ['dnsdata']
+ },
+ {
+ name: 'mxrecord',
+ attributes: [
+ 'mx_part_preference',
+ 'mx_part_exchanger'
+ ],
+ columns: ['mx_part_preference', 'mx_part_exchanger']
+ },
+ {
+ name: 'naptrrecord',
+ attributes: [
+ 'naptr_part_order',
+ 'naptr_part_preference',
+ {
+ name: 'naptr_part_flags',
+ type: 'select',
+ options: IPA.create_options(['S', 'A', 'U', 'P'])
+ },
+ 'naptr_part_service',
+ 'naptr_part_regexp',
+ 'naptr_part_replacement'
+ ],
+ adder_attributes: [],
+ columns: ['dnsdata']
+ },
+ {
+ name: 'nsrecord',
+ attributes: [
+ 'ns_part_hostname'
+ ],
+ adder_attributes: [],
+ columns: ['ns_part_hostname']
+ },
+ {
+ name: 'nsecrecord',
+ attributes: [
+ 'nsec_part_next',
+ 'nsec_part_types'
+// TODO: nsec_part_types is multivalued attribute. New selector
+// widget or at least new validator should be created.
+// {
+// name: 'nsec_part_types',
+// options: IPA.create_options(['SOA', 'A', 'AAAA', 'A6', 'AFSDB',
+// 'APL', 'CERT', 'CNAME', 'DHCID', 'DLV', 'DNAME', 'DNSKEY',
+// 'DS', 'HIP', 'IPSECKEY', 'KEY', 'KX', 'LOC', 'MX', 'NAPTR',
+// 'NS', 'NSEC','NSEC3', 'NSEC3PARAM', 'PTR', 'RRSIG', 'RP',
+// 'SIG', 'SPF', 'SRV', 'SSHFP', 'TA', 'TKEY', 'TSIG', 'TXT']),
+// type: 'select'
+// }
+ ],
+ adder_attributes: [],
+ columns: [ 'nsec_part_next', 'nsec_part_types']
+ },
+ {
+ name: 'ptrrecord',
+ attributes: [
+ 'ptr_part_hostname'
+ ],
+ adder_attributes: [],
+ columns: [ 'ptr_part_hostname']
+ },
+ {
+ name: 'rrsigrecord',
+ attributes: [
+ {
+ name: 'rrsig_part_type_covered',
+ type: 'select',
+ options: IPA.create_options(['SOA', 'A', 'AAAA', 'A6', 'AFSDB',
+ 'APL', 'CERT', 'CNAME', 'DHCID', 'DLV', 'DNAME',
+ 'DNSKEY', 'DS', 'HIP', 'IPSECKEY', 'KEY', 'KX',
+ 'LOC', 'MX', 'NAPTR', 'NS', 'NSEC', 'NSEC3',
+ 'NSEC3PARAM', 'PTR', 'RRSIG', 'RP', 'SPF', 'SRV',
+ 'SSHFP', 'TA', 'TKEY', 'TSIG', 'TXT'])
+ },
+ 'rrsig_part_algorithm',
+ 'rrsig_part_labels',
+ 'rrsig_part_original_ttl',
+ 'rrsig_part_signature_expiration',
+ 'rrsig_part_signature_inception',
+ 'rrsig_part_key_tag',
+ 'rrsig_part_signers_name',
+ {
+ name: 'rrsig_part_signature',
+ type: 'textarea'
+ }
+ ],
+ adder_attributes: [],
+ columns: ['dnsdata']
+ },
+ {
+ name: 'sigrecord',
+ attributes: [
+ {
+ name: 'sig_part_type_covered',
+ type: 'select',
+ options: IPA.create_options(['SOA', 'A', 'AAAA', 'A6', 'AFSDB',
+ 'APL', 'CERT', 'CNAME', 'DHCID', 'DLV', 'DNAME',
+ 'DNSKEY', 'DS', 'HIP', 'IPSECKEY', 'KEY', 'KX',
+ 'LOC', 'MX', 'NAPTR', 'NS', 'NSEC', 'NSEC3',
+ 'NSEC3PARAM', 'PTR', 'RRSIG', 'RP', 'SPF', 'SRV',
+ 'SSHFP', 'TA', 'TKEY', 'TSIG', 'TXT'])
+ },
+ 'sig_part_algorithm',
+ 'sig_part_labels',
+ 'sig_part_original_ttl',
+ 'sig_part_signature_expiration',
+ 'sig_part_signature_inception',
+ 'sig_part_key_tag',
+ 'sig_part_signers_name',
+ {
+ name: 'sig_part_signature',
+ type: 'textarea'
+ }
+ ],
+ adder_attributes: [],
+ columns: ['dnsdata']
+ },
+ {
+ name: 'srvrecord',
+ attributes: [
+ 'srv_part_priority',
+ 'srv_part_weight',
+ 'srv_part_port',
+ 'srv_part_target'
+ ],
+ adder_attributes: [],
+ columns: ['srv_part_priority', 'srv_part_weight', 'srv_part_port',
+ 'srv_part_target']
+ },
+ {
+ name: 'sshfprecord',
+ attributes: [
+ 'sshfp_part_algorithm',
+ 'sshfp_part_fp_type',
+ {
+ name: 'sshfp_part_fingerprint',
+ type: 'textarea'
+ }
+ ],
+ adder_attributes: [],
+ columns: ['sshfp_part_algorithm', 'sshfp_part_fp_type']
+ },
+ {
+ name: 'txtrecord',
+ attributes: [
+ 'txt_part_data'
+ ],
+ adder_attributes: [],
+ columns: ['txt_part_data']
+ }
+ ];
+
+ //set required flags for attributes based on 'dnsrecord_optional' flag
+ //in param metadata
+
+ for (var i=0; i<IPA.dns.record_metadata.length; i++) {
+ var type = IPA.dns.record_metadata[i];
+
+ for (var j=0; j<type.attributes.length; j++) {
+ var attr = type.attributes[j];
+ if (typeof attr === 'string') {
+ attr = {
+ name: attr
+ };
+ type.attributes[j] = attr;
+ }
+ var attr_meta = IPA.get_entity_param('dnsrecord', attr.name);
+
+ if (attr_meta && attr_meta.flags.indexOf('dnsrecord_optional') === -1) {
+ attr.required = true;
+ }
+ }
+ }
+
+ }
+
+ return IPA.dns.record_metadata;
+};
+
+
+IPA.dns.get_record_type = function(type_name) {
+
+ var metadata = IPA.dns.get_record_metadata();
+
+ for (var i=0; i<metadata.length; i++) {
+ var type = metadata[i];
+ if (type.name === type_name) return type;
+ }
+
+ return null;
+};
+
+IPA.dns.record_entity = function(spec) {
+
+ spec = spec || {};
+
+ spec.policies = spec.policies || [
+ IPA.facet_update_policy({
+ source_facet: 'details',
+ dest_entity: 'dnszone',
+ dest_facet: 'records'
+ }),
+ IPA.adder_facet_update_policy()
+ ];
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+
+ if (!IPA.dns_enabled) {
+ throw {
+ expected: true
+ };
+ }
+
+ that.entity_init();
+
+ that.builder.containing_entity('dnszone').
+ details_facet({
+ factory: IPA.dns.record_details_facet,
+ disable_breadcrumb: false,
+ fields: [
+ {
+ type: 'dnsrecord_host_link',
+ name: 'idnsname',
+ other_entity: 'host',
+ widget: 'identity.idnsname'
+ }
+ ],
+ widgets:[
+ {
+ name: 'identity',
+ label: IPA.messages.details.identity,
+ type: 'details_table_section',
+ widgets: [
+ {
+ type: 'dnsrecord_host_link',
+ name: 'idnsname',
+ other_entity: 'host',
+ label: IPA.get_entity_param(
+ 'dnsrecord', 'idnsname').label
+ }
+ ]
+ }
+ ]
+ }).
+ adder_dialog({
+ factory: IPA.dns.record_adder_dialog,
+ fields: [
+ {
+ name: 'idnsname',
+ widget: 'general.idnsname'
+ },
+ {
+ name: 'record_type',
+ type: 'dnsrecord_type',
+ flags: ['no_command'],
+ widget: 'general.record_type'
+ }
+ ],
+ widgets: [
+ {
+ name: 'general',
+ type: 'details_table_section_nc',
+ widgets: [
+ 'idnsname',
+ {
+ type: 'dnsrecord_type',
+ name: 'record_type',
+ label: IPA.messages.objects.dnsrecord.type
+ }
+ ]
+ }
+ ],
+ policies: [
+ IPA.dnsrecord_adder_dialog_type_policy({
+ type_field: 'record_type'
+ })
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.dns.record_adder_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.retry = spec.retry !== undefined ? spec.retry : false;
+
+ IPA.dns.record_prepare_spec(spec, IPA.dns.record_prepare_editor_for_type);
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.on_error = IPA.create_4304_error_handler(that);
+
+ return that;
+};
+
+IPA.dns.record_details_facet = function(spec) {
+
+ IPA.dns.record_prepare_details_spec(spec);
+
+ var that = IPA.details_facet(spec);
+
+ that.load = function(data) {
+
+ if (!data.result.result.idnsname) {
+ that.reset();
+ var dialog = IPA.dnsrecord_redirection_dialog();
+ dialog.open(that.container);
+ return;
+ }
+
+ that.details_facet_load(data);
+ };
+
+ that.create_refresh_command = function() {
+
+ var command = that.details_facet_create_refresh_command();
+ command.set_option('structured', true);
+ return command;
+ };
+
+ return that;
+};
+
+IPA.dnsrecord_redirection_dialog = function(spec) {
+ spec = spec || {};
+ spec.title = spec.title || IPA.messages.dialogs.redirection;
+
+ var that = IPA.message_dialog(spec);
+
+ that.create = function() {
+ $('<p/>', {
+ 'text': IPA.messages.objects.dnsrecord.deleted_no_data
+ }).appendTo(that.container);
+ $('<p/>', {
+ 'text': IPA.messages.objects.dnsrecord.redirection_dnszone
+ }).appendTo(that.container);
+ };
+
+ that.on_ok = function() {
+ IPA.nav.show_page('dnszone','default');
+ };
+
+ return that;
+};
+
+/*
+ * Spec preparation methods
+ */
+
+IPA.dns.record_prepare_spec = function(spec, type_prepare_method) {
+
+ var metadata = IPA.dns.get_record_metadata();
+
+ var fields = [];
+ var widgets = [];
+
+ for (var i=0; i<metadata.length; i++) {
+
+ var type = metadata[i];
+
+ type_prepare_method(type, fields, widgets);
+ }
+
+ IPA.dns.extend_spec(spec, fields, widgets);
+};
+
+IPA.dns.extend_spec = function(spec, fields, widgets) {
+
+ if (spec.sections) delete spec.sections;
+
+ if (spec.fields instanceof Array) {
+ spec.fields.push.apply(spec.fields, fields);
+ } else {
+ spec.fields = fields;
+ }
+
+ if (spec.widgets instanceof Array) {
+ spec.widgets.push.apply(spec.widgets, widgets);
+ } else {
+ spec.widgets = widgets;
+ }
+};
+
+IPA.dns.record_prepare_editor_for_type = function(type, fields, widgets, update) {
+
+ var set_defined = function(property, object, name) {
+ if (property !== undefined) {
+ object[name] = property;
+ }
+ };
+
+ var copy_obj = function(source, dest) {
+ if (source !== null || source !== undefined) {
+ $.extend(source,dest);
+ }
+ };
+
+ var section = {
+ name: type.name,
+ type: 'details_table_section_nc',
+ widgets: []
+ };
+ widgets.push(section);
+
+ for (var i=0; i<type.attributes.length;i++) {
+ var attribute = type.attributes[i];
+
+ if (typeof attribute === 'string') {
+ attribute = {
+ name: attribute
+ };
+ }
+
+ var metadata = IPA.get_entity_param('dnsrecord', attribute.name);
+ if (metadata && update && metadata.flags &&
+ metadata.flags.indexOf('no_update') > -1) continue;
+
+ //create field
+ var field = {};
+
+ field.name = attribute.name;
+ field.label = attribute.label ||
+ IPA.dns.record_get_attr_label(attribute.name);
+ set_defined(attribute.type, field, 'type');
+ set_defined(attribute.validators, field, 'validators');
+ set_defined(attribute.required, field, 'required');
+ copy_obj(widget, attribute.field_opt);
+
+ field.widget = type.name+'.'+field.name;
+ fields.push(field);
+
+ //create editor widget
+ var widget = {};
+ if (typeof attribute === 'string') {
+ widget.name = attribute;
+ } else {
+ widget.name = attribute.name;
+ set_defined(attribute.type, widget, 'type');
+ set_defined(attribute.options, widget, 'options');
+ copy_obj(widget, attribute.widget_opt);
+ }
+ section.widgets.push(widget);
+ }
+};
+
+IPA.dns.record_prepare_details_spec = function(spec, type_prepare_method) {
+
+ var metadata = IPA.dns.get_record_metadata();
+
+ var fields = [];
+ var widgets = [];
+
+ var standard_record_section = {
+ name: 'standard_types',
+ type: 'details_table_section',
+ label: IPA.messages.objects.dnsrecord.standard,
+ widgets: []
+ };
+
+ var other_record_section = {
+ name: 'other_types',
+ type: 'details_table_section',
+ label: IPA.messages.objects.dnsrecord.other,
+ widgets: []
+ };
+
+ widgets.push(standard_record_section);
+ widgets.push(other_record_section);
+
+ var standard_types = ['arecord', 'aaaarecord', 'ptrrecord', 'srvrecord',
+ 'txtrecord', 'cnamerecord', 'mxrecord', 'nsrecord'];
+
+ for (var i=0; i<metadata.length; i++) {
+
+ var type = metadata[i];
+
+ if (standard_types.indexOf(type.name) > -1) {
+ IPA.dns.record_prepare_details_for_type(type, fields, standard_record_section);
+ } else {
+ IPA.dns.record_prepare_details_for_type(type, fields, other_record_section);
+ }
+ }
+
+ IPA.dns.extend_spec(spec, fields, widgets);
+};
+
+IPA.dns.record_prepare_details_for_type = function(type, fields, container) {
+
+ var index = type.name.search('record$');
+ var dnstype = type.name.substring(0, index).toUpperCase();
+
+ var type_widget = {
+ name: type.name,
+ type: 'dnsrecord_type_table',
+ record_type: type.name,
+ value_attribute: 'dnsdata',
+ dnstype: dnstype,
+ columns: type.columns
+ };
+
+ container.widgets.push(type_widget);
+
+ var field = {
+ name: type.name,
+ type: 'dnsrecord_type_table',
+ dnstype: dnstype,
+ label: dnstype,
+ widget: container.name+'.'+type.name
+ };
+
+ fields.push(field);
+};
+
+/*
+ * Widgets and policies
+ */
+
+
+IPA.dnsrecord_host_link_field = function(spec) {
+ var that = IPA.link_field(spec);
+ that.other_pkeys = function() {
+ var pkey = that.entity.get_primary_key();
+ return [pkey[0]+'.'+pkey[1]];
+ };
+ return that;
+};
+
+IPA.field_factories['dnsrecord_host_link'] = IPA.dnsrecord_host_link_field;
+IPA.widget_factories['dnsrecord_host_link'] = IPA.link_widget;
+
+IPA.dns_record_types = function() {
+
+ //only supported
+ var attrs = ['A', 'AAAA', 'A6', 'AFSDB', 'CERT', 'CNAME', 'DNAME',
+ 'DS','KEY', 'KX', 'LOC', 'MX', 'NAPTR', 'NS', 'NSEC',
+ 'PTR', 'RRSIG', 'SRV', 'SIG', 'SSHFP', 'TXT'];
+ var record_types = [];
+ for (var i=0; i<attrs.length; i++) {
+ var attr = attrs[i];
+
+ var rec_type = {
+ label: attr,
+ value: attr.toLowerCase()+'record'
+ };
+ record_types.push(rec_type);
+ }
+ return record_types;
+};
+
+IPA.dns.record_get_attr_label = function(part_name) {
+
+ var metadata = IPA.get_entity_param('dnsrecord', part_name);
+
+ if (!metadata) return null;
+
+ var label = metadata.label;
+
+ if (part_name.indexOf('_part_') > -1) {
+
+ label = label.substring(label.indexOf(' '));
+ } else if (part_name.indexOf('_extra_') > -1) {
+
+ label = label.substring(label.indexOf(' '));
+ }
+
+ return label;
+};
+
+
+IPA.dnsrecord_type_field = function(spec) {
+
+ spec = spec || {};
+ var that = IPA.field(spec);
+
+ that.type_changed = IPA.observer();
+
+ that.get_type = function() {
+
+ return that.widget.save()[0];
+ };
+
+ that.on_type_change = function() {
+
+ that.type_changed.notify([], that);
+ };
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ that.widget.value_changed.attach(that.on_type_change);
+ };
+
+ that.reset = function() {
+ that.field_reset();
+ that.on_type_change();
+ };
+
+ return that;
+};
+
+IPA.field_factories['dnsrecord_type'] = IPA.dnsrecord_type_field;
+
+
+IPA.dnsrecord_type_widget = function(spec) {
+
+ spec.options = IPA.dns_record_types();
+ var that = IPA.select_widget(spec);
+ return that;
+};
+
+IPA.widget_factories['dnsrecord_type'] = IPA.dnsrecord_type_widget;
+
+
+IPA.dnsrecord_adder_dialog_type_policy = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.facet_policy(spec);
+
+ that.type_field_name = spec.type_field;
+
+ that.post_create = function() {
+ that.type_field = that.container.fields.get_field(that.type_field_name);
+ that.type_field.type_changed.attach(that.on_type_change);
+ that.on_type_change();
+ };
+
+ that.on_type_change = function() {
+
+ var type = that.type_field.get_type();
+
+ that.allow_fields_for_type(type);
+ that.show_widgets_for_type(type);
+ };
+
+ that.allow_fields_for_type = function(type) {
+
+ type = type.substring(0, type.indexOf('record'));
+
+ var fields = that.container.fields.get_fields();
+
+ for (var i=0; i<fields.length; i++) {
+
+ var field = fields[i];
+ var fieldtype;
+ var attr_types = ['_part_', '_extra_', 'record'];
+
+ for (var j=0; j<attr_types.length; j++) {
+ var index = field.name.indexOf(attr_types[j]);
+ if (index > -1) {
+ fieldtype = field.name.substring(0, index);
+ break;
+ }
+ }
+
+ field.enabled = (field.name === 'idnsname' ||
+ field.name === that.type_field_name ||
+ fieldtype === type);
+ }
+ };
+
+ that.show_widgets_for_type = function(type) {
+
+ var widgets = that.container.widgets.get_widgets();
+
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+ var visible = widget.name.indexOf(type) === 0 ||
+ widget.name === 'general';
+ widget.set_visible(visible);
+ }
+ };
+
+ return that;
+};
+
+
+IPA.dns.record_type_table_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.dnstype = spec.dnstype;
+
+ that.load = function(record) {
+
+ var data = {};
+
+ data.idnsname = record.idnsname;
+ data.dnsrecords = [];
+
+ for (var i=0, j=0; i<record.dnsrecords.length; i++) {
+
+ var dnsrecord = record.dnsrecords[i];
+ if(dnsrecord.dnstype === that.dnstype) {
+
+ dnsrecord.position = j;
+ j++;
+ data.dnsrecords.push(dnsrecord);
+ }
+ }
+
+ that.values = data;
+
+ that.load_writable(record);
+ that.reset();
+ };
+
+ return that;
+};
+
+IPA.field_factories['dnsrecord_type_table'] = IPA.dns.record_type_table_field;
+
+
+IPA.dns.record_type_table_widget = function(spec) {
+
+ spec = spec || {};
+ spec.columns = spec.columns || [];
+
+ spec.columns.push({
+ name: 'position',
+ label: '',
+ factory: IPA.dns.record_modify_column,
+ width: '106px'
+ });
+
+ var that = IPA.table_widget(spec);
+
+ that.dnstype = spec.dnstype;
+
+ that.create_column = function(spec) {
+
+ if (typeof spec === 'string') {
+ spec = {
+ name: spec
+ };
+ }
+
+ spec.entity = that.entity;
+ spec.label = spec.label || IPA.dns.record_get_attr_label(spec.name);
+
+ var factory = spec.factory || IPA.column;
+
+ var column = factory(spec);
+ that.add_column(column);
+ return column;
+ };
+
+ that.create_columns = function() {
+ that.clear_columns();
+ if (spec.columns) {
+ for (var i=0; i<spec.columns.length; i++) {
+ that.create_column(spec.columns[i]);
+ }
+ }
+
+ var modify_column = that.columns.get('position');
+ modify_column.link_handler = that.on_modify;
+ };
+
+ that.create = function(container) {
+
+ that.create_columns();
+ that.table_create(container);
+
+ container.addClass('dnstype-table');
+
+ that.remove_button = IPA.action_button({
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon',
+ 'class': 'action-button-disabled',
+ click: function() {
+ if (!that.remove_button.hasClass('action-button-disabled')) {
+ that.remove_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.buttons);
+
+ that.add_button = IPA.action_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon',
+ click: function() {
+ if (!that.add_button.hasClass('action-button-disabled')) {
+ that.add_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.buttons);
+ };
+
+ that.set_enabled = function(enabled) {
+ that.table_set_enabled(enabled);
+ if (enabled) {
+ if(that.add_button) {
+ that.add_button.removeClass('action-button-disabled');
+ }
+ } else {
+ $('.action-button', that.table).addClass('action-button-disabled');
+ that.unselect_all();
+ }
+ that.enabled = enabled;
+ };
+
+ that.select_changed = function() {
+
+ var values = that.get_selected_values();
+
+ if (that.remove_button) {
+ if (values.length === 0) {
+ that.remove_button.addClass('action-button-disabled');
+ } else {
+ that.remove_button.removeClass('action-button-disabled');
+ }
+ }
+ };
+
+ that.add_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_add_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_add_dialog();
+ }
+ };
+
+ that.remove_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_remove_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_remove_dialog();
+ }
+ };
+
+ that.show_remove_dialog = function() {
+
+ var selected_values = that.get_selected_values();
+
+ if (!selected_values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return;
+ }
+
+ var dialog = IPA.deleter_dialog({
+ entity: that.entity,
+ values: selected_values
+ });
+
+ dialog.execute = function() {
+ that.remove(
+ selected_values,
+ that.idnsname[0],
+ function(data) {
+ that.reload_facet(data);
+ that.notify_facet_update();
+ that.facet.nofify_update_success();
+ },
+ function() {
+ that.refresh_facet();
+ }
+ );
+ };
+
+
+ dialog.open(that.container);
+ };
+
+ that.remove = function(values, pkey, on_success, on_error) {
+
+ var dnszone = IPA.nav.get_state('dnszone-pkey');
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: 'del',
+ args: [dnszone, pkey],
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ var record_name = that.dnstype.toLowerCase()+'record';
+ command.set_option(record_name, values);
+ command.set_option('structured', true);
+
+ command.execute();
+ };
+
+ that.create_add_dialog = function() {
+
+ var title = IPA.messages.dialogs.add_title;
+ var label = that.entity.metadata.label_singular;
+
+ var dialog_spec = {
+ entity: that.entity,
+ fields: [],
+ widgets: [],
+ retry: false,
+ title: title.replace('${entity}', label)
+ };
+
+ var dnstype = that.dnstype.toLowerCase();
+ var type = IPA.dns.get_record_type(dnstype+'record');
+
+ IPA.dns.record_prepare_editor_for_type(type, dialog_spec.fields,
+ dialog_spec.widgets);
+
+ var dialog = IPA.entity_adder_dialog(dialog_spec);
+
+ var cancel_button = dialog.buttons.get('cancel');
+ dialog.buttons.empty();
+
+ dialog.on_error = IPA.create_4304_error_handler(dialog);
+
+ dialog.get_add_message = function() {
+ var label = that.entity.metadata.label_singular;
+ var message = IPA.messages.dialogs.add_confirmation;
+ message = message.replace('${entity}', label);
+ return message;
+ };
+
+ dialog.create_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ click: function() {
+ dialog.hide_message();
+ dialog.add(
+ function(data, text_status, xhr) {
+
+ if (data.result.result.dnsrecords) {
+ that.reload_facet(data);
+ } else {
+ that.refresh_facet();
+ }
+ dialog.close();
+ that.notify_facet_update();
+ IPA.notify_success(dialog.get_add_message());
+ },
+ dialog.on_error);
+ }
+ });
+
+ dialog.create_button({
+ name: 'add_and_add_another',
+ label: IPA.messages.buttons.add_and_add_another,
+ click: function() {
+ dialog.hide_message();
+ dialog.add(
+ function(data, text_status, xhr) {
+
+ dialog.show_message(dialog.get_add_message());
+
+ if (data.result.result.dnsrecords) {
+ that.reload_facet(data);
+ } else {
+ that.refresh_facet();
+ }
+ dialog.reset();
+ that.notify_facet_update();
+ },
+ dialog.on_error);
+ }
+ });
+
+ dialog.buttons.put('cancel', cancel_button);
+
+ dialog.create_add_command = function(record) {
+
+ var dnszone = IPA.nav.get_state('dnszone-pkey');
+
+ var command = dialog.entity_adder_dialog_create_add_command(record);
+ command.args = [dnszone, that.idnsname[0]];
+ command.set_option('structured', true);
+
+ return command;
+ };
+
+ return dialog;
+ };
+
+ that.show_add_dialog = function() {
+
+ var dialog = that.create_add_dialog();
+ dialog.open(that.container);
+ };
+
+ that.create_mod_dialog = function() {
+
+ var title = IPA.messages.dialogs.edit_title;
+ var label = that.entity.metadata.label_singular;
+
+ var dialog_spec = {
+ entity: that.entity,
+ fields: [],
+ widgets: [],
+ title: title.replace('${entity}', label)
+ };
+
+ var dnstype = that.dnstype.toLowerCase();
+
+ var type = IPA.dns.get_record_type(dnstype+'record');
+
+ IPA.dns.record_prepare_editor_for_type(type, dialog_spec.fields,
+ dialog_spec.widgets, true);
+
+ var dialog = IPA.entity_adder_dialog(dialog_spec);
+
+ dialog.buttons.empty();
+
+ dialog.create_button({
+ name: 'modify',
+ label: IPA.messages.buttons.update,
+ click: function() {
+ dialog.modify();
+ }
+ });
+
+ dialog.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ dialog.reset();
+ dialog.close();
+ }
+ });
+
+ dialog.load = function(record, full_value) {
+
+ dialog.full_value = full_value;
+
+ var fields = dialog.fields.get_fields();
+
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+ field.load(record);
+ }
+ };
+
+ dialog.modify = function() {
+
+ if (!dialog.validate()) return;
+
+ var record = {};
+ dialog.save(record);
+
+ var command = dialog.create_add_command(record);
+
+ command.on_success = function(data) {
+ that.reload_facet(data);
+ dialog.close();
+ that.notify_facet_update();
+ that.facet.nofify_update_success();
+ };
+ command.on_error = function() {
+ that.refresh_facet();
+ dialog.close();
+ };
+ command.execute();
+ };
+
+ dialog.create_add_command = function(record) {
+
+ var dnszone = IPA.nav.get_state('dnszone-pkey');
+
+ var command = dialog.entity_adder_dialog_create_add_command(record);
+
+ command.method = 'mod';
+ command.args = [dnszone, that.idnsname[0]];
+
+ var record_name = that.dnstype.toLowerCase()+'record';
+ command.set_option(record_name, dialog.full_value);
+ command.set_option('structured', true);
+
+ return command;
+ };
+
+ return dialog;
+ };
+
+ that.reload_facet = function(data) {
+
+ //FIXME: seems as bad approach
+ var facet = IPA.current_entity.get_facet();
+ facet.load(data);
+ };
+
+ that.refresh_facet = function() {
+
+ //FIXME: seems as bad approach
+ var facet = IPA.current_entity.get_facet();
+ facet.refresh();
+ };
+
+ that.notify_facet_update = function() {
+ var facet = IPA.current_entity.get_facet();
+ facet.on_update.notify();
+ };
+
+ that.update = function(values) {
+
+ that.idnsname = values.idnsname;
+ that.dnsrecords = values.dnsrecords;
+ that.table_update(that.dnsrecords);
+ that.unselect_all();
+ };
+
+ that.on_modify = function(position) {
+
+ var values = that.values[position];
+
+ var dialog = that.create_mod_dialog();
+ dialog.open();
+ dialog.load(that.records[position], values);
+
+ return false;
+ };
+
+
+ return that;
+};
+
+IPA.widget_factories['dnsrecord_type_table'] = IPA.dns.record_type_table_widget;
+
+IPA.dns.netaddr_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.multivalued_field(spec);
+
+ that.load = function(record) {
+
+ that.record = record;
+
+ that.values = that.get_value(record, that.name);
+ that.values = that.values[0].split(';');
+
+ that.load_writable(record);
+
+ that.reset();
+ };
+
+ that.test_dirty = function() {
+
+ if (that.read_only) return false;
+
+ var values = that.field_save();
+
+ //check for empty value: null, [''], '', []
+ var orig_empty = IPA.is_empty(that.values);
+ var new_empty= IPA.is_empty(values);
+ if (orig_empty && new_empty) return false;
+ if (orig_empty != new_empty) return true;
+
+ //strict equality - checks object's ref equality, numbers, strings
+ if (values === that.values) return false;
+
+ //compare values in array
+ if (values.length !== that.values.length) return true;
+
+ for (var i=0; i<values.length; i++) {
+ if (values[i] != that.values[i]) {
+ return true;
+ }
+ }
+
+ return that.widget.test_dirty();
+ };
+
+ that.save = function(record) {
+
+ var values = that.field_save();
+ var new_val = values.join(';');
+
+ if (record) {
+ record[that.name] = new_val;
+ }
+
+ return [new_val];
+ };
+
+ that.validate = function() {
+
+ var values = that.field_save();
+
+ return that.validate_core(values);
+ };
+
+ return that;
+};
+
+IPA.field_factories['netaddr'] = IPA.dns.netaddr_field;
+IPA.widget_factories['netaddr'] = IPA.multivalued_widget;
+
+
+
+IPA.dns.record_modify_column = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.column(spec);
+
+ that.text = spec.text || IPA.messages.buttons.edit;
+
+ that.setup = function(container, record, suppress_link) {
+
+ container.empty();
+
+ var value = record[that.name];
+
+ $('<a/>', {
+ href: '#'+that.text,
+ text: that.text,
+ style: 'float: right;',
+ click: function() {
+ return that.link_handler(value);
+ }
+ }).appendTo(container);
+ };
+
+ return that;
+};
+
+IPA.dns.ptr_redirection_column = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.column(spec);
+
+ that.link = true;
+
+ that.link_handler = function(value) {
+
+ var address = NET.ip_address(value);
+
+ var dialog = IPA.dns.ptr_redirection_dialog({
+ address: address
+ });
+ dialog.open();
+
+ return false;
+ };
+
+ return that;
+};
+
+IPA.dns.ptr_redirection_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.title = IPA.messages.objects.dnsrecord.ptr_redir_title;
+
+ var that = IPA.dialog(spec);
+
+ that.address = spec.address;
+
+ that.create = function() {
+
+ that.status_div = $('<div />', {
+ 'class': 'redirection-status'
+ }).appendTo(that.container);
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'close',
+ label: IPA.messages.buttons.close,
+ click: function() {
+ that.close();
+ }
+ });
+ };
+
+ that.create_add_record_button = function() {
+
+ $('<a />', {
+ text: IPA.messages.objects.dnsrecord.ptr_redir_create,
+ href: '#create_record',
+ click: function() {
+ that.create_record();
+ return false;
+ }
+ }).appendTo(that.container);
+ };
+
+ that.append_status = function(message) {
+
+ $('<div />', {
+ text: message
+ }).appendTo(that.status_div);
+ };
+
+ that.open = function() {
+
+ that.dialog_open();
+ that.start_redirect();
+ };
+
+ //step 0 - preparation
+ that.start_redirect = function() {
+
+ if (!that.address.valid) {
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_address_err);
+ } else {
+ that.reverse_address = that.address.get_reverse().toLowerCase()+'.';
+
+ var record = IPA.nav.get_state('dnsrecord-pkey');
+ var zone = IPA.nav.get_state('dnszone-pkey');
+
+ if (record && zone && record !== '' && zone !== '') {
+ that.dns_record = {
+ name: record,
+ zone: zone
+ };
+ }
+
+ that.get_zones();
+ }
+ };
+
+ //1st step: get all zones
+ that.get_zones = function() {
+
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_zones);
+
+ var command = IPA.command({
+ entity: 'dnszone',
+ method: 'find',
+ options: {
+ pkey_only: true
+ },
+ on_success: that.find_zone,
+ on_error: function() {
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_zones_err);
+ }
+ });
+
+ command.execute();
+ };
+
+ //2nd step: find target zone
+ that.find_zone = function(data) {
+ var zones = data.result.result;
+ var target_zone = null;
+
+ for (var i=0; i<zones.length; i++) {
+
+ var zone_name = zones[i].idnsname[0];
+ if (that.reverse_address.indexOf(zone_name) > -1) {
+ var msg = IPA.messages.objects.dnsrecord.ptr_redir_zone;
+ msg = msg.replace('${zone}', zone_name);
+ that.append_status(msg);
+
+ if (!target_zone ||
+ (target_zone && zone_name.length > target_zone.length)) {
+
+ target_zone = zone_name;
+ }
+
+ break;
+ }
+ }
+
+ if (target_zone) {
+ that.zone = target_zone;
+ that.check_record();
+ } else {
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_zone_err);
+ }
+ };
+
+ //3rd step: check record existance
+ that.check_record = function(zone) {
+
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_record);
+
+ var i1 = that.reverse_address.indexOf(that.zone);
+ var record_name = that.reverse_address.substring(0,i1 - 1);
+ that.record_keys = [that.zone, record_name];
+
+ var command = IPA.command({
+ entity: 'dnsrecord',
+ method: 'show',
+ args: that.record_keys,
+ on_success: function() {
+ that.redirect();
+ },
+ on_error: function() {
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_record_err);
+ if (that.dns_record) {
+ that.create_add_record_button();
+ }
+ },
+ retry: false
+ });
+
+ command.execute();
+ };
+
+ //4th-a step: actual redirect
+ that.redirect = function() {
+
+ var entity = IPA.get_entity('dnsrecord');
+
+ IPA.nav.show_entity_page(
+ entity,
+ 'default',
+ that.record_keys);
+
+ that.close();
+ };
+
+ //4th-b optional step: create PTR record
+ that.create_record = function() {
+
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_creating);
+
+ var ptr = that.dns_record.name +'.' + that.dns_record.zone;
+
+ var command = IPA.command({
+ entity: 'dnsrecord',
+ method: 'add',
+ args: that.record_keys,
+ options: {
+ ptrrecord: [ptr]
+ },
+ on_success: function() {
+ that.redirect();
+ },
+ on_error: function() {
+ that.append_status(IPA.messages.objects.dnsrecord.ptr_redir_creating_err);
+ }
+ });
+
+ command.execute();
+ };
+
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.ip_address_validator = function(spec) {
+
+ spec = spec || {};
+ var that = IPA.validator(spec);
+
+ that.address_type = spec.address_type;
+ that.message = spec.message || IPA.messages.widget.validation.ip_address;
+
+ that.validate = function(value) {
+
+ if (IPA.is_empty(value)) return that.true_result();
+
+ var address = NET.ip_address(value);
+
+ if (!address.valid || !that.is_type_match(address.type)) {
+ return that.false_result();
+ }
+
+ return that.true_result();
+ };
+
+ that.is_type_match = function(net_type) {
+
+ return (!that.address_type ||
+
+ (that.address_type === 'IPv4' &&
+ (net_type === 'v4-quads' || net_type === 'v4-int')) ||
+
+ (that.address_type === 'IPv6' && net_type === 'v6'));
+ };
+
+ that.ip_address_validate = that.validate;
+
+ return that;
+};
+
+IPA.ip_v4_address_validator = function(spec) {
+
+ spec = spec || {};
+ spec.address_type = 'IPv4';
+ spec.message = IPA.messages.widget.validation.ip_v4_address;
+ return IPA.ip_address_validator(spec);
+};
+
+IPA.ip_v6_address_validator = function(spec) {
+
+ spec = spec || {};
+ spec.address_type = 'IPv6';
+ spec.message = IPA.messages.widget.validation.ip_v6_address;
+ return IPA.ip_address_validator(spec);
+};
+
+IPA.dnsforwarder_validator = function(spec) {
+
+ spec = spec || {};
+ var that = IPA.ip_address_validator(spec);
+
+ that.validate = function(value) {
+
+ var address_part = value;
+
+ if (value.indexOf(' ') > - 1) {
+ var parts = value.split(' ');
+
+ if (parts.length !== 3 || parts[1] !== 'port') return that.false_result();
+
+ address_part = parts[0];
+ var port = parts[2];
+
+ if (!port.match(/^[1-9]\d*$|^0$/) || port < 0 || port > 65535) {
+ var message = IPA.messages.widget.validation.port;
+ message = message.replace('${port}', port);
+ return that.false_result(message);
+ }
+ }
+
+ return that.ip_address_validate(address_part);
+ };
+
+ return that;
+};
+
+IPA.network_validator = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.validator(spec);
+
+ that.allow_negation = spec.allow_negation;
+ that.allow_host_address = spec.allow_host_address;
+ that.specials = spec.specials || [];
+ that.message = spec.message || IPA.messages.widget.validation.net_address;
+
+ that.validate = function(value) {
+
+ if (IPA.is_empty(value)) return that.true_result();
+
+ if (typeof value !== 'string') return that.false_result();
+
+ if (that.specials.indexOf(value) > -1) {
+ return that.true_result();
+ }
+
+ var address_part, mask;
+
+ if (value.indexOf('/') > -1) {
+
+ var parts = value.split('/');
+
+ if (parts.length === 2) {
+ address_part = parts[0];
+ mask = parts[1];
+
+ if (mask === '') return that.false_result();
+
+ } else {
+ return that.false_result();
+ }
+ } else if (that.allow_host_address) {
+ address_part = value;
+ } else {
+ return that.false_result();
+ }
+
+
+ if (that.allow_negation && address_part.indexOf('!') === 0) {
+ address_part = address_part.substring(1);
+ }
+
+ var address = NET.ip_address(address_part);
+ if (!address.valid) return that.false_result();
+
+ if (mask) {
+
+ var mask_length = 32;
+ if (address.type === 'v6') mask_length = 128;
+
+ if (!mask.match(/^[1-9]\d*$/) || mask < 8 || mask > mask_length) {
+ return that.false_result();
+ }
+ }
+
+ return that.true_result();
+ };
+
+ return that;
+};
+
+IPA.register('dnsconfig', IPA.dns.config_entity);
+IPA.register('dnszone', IPA.dns.zone_entity);
+IPA.register('dnsrecord', IPA.dns.record_entity);
diff --git a/install/ui/src/freeipa/entitle.js b/install/ui/src/freeipa/entitle.js
new file mode 100644
index 000000000..ccf82173b
--- /dev/null
+++ b/install/ui/src/freeipa/entitle.js
@@ -0,0 +1,745 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi S. Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+
+IPA.entitle = {};
+
+IPA.entitle.unregistered = 'unregistered';
+IPA.entitle.online = 'online';
+IPA.entitle.offline = 'offline';
+
+IPA.entitle.entity = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity(spec);
+
+ that.status = IPA.entitle.unregistered;
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups([ 'account', 'certificates' ]).
+ details_facet({
+ factory: IPA.entitle.details_facet,
+ label: IPA.messages.objects.entitle.account,
+ facet_group: 'account',
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ {
+ name: 'uuid',
+ label: IPA.get_command_option('entitle_register', 'ipaentitlementid').label,
+ read_only: true
+ },
+ {
+ factory: IPA.entitle.download_widget,
+ name: 'certificate',
+ label: IPA.messages.objects.entitle.certificate
+ }
+ ]
+ },
+ {
+ name: 'status',
+ label: IPA.messages.objects.entitle.status,
+ fields: [
+ {
+ name: 'product',
+ label: IPA.messages.objects.entitle.product,
+ read_only: true
+ },
+ {
+ name: 'quantity',
+ label: IPA.get_command_arg('entitle_consume', 'quantity').label,
+ read_only: true
+ },
+ {
+ name: 'consumed',
+ label: IPA.messages.objects.entitle.consumed,
+ read_only: true
+ }
+ ]
+ }
+ ]
+ }).
+ facet({
+ factory: IPA.entitle.certificates_facet,
+ name: 'certificates',
+ label: IPA.messages.objects.entitle.certificates,
+ facet_group: 'certificates',
+ columns: [
+ {
+ name: 'product',
+ label: IPA.messages.objects.entitle.product
+ },
+ {
+ name: 'quantity',
+ label: IPA.get_command_arg('entitle_consume', 'quantity').label
+ },
+ {
+ name: 'start',
+ label: IPA.messages.objects.entitle.start
+ },
+ {
+ name: 'end',
+ label: IPA.messages.objects.entitle.end
+ },
+ {
+ factory: IPA.entitle.certificate_column,
+ name: 'certificate',
+ label: IPA.messages.objects.entitle.certificate
+ }
+ ]
+ }).
+ standard_association_facets().
+ dialog({
+ factory: IPA.entitle.register_online_dialog,
+ name: 'online_registration',
+ title: IPA.messages.objects.entitle.registration,
+ fields: [
+ {
+ name: 'username',
+ label: IPA.get_command_arg('entitle_register', 'username').label
+ },
+ {
+ name: 'password',
+ label: IPA.get_command_option('entitle_register', 'password').label,
+ type: 'password'
+ }
+/* currently not supported
+ , {
+ name: 'ipaentitlementid',
+ label: IPA.get_command_option('entitle_register', 'ipaentitlementid').label
+ }
+*/
+ ]
+ }).
+ dialog({
+ factory: IPA.entitle.register_offline_dialog,
+ name: 'offline_registration',
+ title: IPA.messages.objects.entitle.import_certificate,
+ message: IPA.messages.objects.entitle.import_message,
+ fields: [
+ {
+ name: 'certificate',
+ label: IPA.messages.objects.entitle.certificate
+ }
+ ]
+ }).
+ dialog({
+ factory: IPA.entitle.consume_dialog,
+ name: 'consume',
+ title: IPA.messages.objects.entitle.consume_entitlement,
+ fields: [
+ {
+ name: 'quantity',
+ label: IPA.get_command_arg('entitle_consume', 'quantity').label,
+ metadata: IPA.get_command_arg('entitle_consume', 'quantity')
+ }
+ ]
+ }).
+ dialog({
+ factory: IPA.entitle.import_dialog,
+ name: 'import',
+ title: IPA.messages.objects.entitle.import_certificate,
+ message: IPA.messages.objects.entitle.import_message,
+ fields: [
+ {
+ name: 'certificate',
+ label: IPA.messages.objects.entitle.certificate
+ }
+ ]
+ });
+ };
+
+ that.get_accounts = function(on_success, on_error) {
+
+ var command = IPA.command({
+ name: 'entitle_find_'+that.status,
+ entity: 'entitle',
+ method: 'find',
+ options: { all: true },
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ that.get_status = function(on_success, on_error) {
+
+ var command = IPA.command({
+ name: 'entitle_status_'+that.status,
+ entity: 'entitle',
+ method: 'status',
+ on_success: function(data, text_status, xhr) {
+ if (data.result.result.uuid == 'IMPORTED') {
+ that.status = IPA.entitle.offline;
+ } else {
+ that.status = IPA.entitle.online;
+ }
+
+ if (on_success) {
+ on_success.call(this, data, text_status, xhr);
+ }
+ },
+ on_error: function(xhr, text_status, error_thrown) {
+ that.status = IPA.entitle.unregistered;
+
+ if (on_error) {
+ on_error.call(this, xhr, text_status, error_thrown);
+ }
+ },
+ retry: false
+ });
+
+ command.execute();
+ };
+
+ that.get_certificates = function(on_success, on_error) {
+
+ var command = IPA.command({
+ entity: 'entitle',
+ method: 'get',
+ on_success: on_success,
+ on_error: on_error,
+ retry: false
+ });
+
+ command.execute();
+ };
+
+ that.register_online = function(username, password, ipaentitlementid, on_success, on_error) {
+
+ var command = IPA.command({
+ entity: 'entitle',
+ method: 'register',
+ args: [ username ],
+ options: {
+ password: password
+ },
+ on_success: function(data, text_status, xhr) {
+ that.status = IPA.entitle.online;
+ if (on_success) {
+ on_success.call(this, data, text_status, xhr);
+ }
+ },
+ on_error: on_error
+ });
+
+ if (ipaentitlementid) {
+ command.set_option('ipaentitlementid', ipaentitlementid);
+ }
+
+ command.execute();
+ };
+
+ that.register_offline = function(certificate, on_success, on_error) {
+
+ var command = IPA.command({
+ entity: 'entitle',
+ method: 'import',
+ args: [ certificate ],
+ on_success: function(data, text_status, xhr) {
+ that.status = IPA.entitle.offline;
+ if (on_success) {
+ on_success.call(this, data, text_status, xhr);
+ }
+ },
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ that.consume = function(quantity, on_success, on_error) {
+
+ var command = IPA.command({
+ entity: 'entitle',
+ method: 'consume',
+ args: [ quantity ],
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ that.import_certificate = function(certificate, on_success, on_error) {
+
+ var command = IPA.command({
+ entity: 'entitle',
+ method: 'import',
+ args: [ certificate ],
+ on_success: function(data, text_status, xhr) {
+ that.status = IPA.entitle.offline;
+ if (on_success) {
+ on_success.call(this, data, text_status, xhr);
+ }
+ },
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ return that;
+};
+
+IPA.entitle.details_facet = function(spec) {
+
+ spec = spec || {};
+ spec.disable_breadcrumb = true;
+
+ var that = IPA.details_facet(spec);
+
+ that.create_controls = function() {
+
+ that.register_buttons = $('<span/>', {
+ name: 'register_buttons'
+ }).appendTo(that.controls);
+
+ that.register_online_button = IPA.action_button({
+ name: 'register',
+ label: IPA.messages.objects.entitle.register,
+ icon: 'register-icon',
+ click: function() {
+ var dialog = that.entity.get_dialog('online_registration');
+ dialog.open(that.container);
+ return false;
+ }
+ }).appendTo(that.register_buttons);
+
+ that.register_online_button.css('display', 'none');
+/*
+ that.register_offline_button = IPA.action_button({
+ name: 'import',
+ label: IPA.messages.objects.entitle.import,
+ icon: 'import-icon',
+ click: function() {
+ var dialog = that.entity.get_dialog('offline_registration');
+ dialog.open(that.container);
+ return false;
+ }
+ }).appendTo(that.register_buttons);
+
+ that.register_offline_button.css('display', 'none');
+*/
+ };
+
+ that.refresh = function() {
+
+ var summary = $('span[name=summary]', that.container).empty();
+ summary.append(IPA.messages.objects.entitle.loading);
+
+ function on_success(data, text_status, xhr) {
+ if (that.entity.status == IPA.entitle.unregistered) {
+ that.register_online_button.css('display', 'inline');
+ // that.register_offline_button.css('display', 'inline');
+
+ } else {
+ that.register_online_button.css('display', 'none');
+ // that.register_offline_button.css('display', 'none');
+ }
+
+ that.load(data);
+
+ summary.empty();
+ }
+
+ function on_error(xhr, text_status, error_thrown) {
+
+ that.register_online_button.css('display', 'inline');
+ // that.register_offline_button.css('display', 'inline');
+
+ var data = {};
+ data.result = {};
+ data.result.result = {
+ uuid: '',
+ product: '',
+ quantity: 0,
+ consumed: 0
+ };
+ that.load(data);
+
+ summary.empty();
+ summary.append(error_thrown.name+': '+error_thrown.message);
+ }
+
+ that.entity.get_status(
+ on_success,
+ on_error);
+ };
+
+ return that;
+};
+
+IPA.entitle.certificates_facet = function(spec) {
+
+ spec = spec || {};
+ spec.disable_facet_tabs = false;
+ spec.selectable = false;
+
+ var that = IPA.table_facet(spec);
+
+ var init = function() {
+ that.init_table(that.entity);
+ };
+
+ that.create_header = function(container) {
+
+ that.facet_create_header(container);
+
+ that.consume_buttons = $('<span/>', {
+ name: 'consume_buttons'
+ }).appendTo(that.controls);
+
+ that.consume_button = IPA.action_button({
+ name: 'consume',
+ label: IPA.messages.objects.entitle.consume,
+ icon: 'consume-icon',
+ click: function() {
+ var dialog = that.entity.get_dialog('consume');
+ dialog.open(that.container);
+ return false;
+ }
+ }).appendTo(that.consume_buttons);
+
+ that.consume_button.css('display', 'none');
+
+ that.import_button = IPA.action_button({
+ name: 'import',
+ label: IPA.messages.objects.entitle.import_button,
+ icon: 'import-icon',
+ click: function() {
+ var dialog = that.entity.get_dialog('import');
+ dialog.open(that.container);
+ return false;
+ }
+ }).appendTo(that.consume_buttons);
+
+ that.import_button.css('display', 'none');
+ };
+
+ that.refresh = function() {
+
+ function on_success(data, text_status, xhr) {
+
+ if (that.entity.status == IPA.entitle.online) {
+ that.consume_button.css('display', 'inline');
+ that.import_button.css('display', 'none');
+
+ } else if (that.entity.status == IPA.entitle.offline) {
+ that.consume_button.css('display', 'none');
+ that.import_button.css('display', 'inline');
+
+ } else {
+ that.consume_button.css('display', 'none');
+ that.import_button.css('display', 'inline');
+ }
+
+ that.load(data);
+ }
+
+ function on_error(xhr, text_status, error_thrown) {
+
+ that.consume_button.css('display', 'none');
+ that.import_button.css('display', 'inline');
+
+ that.table.summary.text(error_thrown.name+': '+error_thrown.message);
+ }
+
+ that.entity.get_status(
+ function(data, text_status, xhr) {
+ that.entity.get_certificates(
+ on_success,
+ on_error);
+ },
+ on_error);
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.entitle.certificate_column = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.column(spec);
+
+ that.setup = function(container, record) {
+
+ container.empty();
+
+ var certificate = record[that.name];
+
+ $('<a/>', {
+ href: '#download',
+ html: IPA.messages.objects.entitle.download,
+ click: function() {
+ var dialog = IPA.cert.download_dialog({
+ title: IPA.messages.objects.entitle.download_certificate,
+ certificate: certificate
+ });
+ dialog.open();
+ return false;
+ }
+ }).appendTo(container);
+ };
+
+ return that;
+};
+
+IPA.entitle.certificate_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.width = spec.width || 500;
+ that.height = spec.height || 400;
+ that.message = spec.message;
+ that.label = spec.label;
+
+ that.get_certificate = function() {
+ var certificate = that.textarea.val();
+ return IPA.cert.BEGIN_CERTIFICATE+'\n'+
+ $.trim(certificate)+'\n'+
+ IPA.cert.END_CERTIFICATE+'\n';
+ };
+
+ that.create = function() {
+ that.container.append(that.message);
+ that.container.append('<br/>');
+ that.container.append('<br/>');
+
+ that.container.append(IPA.cert.BEGIN_CERTIFICATE);
+ that.container.append('<br/>');
+
+ that.textarea = $('<textarea/>', {
+ style: 'width: 100%; height: 225px;'
+ }).appendTo(that.container);
+
+ that.container.append('<br/>');
+ that.container.append(IPA.cert.END_CERTIFICATE);
+ };
+
+ return that;
+};
+
+IPA.entitle.register_online_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.create_button({
+ name: 'register',
+ label: IPA.messages.objects.entitle.register,
+ click: function() {
+ var record = {};
+ that.save(record);
+
+ that.entity.register_online(
+ record.username[0],
+ record.password[0],
+ record.ipaentitlementid[0],
+ function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ that.close();
+ }
+ );
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ return that;
+};
+
+IPA.entitle.register_offline_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entitle.certificate_dialog(spec);
+
+ that.create_button({
+ name: 'register',
+ label: that.label,
+ click: function() {
+ that.entity.register_offline(
+ that.get_certificate(),
+ function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ that.close();
+ }
+ );
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ return that;
+};
+
+IPA.entitle.consume_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+
+ that.create_button({
+ name: 'consume',
+ label: IPA.messages.objects.entitle.consume,
+ click: function() {
+
+ if (!that.validate()) {
+ return;
+ }
+
+ var record = {};
+ that.save(record);
+
+ that.entity.consume(
+ record.quantity[0],
+ function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ that.close();
+ }
+ );
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ return that;
+};
+
+IPA.entitle.import_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entitle.certificate_dialog(spec);
+
+ that.create_button({
+ name: 'import',
+ label: IPA.messages.objects.entitle.import_button,
+ click: function() {
+ that.entity.import_certificate(
+ that.get_certificate(),
+ function() {
+ var facet = that.entity.get_facet();
+ facet.refresh();
+ that.close();
+ }
+ );
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ return that;
+};
+
+IPA.entitle.download_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.create = function(container) {
+ that.link = $('<a/>', {
+ 'href': '#download',
+ 'html': IPA.messages.objects.entitle.download,
+ 'click': function() {
+ that.entity.get_accounts(
+ function(data, text_status, xhr) {
+ var userpkcs12 = data.result.result[0].userpkcs12;
+ if (!userpkcs12) {
+ alert(IPA.messages.objects.entitle.no_certificate);
+ return;
+ }
+
+ /*
+ * WARNING - despite using cert.download_dialog() and passing
+ * a certificate, it's NOT a certificate, it's a binary
+ * PKCS12 file that's been base64 encoded!
+ * Hence the reason add_pem_delimiters is false.
+ */
+ var dialog = IPA.cert.download_dialog({
+ title: IPA.messages.objects.entitle.download_certificate,
+ certificate: userpkcs12[0].__base64__,
+ add_pem_delimiters: false
+ });
+ dialog.open();
+ }
+ );
+ return false;
+ }
+ }).appendTo(container);
+ };
+
+ that.update = function() {
+ if (that.entity.status == IPA.entitle.online) {
+ that.link.css('display', 'inline');
+ } else {
+ that.link.css('display', 'none');
+ }
+ };
+
+ return that;
+};
+
+IPA.register('entitle', IPA.entitle.entity);
diff --git a/install/ui/src/freeipa/entity.js b/install/ui/src/freeipa/entity.js
new file mode 100644
index 000000000..d474ad95b
--- /dev/null
+++ b/install/ui/src/freeipa/entity.js
@@ -0,0 +1,731 @@
+/*jsl:import ipa.js */
+/*jsl:import facet.js */
+/*jsl:import navigation.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010-2011 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, facet.js, details.js, search.js, add.js */
+
+IPA.entity = function(spec) {
+
+ spec = spec || {};
+
+ spec.policies = spec.policies || [
+ IPA.search_facet_update_policy(),
+ IPA.details_facet_update_policy()
+ ];
+
+ var that = {};
+
+ that.name = spec.name;
+ that.label = spec.label;
+
+ that.metadata = spec.metadata;
+ that.builder = spec.builder;
+
+ that.dialogs = $.ordered_map();
+ that.dialog_specs = spec.dialogs || [];
+ that.dialogs_created = false;
+
+ that.policies = IPA.entity_policies({
+ entity: that,
+ policies: spec.policies
+ });
+
+ that.facets = $.ordered_map();
+ that.facet_groups = $.ordered_map();
+ that.facet_specs = spec.facets || [];
+ that.facets_created = false;
+
+ // current facet
+ that.facet = null;
+
+ that.redirect_facet = spec.redirect_facet;
+ that.containing_entity = null;
+
+ that.init = function() {
+ if (!that.metadata) {
+ that.metadata = that.get_default_metadata();
+ if (!that.metadata) {
+ throw {
+ expected: true,
+ message: "Entity " + that.name + " not supported by server."
+ };
+ }
+ }
+ that.label = that.label || that.metadata.label || that.name;
+ };
+
+ that.get_default_metadata = function() {
+ return IPA.metadata.objects[that.name];
+ };
+
+ that.get_containing_entity = function() {
+ return that.containing_entity;
+ };
+
+ that.get_dialog = function(name) {
+
+ //build all dialogs on the first time
+ if(!that.dialogs_created) {
+ var builder = IPA.dialog_builder(that);
+ builder.build_dialogs();
+ that.dialogs_created = true;
+ }
+
+ return that.dialogs.get(name);
+ };
+
+ that.add_dialog = function(dialog) {
+ return that.dialog(dialog);
+ };
+
+ that.dialog = function(dialog) {
+ dialog.entity = that;
+ that.dialogs.put(dialog.name, dialog);
+ return that;
+ };
+
+ that.add_facet_group = function(facet_group) {
+ that.facet_groups.put(facet_group.name, facet_group);
+ };
+
+ that.get_facet_group = function(name) {
+ return that.facet_groups.get(name);
+ };
+
+ that.remove_facet_groups = function() {
+ that.facet_groups.empty();
+ };
+
+ that.get_facet = function(name) {
+
+ //build all facets on the first time
+ if(!that.facets_created) {
+ var builder = IPA.facet_builder(that);
+ builder.build_facets();
+ that.facets_created = true;
+ that.policies.facets_created();
+ }
+
+ if (name === undefined) {
+ // return the current facet
+ if (that.facet) return that.facet;
+
+ // return the main facet
+ return that.facets.values[0];
+
+ } else if (name === 'default') {
+ // return the first facet in the first facet group
+ var facet_groups = that.facet_groups.values;
+ for (var i=0; i<facet_groups.length; i++) {
+ var facet_group = facet_groups[i];
+ var facets = facet_group.facets.values;
+ if (!facets.length) continue;
+ return facets[0];
+ }
+
+ return that.facets.values[0];
+ }
+
+ return that.facets.get(name);
+ };
+
+ that.add_facet = function(facet) {
+ facet.entity = that;
+
+ that.facets.put(facet.name, facet);
+
+ if (facet.facet_group) {
+ var facet_group = that.get_facet_group(facet.facet_group);
+ if (facet_group) {
+ facet_group.add_facet(facet);
+ }
+ }
+
+ return that;
+ };
+
+ that.create = function(container) {
+ that.container = container;
+ };
+
+ that.display = function(container) {
+
+ var prev_entity = IPA.current_entity;
+ var prev_facet = prev_entity ? prev_entity.facet : null;
+
+ IPA.current_entity = that;
+
+ var facet_name = IPA.nav.get_state(that.name+'-facet');
+ that.facet = that.get_facet(facet_name);
+
+ var needs_update = that.facet.needs_update();
+
+ // same entity, same facet, and doesn't need updating => return
+ if (that == prev_entity && that.facet == prev_facet && !needs_update) {
+ return;
+ }
+
+ if (prev_facet) {
+ prev_facet.hide();
+ }
+
+ var facet_container = $('.facet[name="'+that.facet.name+'"]', that.container);
+ if (!facet_container.length) {
+ facet_container = $('<div/>', {
+ name: that.facet.name,
+ 'class': 'facet'
+ }).appendTo(that.container);
+
+ that.facet.create(facet_container);
+ }
+
+ if (needs_update) {
+ that.facet.clear();
+ that.facet.show();
+ that.facet.header.select_tab();
+ that.facet.refresh();
+ } else {
+ that.facet.show();
+ that.facet.header.select_tab();
+ }
+ };
+
+ that.get_primary_key_prefix = function() {
+ var pkey = [];
+ var current_entity = that;
+ current_entity = current_entity.get_containing_entity();
+ while(current_entity !== null){
+
+ var key = IPA.nav.get_state(current_entity.name+'-pkey');
+ if (key){
+ pkey.unshift(key);
+ }
+ current_entity = current_entity.get_containing_entity();
+ }
+ return pkey;
+ };
+
+ /*gets the primary key for the current entity out of the URL parameters */
+ that.get_primary_key = function() {
+ var pkey = that.get_primary_key_prefix();
+ var current_entity = that;
+ pkey.unshift(IPA.nav.get_state(current_entity.name+'-pkey'));
+ return pkey;
+ };
+
+ /* most entites only require -pkey for their primary keys, but some
+ are more specific. This call allows those entites a place
+ to override the other parameters. */
+ that.get_key_names = function() {
+ return [that.name + '-pkey'];
+ };
+
+ that.entity_init = that.init;
+
+ return that;
+};
+
+IPA.nested_tab_labels = {};
+
+IPA.get_nested_tab_label = function(entity_name){
+
+ if (!IPA.nested_tab_labels[entity_name]){
+ IPA.nested_tab_labels[entity_name] = "LABEL";
+
+ }
+ return IPA.nested_tab_labels[entity_name];
+
+};
+
+/*Returns the entity requested, as well as:
+ any nested tabs underneath it or
+ its parent tab and the others nested at the same level*/
+
+IPA.nested_tabs = function(entity_name) {
+
+ var siblings = [];
+ var i;
+ var i2;
+ var nested_entities;
+ var sub_i;
+ var sub_tab;
+
+ var key = entity_name;
+ function push_sibling(sibling){
+ siblings.push (sibling);
+ IPA.nested_tab_labels[key] = sub_tab;
+ }
+
+
+ if (!IPA.nav.tabs) {
+ siblings.push(entity_name);
+ return siblings;
+ }
+
+ for (var top_i = 0; top_i < IPA.nav.tabs.length; top_i++) {
+ var top_tab = IPA.nav.tabs[top_i];
+ for (sub_i = 0; sub_i < top_tab.children.length; sub_i++) {
+ sub_tab = top_tab.children[sub_i];
+ nested_entities = sub_tab.children;
+ if (sub_tab.name === entity_name){
+ push_sibling(entity_name);
+ }
+ if (sub_tab.children){
+ for (i = 0; i < nested_entities.length; i += 1){
+ if (sub_tab.name === entity_name){
+ push_sibling(nested_entities[i].name);
+ }else{
+ if (nested_entities[i].name === entity_name){
+ push_sibling(sub_tab.name);
+ for (i2 = 0; i2 < nested_entities.length; i2 += 1){
+ key = nested_entities[i].name;
+ push_sibling(nested_entities[i2].name);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return siblings;
+};
+
+IPA.entity_builder = function() {
+
+ var that = {};
+
+ var entity = null;
+ var facet_group = null;
+ var facet = null;
+ var section = null;
+
+ that.entity = function(spec) {
+ var factory = IPA.entity;
+ if (spec instanceof Object) {
+ factory = spec.factory || IPA.entity;
+ } else {
+ spec = { name: spec };
+ }
+ spec.builder = that;
+
+ entity = factory(spec);
+
+ that.facet_groups([
+ 'member',
+ 'settings',
+ 'memberof',
+ 'managedby'
+ ]);
+
+ return that;
+ };
+
+ that.facet_group = function(spec) {
+ spec.entity = entity;
+ if (spec instanceof Object) {
+ var factory = spec.factory || IPA.facet_group;
+ facet_group = factory(spec);
+ } else {
+ facet_group = IPA.facet_group({ name: spec });
+ }
+
+ if (facet_group.label == undefined) {
+ facet_group.label = IPA.messages.facet_groups[facet_group.name];
+ }
+
+ entity.add_facet_group(facet_group);
+
+ return that;
+ };
+
+ that.facet_groups = function(specs) {
+
+ entity.remove_facet_groups();
+
+ for (var i=0; i<specs.length; i++) {
+ specs[i].entity = entity;
+ that.facet_group(specs[i]);
+ }
+
+ return that;
+ };
+
+ that.facet = function(spec) {
+
+ spec.entity = entity;
+ entity.facet_specs.push(spec);
+
+ return that;
+ };
+
+ that.search_facet = function(spec) {
+
+ spec.type = spec.type || 'search';
+
+ that.facet(spec);
+
+ add_redirect_info(spec.name);
+
+ return that;
+ };
+
+ that.nested_search_facet = function(spec) {
+
+ spec.type = spec.type || 'nested_search';
+
+ that.facet(spec);
+
+ return that;
+ };
+
+ that.details_facet = function(spec) {
+
+ spec.type = spec.type || 'details';
+
+ that.facet(spec);
+
+ return that;
+ };
+
+ that.association_facet = function(spec) {
+
+ spec.type = spec.type || 'association';
+
+ that.facet(spec);
+
+ return that;
+ };
+
+ that.attribute_facet = function(spec) {
+
+ spec.type = spec.type || 'attribute';
+
+ that.facet(spec);
+
+ return that;
+ };
+
+ that.standard_association_facets = function(spec) {
+
+ spec = spec || {};
+ spec.entity = entity;
+
+ var direct_associations = [];
+ var indirect_associations = [];
+
+ for (var association in entity.metadata.attribute_members) {
+ if (association == 'memberindirect' ||
+ association == 'memberofindirect') {
+ indirect_associations.push(association);
+ } else {
+ direct_associations.push(association);
+ }
+ }
+
+ // make sure direct facets are created first
+ var attribute_members = direct_associations.concat(indirect_associations);
+
+ for (var i=0; i<attribute_members.length; i++) {
+ var attribute_member = attribute_members[i];
+ var other_entities = entity.metadata.attribute_members[attribute_member];
+
+ for (var j=0; j<other_entities.length; j++) {
+
+ var other_entity = other_entities[j];
+ var association_name = attribute_member+'_'+other_entity;
+
+ //already prepared facet
+ var facet = get_spec_by_name(entity.facet_specs, association_name);
+ //already prepared direct facet for indirect facet
+ var direct_facet = get_direct_facet(entity.facet_specs,
+ attribute_member,
+ other_entity);
+ if (facet || direct_facet) {
+ continue; //in both cases don't prepare new facet
+ }
+
+ var tmp_spec = $.extend({}, spec);
+ tmp_spec.name = association_name;
+
+ that.association_facet(tmp_spec);
+ }
+ }
+
+ return that;
+ };
+
+ function get_spec_by_name(specs, name) {
+ if(!specs || !specs.length) return null;
+
+ for(var i=0; i<specs.length; i++) {
+ if(specs[i].name === name) {
+ return specs[i];
+ }
+ }
+
+ return null;
+ }
+
+ /*
+ * If it's an indirect attribute member, return its direct facets spec
+ * if it exists.
+ */
+ function get_direct_facet(facets, attribute_member, other_entity) {
+
+ var index = attribute_member.indexOf('indirect');
+ if(index > -1) {
+ var direct_attribute_member = attribute_member.substring(0, index);
+ return get_spec_by_name(facets,
+ direct_attribute_member+'_'+other_entity);
+ }
+
+ return null;
+ }
+
+ function add_redirect_info(facet_name){
+ facet_name = facet_name || 'search';
+ if (!entity.redirect_facet){
+ entity.redirect_facet = facet_name;
+ }
+ }
+
+ that.containing_entity = function(entity_name) {
+ add_redirect_info();
+ entity.containing_entity = IPA.get_entity(entity_name);
+ return that;
+ };
+
+ that.dialog = function(spec) {
+
+ if (spec instanceof Object) {
+ spec.factory = spec.factory || IPA.dialog;
+ spec.entity = entity;
+
+ } else {
+ spec = {
+ factory: IPA.dialog,
+ name: spec,
+ entity: entity
+ };
+ }
+
+ entity.dialog_specs.push(spec);
+ return that;
+ };
+
+ that.adder_dialog = function(spec) {
+ spec.factory = spec.factory || IPA.entity_adder_dialog;
+ spec.name = spec.name || 'add';
+
+ if (!spec.title) {
+ var title = IPA.messages.dialogs.add_title;
+ var label = entity.metadata.label_singular;
+ spec.title = title.replace('${entity}', label);
+ }
+
+ return that.dialog(spec);
+ };
+
+ that.deleter_dialog = function(spec) {
+ spec.factory = spec.factory || IPA.search_deleter_dialog;
+ spec.name = spec.name || 'remove';
+
+ return that.dialog(spec);
+ };
+
+ that.build = function(){
+ return entity;
+ };
+
+ return that;
+};
+
+IPA.dialog_builder = function(entity) {
+
+ var that = {};
+
+ that.build_dialogs = function() {
+
+ if(entity.dialog_specs && entity.dialog_specs.length) {
+ var dialogs = entity.dialog_specs;
+ for(var i=0; i<dialogs.length; i++) {
+ that.build_dialog(dialogs[i]);
+ }
+ }
+ };
+
+ that.build_dialog = function(spec) {
+ //do common logic
+ spec.entity = entity;
+
+ //add dialog
+ var dialog = spec.factory(spec);
+ entity.dialog(dialog);
+ };
+
+ return that;
+};
+
+IPA.entity_policy = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.entity = spec.entity;
+
+ that.facets_created = function() {
+ };
+
+ return that;
+};
+
+IPA.entity_policies = function(spec) {
+
+ var that = {};
+
+ that.entity = spec.entity;
+ that.policies = [];
+
+ that.add_policy = function(policy) {
+
+ policy.entity = that.entity;
+ that.policies.push(policy);
+ };
+
+ that.add_policies = function(policies) {
+
+ if (!policies) return;
+
+ for (var i=0; i<policies.length; i++) {
+ that.add_policy(policies[i]);
+ }
+ };
+
+ that.facets_created = function() {
+
+ for (var i=0; i<that.policies.length; i++) {
+ that.policies[i].facets_created();
+ }
+ };
+
+ that.add_policies(spec.policies);
+
+ return that;
+};
+
+IPA.facet_update_policy = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_policy();
+
+ that.event = spec.event || 'on_update';
+ that.source_facet_name = spec.source_facet;
+ that.dest_facet_name = spec.dest_facet;
+ that.dest_entity_name = spec.dest_entity;
+
+ that.facets_created = function() {
+
+ that.source_facet = that.entity.get_facet(that.source_facet_name);
+ var dest_entity = that.entity;
+ if (that.dest_entity_name) {
+ dest_entity = IPA.get_entity(that.dest_entity_name);
+ if (!dest_entity) return;
+ }
+ that.dest_facet = dest_entity.get_facet(that.dest_facet_name);
+
+ if (!that.source_facet || !that.dest_facet) return;
+
+ var event = that.source_facet[that.event];
+ if (!event && !event.attach) return;
+
+ event.attach(that.set_expired_flag);
+ };
+
+ that.set_expired_flag = function() {
+
+ that.dest_facet.set_expired_flag();
+ };
+
+ return that;
+};
+
+IPA.adder_facet_update_policy = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_policy();
+
+ that.event = spec.event || 'added';
+ that.dialog_name = spec.dialog_name || 'add';
+ that.dest_facet_name = spec.dest_facet || 'details';
+ that.dest_entity_name = spec.dest_entity;
+
+ that.facets_created = function() {
+
+ that.dialog = that.entity.get_dialog(that.dialog_name);
+ var dest_entity = that.entity;
+ if (that.dest_entity_name) {
+ dest_entity = IPA.get_entity(that.dest_entity_name);
+ if (!dest_entity) return;
+ }
+ that.dest_facet = dest_entity.get_facet(that.dest_facet_name);
+
+ if (!that.dialog || !that.dest_facet) return;
+
+ var event = that.dialog[that.event];
+ if (!event && !event.attach) return;
+
+ event.attach(that.set_expired_flag);
+ };
+
+ that.set_expired_flag = function() {
+
+ that.dest_facet.set_expired_flag();
+ };
+
+ return that;
+};
+
+IPA.search_facet_update_policy = function(spec) {
+
+ spec = spec || {};
+ spec.source_facet = 'search';
+ spec.dest_facet = 'details';
+
+ return IPA.facet_update_policy(spec);
+};
+
+IPA.details_facet_update_policy = function(spec) {
+
+ spec = spec || {};
+ spec.source_facet = 'details';
+ spec.dest_facet = 'search';
+
+ return IPA.facet_update_policy(spec);
+}; \ No newline at end of file
diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js
new file mode 100644
index 000000000..25d48bf66
--- /dev/null
+++ b/install/ui/src/freeipa/facet.js
@@ -0,0 +1,2044 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010-2011 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js */
+
+IPA.facet = function(spec, no_init) {
+
+ spec = spec || {};
+ spec.state = spec.state || {};
+ $.extend(spec.state, { factory: IPA.state });
+
+ var that = {};
+
+ that.entity = IPA.get_entity(spec.entity);
+
+ that.name = spec.name;
+ that.label = spec.label;
+ that.title = spec.title || that.label;
+ that.tab_label = spec.tab_label || that.label;
+ that.display_class = spec.display_class;
+
+ that.disable_breadcrumb = spec.disable_breadcrumb;
+ that.disable_facet_tabs = spec.disable_facet_tabs;
+
+ that.action_state = IPA.build(spec.state);
+ that.actions = IPA.build({ actions: spec.actions }, IPA.action_holder_builder);
+
+ that.header_actions = spec.header_actions;
+ that.header = spec.header || IPA.facet_header({ facet: that });
+
+ that._needs_update = spec.needs_update;
+ that.expired_flag = true;
+ that.last_updated = null;
+ that.expire_timeout = spec.expire_timeout || 600; //[seconds]
+ that.on_update = IPA.observer();
+ that.post_load = IPA.observer();
+
+ that.dialogs = $.ordered_map();
+
+ // facet group name
+ that.facet_group = spec.facet_group;
+
+ that.redirect_info = spec.redirect_info;
+
+ that.state = {};
+
+ that.get_dialog = function(name) {
+ return that.dialogs.get(name);
+ };
+
+ that.dialog = function(dialog) {
+ that.dialogs.put(dialog.name, dialog);
+ return that;
+ };
+
+ that.create = function(container) {
+
+ that.container = container;
+
+ if (that.disable_facet_tabs) that.container.addClass('no-facet-tabs');
+ that.container.addClass(that.display_class);
+
+ that.header_container = $('<div/>', {
+ 'class': 'facet-header'
+ }).appendTo(container);
+ that.create_header(that.header_container);
+
+ that.content = $('<div/>', {
+ 'class': 'facet-content'
+ }).appendTo(container);
+
+ that.error_container = $('<div/>', {
+ 'class': 'facet-content facet-error'
+ }).appendTo(container);
+
+ that.create_content(that.content);
+ };
+
+ that.create_header = function(container) {
+
+ that.header.create(container);
+
+ that.controls = $('<div/>', {
+ 'class': 'facet-controls'
+ }).appendTo(container);
+ };
+
+ that.create_content = function(container) {
+ };
+
+ that.create_control_buttons = function(container) {
+
+ if (that.control_buttons) {
+ that.control_buttons.create(container);
+ }
+ };
+
+ that.set_title = function(container, title) {
+ var element = $('h1', that.title_container);
+ element.html(title);
+ };
+
+ that.show = function() {
+ that.container.css('display', 'block');
+ that.show_content();
+ };
+
+ that.show_content = function() {
+ that.content.css('display', 'block');
+ that.error_container.css('display', 'none');
+ };
+
+ that.show_error = function() {
+ that.content.css('display', 'none');
+ that.error_container.css('display', 'block');
+ };
+
+ that.error_displayed = function() {
+ return that.error_container &&
+ that.error_container.css('display') === 'block';
+ };
+
+ that.hide = function() {
+ that.container.css('display', 'none');
+ };
+
+ that.load = function(data) {
+ that.data = data;
+ that.header.load(data);
+ };
+
+ that.refresh = function() {
+ };
+
+ that.clear = function() {
+ };
+
+ that.needs_update = function() {
+
+ if (that._needs_update !== undefined) return that._needs_update;
+
+ var needs_update = false;
+
+ if (that.expire_timeout && that.expire_timeout > 0) {
+
+ if (!that.last_updated) {
+ needs_update = true;
+ } else {
+ var now = Date.now();
+ needs_update = (now - that.last_updated) > that.expire_timeout * 1000;
+ }
+ }
+
+ needs_update = needs_update || that.expired_flag;
+ needs_update = needs_update || that.error_displayed();
+
+ return needs_update;
+ };
+
+ that.set_expired_flag = function() {
+ that.expired_flag = true;
+ };
+
+ that.clear_expired_flag = function() {
+ that.expired_flag = false;
+ that.last_updated = Date.now();
+ };
+
+ that.is_dirty = function() {
+ return false;
+ };
+
+ that.report_error = function(error_thrown) {
+
+ var add_option = function(ul, text, handler) {
+
+ var li = $('<li/>').appendTo(ul);
+ $('<a />', {
+ href: '#',
+ text: text,
+ click: function() {
+ handler();
+ return false;
+ }
+ }).appendTo(li);
+ };
+
+ var title = IPA.messages.error_report.title;
+ title = title.replace('${error}', error_thrown.name);
+
+ that.error_container.empty();
+ that.error_container.append('<h1>'+title+'</h1>');
+
+ var details = $('<div/>', {
+ 'class': 'error-details'
+ }).appendTo(that.error_container);
+ details.append('<p>'+error_thrown.message+'</p>');
+
+ $('<div/>', {
+ text: IPA.messages.error_report.options
+ }).appendTo(that.error_container);
+
+ var options_list = $('<ul/>').appendTo(that.error_container);
+
+ add_option(
+ options_list,
+ IPA.messages.error_report.refresh,
+ function() {
+ that.refresh();
+ }
+ );
+
+ add_option(
+ options_list,
+ IPA.messages.error_report.main_page,
+ function() {
+ IPA.nav.show_top_level_page();
+ }
+ );
+
+ add_option(
+ options_list,
+ IPA.messages.error_report.reload,
+ function() {
+ window.location.reload(false);
+ }
+ );
+
+ that.error_container.append('<p>'+IPA.messages.error_report.problem_persists+'</p>');
+
+ that.show_error();
+ };
+
+ that.get_redirect_facet = function() {
+
+ var entity = that.entity;
+ while (entity.containing_entity) {
+ entity = entity.get_containing_entity();
+ }
+ var facet_name = that.entity.redirect_facet;
+ var entity_name = entity.name;
+ var tab_name, facet;
+
+ if (that.redirect_info) {
+ entity_name = that.redirect_info.entity || entity_name;
+ facet_name = that.redirect_info.facet || facet_name;
+ tab_name = that.redirect_info.tab;
+ }
+
+ if (tab_name) {
+ facet = IPA.nav.get_tab_facet(tab_name);
+ }
+
+ if (!facet) {
+ entity = IPA.get_entity(entity_name);
+ facet = entity.get_facet(facet_name);
+ }
+
+ return facet;
+ };
+
+ that.redirect = function() {
+
+ var facet = that.get_redirect_facet();
+ if (!facet) return;
+ IPA.nav.show_page(facet.entity.name, facet.name);
+ };
+
+ var redirect_error_codes = [4001];
+
+ that.redirect_error = function(error_thrown) {
+
+ /*If the error is in talking to the server, don't attempt to redirect,
+ as there is nothing any other facet can do either. */
+ for (var i=0; i<redirect_error_codes.length; i++) {
+ if (error_thrown.code === redirect_error_codes[i]) {
+ that.redirect();
+ return;
+ }
+ }
+ };
+
+ that.init_facet = function() {
+
+ that.action_state.init(that);
+ that.actions.init(that);
+ that.header.init();
+
+ var buttons_spec = {
+ factory: IPA.control_buttons_widget,
+ name: 'control-buttons',
+ 'class': 'control-buttons',
+ buttons: spec.control_buttons
+ };
+
+ that.control_buttons = IPA.build(buttons_spec);
+ that.control_buttons.init(that);
+ };
+
+ if (!no_init) that.init_facet();
+
+ // methods that should be invoked by subclasses
+ that.facet_create = that.create;
+ that.facet_create_header = that.create_header;
+ that.facet_create_content = that.create_content;
+ that.facet_needs_update = that.needs_update;
+ that.facet_show = that.show;
+ that.facet_hide = that.hide;
+ that.facet_load = that.load;
+
+ return that;
+};
+
+IPA.facet_header = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.facet = spec.facet;
+
+ that.init = function() {
+
+ if (that.facet.header_actions) {
+
+ var widget_builder = IPA.widget_builder({
+ widget_options: {
+ entity: that.facet.entity,
+ facet: that.facet
+ }
+ });
+
+ var widget = {
+ factory: IPA.action_list_widget,
+ actions: that.facet.header_actions
+ };
+
+ that.action_list = widget_builder.build_widget(widget);
+ that.action_list.init(that.facet);
+ }
+
+ that.facet.action_state.changed.attach(that.update_summary);
+
+ that.title_widget = IPA.facet_title();
+ };
+
+ that.select_tab = function() {
+ if (that.facet.disable_facet_tabs) return;
+
+ $(that.facet_tabs).find('a').removeClass('selected');
+ var facet_name = IPA.nav.get_state(that.facet.entity.name+'-facet');
+
+ if (!facet_name || facet_name === 'default') {
+ that.facet_tabs.find('a:first').addClass('selected');
+ } else {
+ that.facet_tabs.find('a#' + facet_name ).addClass('selected');
+ }
+ };
+
+ that.set_pkey = function(value) {
+
+ if (!value) return;
+
+ var key, i;
+ var pkey_max = that.get_max_pkey_length();
+ var limited_value = IPA.limit_text(value, pkey_max);
+
+ if (!that.facet.disable_breadcrumb) {
+ var breadcrumb = [];
+ var keys = [];
+
+ var entity = that.facet.entity.get_containing_entity();
+
+ while (entity) {
+ key = IPA.nav.get_state(entity.name+'-pkey');
+ breadcrumb.unshift($('<a/>', {
+ 'class': 'breadcrumb-element',
+ text: key,
+ title: entity.metadata.label_singular,
+ click: function(entity) {
+ return function() {
+ IPA.nav.show_page(entity.name, 'default');
+ return false;
+ };
+ }(entity)
+ }));
+
+ entity = entity.get_containing_entity();
+ keys.unshift(key);
+ }
+
+ //calculation of breadcrumb keys length
+ keys.push(value);
+ var max_bc_l = 140; //max chars which can fit on one line
+ var max_key_l = (max_bc_l / keys.length) - 4; //4 chars as divider
+ var bc_l = 0;
+ var to_limit = keys.length;
+
+ //count how many won't be limited and how much space they take
+ for (i=0; i<keys.length; i++) {
+ var key_l = keys[i].length;
+ if (key_l <= max_key_l) {
+ to_limit--;
+ bc_l += key_l + 4;
+ }
+ }
+
+ max_key_l = ((max_bc_l - bc_l) / to_limit) - 4;
+
+
+ that.path.empty();
+
+ for (i=0; i<breadcrumb.length; i++) {
+ var item = breadcrumb[i];
+ key = IPA.limit_text(keys[i], max_key_l);
+ item.text(key);
+
+ that.path.append(' &raquo; ');
+ that.path.append(item);
+ }
+
+ that.path.append(' &raquo; ');
+
+ key = IPA.limit_text(keys[i], max_key_l);
+
+ $('<span>', {
+ 'class': 'breadcrumb-element',
+ title: value,
+ text: key
+ }).appendTo(that.path);
+ }
+
+ var title_info = {
+ title: that.facet.label,
+ pkey: limited_value,
+ pkey_tooltip: value
+ };
+ that.title_widget.update(title_info);
+
+ that.adjust_elements();
+ };
+
+ that.create_facet_link = function(container, other_facet) {
+
+ var li = $('<li/>', {
+ name: other_facet.name,
+ title: other_facet.name,
+ click: function() {
+ if (li.hasClass('entity-facet-disabled')) {
+ return false;
+ }
+
+ var pkey = IPA.nav.get_state(that.facet.entity.name+'-pkey');
+ IPA.nav.show_page(that.facet.entity.name, other_facet.name, pkey);
+
+ return false;
+ }
+ }).appendTo(container);
+
+ $('<a/>', {
+ text: other_facet.tab_label,
+ id: other_facet.name
+ }).appendTo(li);
+ };
+
+ that.create_facet_group = function(container, facet_group) {
+
+ var section = $('<div/>', {
+ name: facet_group.name,
+ 'class': 'facet-group'
+ }).appendTo(container);
+
+ $('<div/>', {
+ 'class': 'facet-group-label'
+ }).appendTo(section);
+
+ var ul = $('<ul/>', {
+ 'class': 'facet-tab'
+ }).appendTo(section);
+
+ var facets = facet_group.facets.values;
+ for (var i=0; i<facets.length; i++) {
+ var facet = facets[i];
+ that.create_facet_link(ul, facet);
+ }
+ };
+
+ that.create = function(container) {
+
+ that.container = container;
+
+ if (!that.facet.disable_breadcrumb) {
+ that.breadcrumb = $('<div/>', {
+ 'class': 'breadcrumb'
+ }).appendTo(container);
+
+ that.back_link = $('<span/>', {
+ 'class': 'back-link'
+ }).appendTo(that.breadcrumb);
+
+ var redirect_facet = that.facet.get_redirect_facet();
+
+ $('<a/>', {
+ text: redirect_facet.label,
+ click: function() {
+ that.facet.redirect();
+ return false;
+ }
+ }).appendTo(that.back_link);
+
+
+ that.path = $('<span/>', {
+ 'class': 'path'
+ }).appendTo(that.breadcrumb);
+ }
+
+ that.title_widget.create(container);
+ that.title_widget.update({ title: that.facet.label });
+
+ if (that.action_list) {
+ that.action_list_container = $('<div/>', {
+ 'class': 'facet-action-list'
+ }).appendTo(container);
+
+ that.action_list.create(that.action_list_container);
+ }
+
+ if (!that.facet.disable_facet_tabs) {
+ that.facet_tabs = $('<div/>', {
+ 'class': 'facet-tabs'
+ }).appendTo(container);
+
+ var facet_groups = that.facet.entity.facet_groups.values;
+ for (var i=0; i<facet_groups.length; i++) {
+ var facet_group = facet_groups[i];
+ if (facet_group.facets.length) {
+ that.create_facet_group(that.facet_tabs, facet_group);
+ }
+ }
+ }
+ };
+
+ that.load = function(data) {
+ if (!data) return;
+ var result = data.result.result;
+ if (!that.facet.disable_facet_tabs) {
+ var pkey = that.facet.pkey;
+
+ var facet_groups = that.facet.entity.facet_groups.values;
+ for (var i=0; i<facet_groups.length; i++) {
+ var facet_group = facet_groups[i];
+
+ var span = $('.facet-group[name='+facet_group.name+']', that.facet_tabs);
+ if (!span.length) continue;
+
+ var label = facet_group.label;
+ if (pkey && label) {
+ var limited_pkey = IPA.limit_text(pkey, 20);
+ label = label.replace('${primary_key}', limited_pkey);
+ } else {
+ label = '';
+ }
+
+ var label_container = $('.facet-group-label', span);
+ label_container.text(label);
+ if (pkey) label_container.attr('title', pkey);
+
+ var facets = facet_group.facets.values;
+ for (var j=0; j<facets.length; j++) {
+ var facet = facets[j];
+ var link = $('li[name='+facet.name+'] a', span);
+
+ var values = result ? result[facet.name] : null;
+ if (values) {
+ link.text(facet.tab_label+' ('+values.length+')');
+ } else {
+ link.text(facet.tab_label);
+ }
+ }
+ }
+ }
+ };
+
+ that.update_summary = function() {
+ var summary = that.facet.action_state.summary();
+
+ if (summary.state.length > 0) {
+ var css_class = summary.state.join(' ');
+ that.title_widget.set_class(css_class);
+ that.title_widget.set_icon_tooltip(summary.description);
+ }
+
+ that.adjust_elements();
+ };
+
+ that.get_max_pkey_length = function() {
+
+ var label_w, max_pkey_w, max_pkey_l, al, al_w, icon_w, char_w, container_w;
+
+ container_w = that.container.width();
+ icon_w = that.title_widget.icon.width();
+ label_w = that.title_widget.title.width();
+ char_w = label_w / that.title_widget.title.text().length;
+ max_pkey_w = container_w - icon_w - label_w;
+ max_pkey_w -= 10; //some space correction to be safe
+
+ if (that.action_list) {
+ al = that.action_list.container;
+ al_w = al.width();
+
+ max_pkey_w -= al_w;
+ }
+
+ max_pkey_l = Math.ceil(max_pkey_w / char_w);
+
+ return max_pkey_l;
+ };
+
+ that.adjust_elements = function() {
+
+ if (that.action_list) {
+
+ var action_list = that.action_list.container;
+ var max_width = that.container.width();
+ var al_width = action_list.width();
+ var title_width = that.title_widget.title_container.width();
+ var title_max = max_width - al_width;
+
+ that.title_widget.set_max_width(title_max);
+ action_list.css('left', title_width + 'px');
+ }
+ };
+
+ that.clear = function() {
+ that.load();
+ if (that.action_list) that.action_list.clear();
+ };
+
+ return that;
+};
+
+IPA.facet_title = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.update = function(data) {
+
+ var tooltip = data.tooltip || data.title;
+ var pkey_tooltip = data.pkey_tooltip || data.pkey;
+ var icon_tooltip = data.icon_tooltip || '';
+
+ that.title.text(data.title);
+ that.title.attr('title', tooltip);
+
+ if (data.pkey) {
+ that.title.text(data.title + ': ');
+ that.pkey.text(data.pkey);
+ that.pkey.attr('title', pkey_tooltip);
+ }
+
+ if (data.css_class) that.set_class(data.css_class);
+
+ that.set_icon_tooltip(icon_tooltip);
+ };
+
+ that.create = function(container) {
+
+ that.title_container = $('<div/>', {
+ 'class': 'facet-title'
+ }).appendTo(container);
+
+ that.icon = $('<div />', {
+ 'class': 'header-icon'
+ }).appendTo(that.title_container);
+
+ var h3 = $('<h3/>').appendTo(that.title_container);
+
+ that.title = $('<span/>').appendTo(h3);
+
+ that.pkey = $('<span/>', {
+ 'class': 'facet-pkey'
+ }).appendTo(h3);
+ };
+
+ that.set_max_width = function(width) {
+ that.title_container.css('max-width', width+'px');
+ };
+
+ that.set_class = function(css_class) {
+
+ if (that.css_class) {
+ that.title_container.removeClass(that.css_class);
+ }
+
+ if (css_class) {
+ that.title_container.addClass(css_class);
+ }
+
+ that.css_class = css_class;
+ };
+
+ that.set_icon_tooltip = function(tooltip) {
+ that.icon.attr('title', tooltip);
+ };
+
+ return that;
+};
+
+IPA.table_facet = function(spec, no_init) {
+
+ spec = spec || {};
+
+ var that = IPA.facet(spec, no_init);
+
+ that.managed_entity = spec.managed_entity ? IPA.get_entity(spec.managed_entity) : that.entity;
+
+ that.pagination = spec.pagination === undefined ? true : spec.pagination;
+ that.search_all_entries = spec.search_all_entries;
+ that.search_all_attributes = spec.search_all_attributes;
+ that.sort_enabled = spec.sort_enabled === undefined ? true : spec.sort_enabled;
+ that.selectable = spec.selectable === undefined ? true : spec.selectable;
+ that.select_changed = IPA.observer();
+
+ that.row_enabled_attribute = spec.row_enabled_attribute;
+ that.row_disabled_attribute = spec.row_disabled_attribute;
+ that.details_facet_name = spec.details_facet || 'default';
+
+ that.table_name = spec.table_name;
+
+ that.columns = $.ordered_map();
+
+ that.get_columns = function() {
+ return that.columns.values;
+ };
+
+ that.get_column = function(name) {
+ return that.columns.get(name);
+ };
+
+ that.add_column = function(column) {
+ column.entity = that.managed_entity;
+ that.columns.put(column.name, column);
+ };
+
+ that.create_column = function(spec) {
+ var column;
+ if (spec instanceof Object) {
+ var factory = spec.factory || IPA.column;
+ } else {
+ factory = IPA.column;
+ spec = { name: spec };
+ }
+
+ spec.entity = that.managed_entity;
+ column = factory(spec);
+
+ that.add_column(column);
+ return column;
+ };
+
+ that.column = function(spec){
+ that.create_column(spec);
+ return that;
+ };
+
+ that.create_content = function(container) {
+ that.table.create(container);
+ };
+
+ that.load = function(data) {
+ that.facet_load(data);
+
+ if (!data) {
+ that.table.empty();
+ that.table.summary.text('');
+ that.table.pagination_control.css('visibility', 'hidden');
+ return;
+ }
+
+ that.table.current_page = 1;
+ that.table.total_pages = 1;
+
+ if (that.pagination) {
+ that.load_page(data);
+ } else {
+ that.load_all(data);
+ }
+
+ that.table.current_page_input.val(that.table.current_page);
+ that.table.total_pages_span.text(that.table.total_pages);
+
+ that.table.pagination_control.css('visibility', 'visible');
+
+ that.post_load.notify([data], that);
+ that.clear_expired_flag();
+ };
+
+
+ that.load_all = function(data) {
+
+ var result = data.result.result;
+ var records = [];
+ for (var i=0; i<result.length; i++) {
+ var record = that.table.get_record(result[i], 0);
+ records.push(record);
+ }
+ that.load_records(records);
+
+ if (data.result.truncated) {
+ var message = IPA.messages.search.truncated;
+ message = message.replace('${counter}', data.result.count);
+ that.table.summary.text(message);
+ } else {
+ that.table.summary.text(data.result.summary || '');
+ }
+ };
+
+ that.get_records_map = function(data) {
+
+ var records_map = $.ordered_map();
+
+ var result = data.result.result;
+ var pkey_name = that.managed_entity.metadata.primary_key;
+
+ for (var i=0; i<result.length; i++) {
+ var record = result[i];
+ var pkey = record[pkey_name];
+ if (pkey instanceof Array) pkey = pkey[0];
+ records_map.put(pkey, record);
+ }
+
+ return records_map;
+ };
+
+ that.load_page = function(data) {
+
+ // get primary keys (and the complete records if search_all_entries is true)
+ var records_map = that.get_records_map(data);
+
+ var total = records_map.length;
+ that.table.total_pages = total ? Math.ceil(total / that.table.page_length) : 1;
+
+ delete that.table.current_page;
+
+ var state = {};
+ var page = parseInt(IPA.nav.get_state(that.entity.name+'-page'), 10) || 1;
+ if (page < 1) {
+ state[that.entity.name+'-page'] = 1;
+ IPA.nav.push_state(state);
+ return;
+ } else if (page > that.table.total_pages) {
+ state[that.entity.name+'-page'] = that.table.total_pages;
+ IPA.nav.push_state(state);
+ return;
+ }
+ that.table.current_page = page;
+
+ if (!total) {
+ that.table.summary.text(IPA.messages.association.no_entries);
+ that.load_records([]);
+ return;
+ }
+
+ // calculate the start and end of the current page
+ var start = (that.table.current_page - 1) * that.table.page_length + 1;
+ var end = that.table.current_page * that.table.page_length;
+ end = end > total ? total : end;
+
+ var summary = IPA.messages.association.paging;
+ summary = summary.replace('${start}', start);
+ summary = summary.replace('${end}', end);
+ summary = summary.replace('${total}', total);
+ that.table.summary.text(summary);
+
+ // sort map based on primary keys
+ if (that.sort_enabled) {
+ records_map = records_map.sort();
+ }
+
+ // trim map leaving the entries visible in the current page only
+ records_map = records_map.slice(start-1, end);
+
+ var columns = that.table.columns.values;
+ if (columns.length == 1) { // show primary keys only
+ that.load_records(records_map.values);
+ return;
+ }
+
+ if (that.search_all_entries) {
+ // map contains the primary keys and the complete records
+ that.load_records(records_map.values);
+ return;
+ }
+
+ // get the complete records
+ that.get_records(
+ records_map.keys,
+ function(data, text_status, xhr) {
+ var results = data.result.results;
+ for (var i=0; i<records_map.length; i++) {
+ var pkey = records_map.keys[i];
+ var record = records_map.get(pkey);
+ // merge the record obtained from the refresh()
+ // with the record obtained from get_records()
+ $.extend(record, results[i].result);
+ }
+ that.load_records(records_map.values);
+ },
+ function(xhr, text_status, error_thrown) {
+ that.load_records([]);
+ var summary = that.table.summary.empty();
+ summary.append(error_thrown.name+': '+error_thrown.message);
+ }
+ );
+ };
+
+ that.load_records = function(records) {
+ that.table.empty();
+ for (var i=0; i<records.length; i++) {
+ that.add_record(records[i]);
+ }
+ that.table.set_values(that.selected_values);
+ };
+
+ that.add_record = function(record) {
+
+ var tr = that.table.add_record(record);
+
+ var attribute;
+ if (that.row_enabled_attribute) {
+ attribute = that.row_enabled_attribute;
+ } else if (that.row_disabled_attribute) {
+ attribute = that.row_disabled_attribute;
+ } else {
+ return;
+ }
+
+ var value = record[attribute];
+ var column = that.table.get_column(attribute);
+ if (column.formatter) value = column.formatter.parse(value);
+
+ that.table.set_row_enabled(tr, value);
+ };
+
+ that.get_records_command_name = function() {
+ return that.managed_entity.name+'_get_records';
+ };
+
+ that.create_get_records_command = function(pkeys, on_success, on_error) {
+
+ var batch = IPA.batch_command({
+ name: that.get_records_command_name(),
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ for (var i=0; i<pkeys.length; i++) {
+ var pkey = pkeys[i];
+
+ var command = IPA.command({
+ entity: that.table.entity.name,
+ method: 'show',
+ args: [ pkey ],
+ options: { all: true }
+ });
+
+ batch.add_command(command);
+ }
+
+ return batch;
+ };
+
+ that.get_records = function(pkeys, on_success, on_error) {
+
+ var batch = that.create_get_records_command(pkeys, on_success, on_error);
+
+ batch.execute();
+ };
+
+ that.get_selected_values = function() {
+ return that.table.get_selected_values();
+ };
+
+ that.init_table = function(entity) {
+
+ that.table = IPA.table_widget({
+ 'class': 'content-table',
+ name: that.table_name || entity.metadata.primary_key,
+ label: entity.metadata.label,
+ entity: entity,
+ pagination: true,
+ search_all_attributes: that.search_all_attributes,
+ scrollable: true,
+ selectable: that.selectable && !that.read_only
+ });
+
+ var columns = that.columns.values;
+ for (var i=0; i<columns.length; i++) {
+ var column = columns[i];
+
+ var metadata = IPA.get_entity_param(entity.name, column.name);
+ column.primary_key = metadata && metadata.primary_key;
+ column.link = (column.link === undefined ? true : column.link) && column.primary_key;
+
+ if (column.link && column.primary_key) {
+ column.link_handler = function(value) {
+ IPA.nav.show_page(entity.name, that.details_facet_name, value);
+ return false;
+ };
+ }
+
+ that.table.add_column(column);
+ }
+
+ that.table.select_changed = function() {
+ that.selected_values = that.get_selected_values();
+ that.select_changed.notify([that.selected_values]);
+ };
+
+ that.table.prev_page = function() {
+ if (that.table.current_page > 1) {
+ var state = {};
+ state[that.entity.name+'-page'] = that.table.current_page - 1;
+ that.set_expired_flag();
+ IPA.nav.push_state(state);
+ }
+ };
+
+ that.table.next_page = function() {
+ if (that.table.current_page < that.table.total_pages) {
+ var state = {};
+ state[that.entity.name+'-page'] = that.table.current_page + 1;
+ that.set_expired_flag();
+ IPA.nav.push_state(state);
+ }
+ };
+
+ that.table.set_page = function(page) {
+ if (page < 1) {
+ page = 1;
+ } else if (page > that.total_pages) {
+ page = that.total_pages;
+ }
+ var state = {};
+ state[that.entity.name+'-page'] = page;
+ that.set_expired_flag();
+ IPA.nav.push_state(state);
+ };
+ };
+
+ that.init_table_columns = function() {
+ var columns = spec.columns || [];
+ for (var i=0; i<columns.length; i++) {
+ that.create_column(columns[i]);
+ }
+ };
+
+ if (!no_init) that.init_table_columns();
+
+ that.table_facet_create_get_records_command = that.create_get_records_command;
+
+ return that;
+};
+
+IPA.facet_group = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.label = spec.label;
+
+ that.facets = $.ordered_map();
+
+ that.add_facet = function(facet) {
+ that.facets.put(facet.name, facet);
+ };
+
+ that.get_facet = function(name) {
+ return that.facets.get(name);
+ };
+
+ that.get_facet_index = function(name) {
+ return that.facets.get_key_index(name);
+ };
+
+ that.get_facet_by_index = function(index) {
+ return that.facets.get_value_by_index(index);
+ };
+
+ that.get_facet_count = function(index) {
+ return that.facets.length;
+ };
+
+ return that;
+};
+
+IPA.facet_builder = function(entity) {
+
+ var that = {};
+
+ that.prepare_methods = {};
+
+ function init() {
+ that.prepare_methods.search = that.prepare_search_spec;
+ that.prepare_methods.nested_search = that.prepare_nested_search_spec;
+ that.prepare_methods.details = that.prepare_details_spec;
+ that.prepare_methods.association = that.prepare_association_spec;
+ that.prepare_methods.attribute = that.prepare_attribute_spec;
+ }
+
+ that.build_facets = function() {
+
+ if(entity.facet_specs && entity.facet_specs.length) {
+ var facets = entity.facet_specs;
+ for(var i=0; i<facets.length; i++) {
+ var facet_spec = facets[i];
+ that.build_facet(facet_spec);
+ }
+ }
+ };
+
+ that.build_facet = function(spec) {
+
+ //do common logic
+ spec.entity = entity;
+
+ //prepare spec based on type
+ var type = spec.type;
+ if (type) {
+ var prepare_method = that.prepare_methods[type];
+ if (prepare_method) {
+ prepare_method.call(that, spec);
+ }
+ }
+
+ //add facet
+ var facet = spec.factory(spec);
+ entity.add_facet(facet);
+ };
+
+ function add_redirect_info(facet_name) {
+
+ facet_name = facet_name || 'search';
+ if (!entity.redirect_facet){
+ entity.redirect_facet = facet_name;
+ }
+ }
+
+ that.prepare_search_spec = function(spec) {
+
+ spec.title = spec.title || entity.metadata.label;
+ spec.label = spec.label || entity.metadata.label;
+ spec.tab_label = spec.tab_label || IPA.messages.facets.search;
+ spec.factory = spec.factory || IPA.search_facet;
+
+ add_redirect_info();
+ return spec;
+ };
+
+ that.prepare_nested_search_spec = function(spec) {
+
+ spec.title = spec.title || entity.metadata.label_singular;
+ spec.label = spec.label || entity.metadata.label;
+ spec.tab_label = spec.tab_label || IPA.messages.facets.search;
+ spec.factory = spec.factory || IPA.nested_search_facet;
+
+ return spec;
+ };
+
+ that.prepare_details_spec = function(spec) {
+ spec.title = spec.title || entity.metadata.label_singular;
+ spec.label = spec.label || entity.metadata.label_singular;
+ spec.tab_label = spec.tab_label || IPA.messages.facets.details;
+ spec.factory = spec.factory || IPA.details_facet;
+
+ return spec;
+ };
+
+ that.prepare_attribute_spec = function(spec) {
+ spec.title = spec.title || entity.metadata.label_singular;
+ spec.label = spec.label || entity.metadata.label_singular;
+
+ var attr_metadata = IPA.get_entity_param(entity.name, spec.attribute);
+ spec.tab_label = spec.tab_label || attr_metadata.label;
+ spec.factory = spec.factory || IPA.attribute_facet;
+
+ entity.policies.add_policy(IPA.build({
+ factory: IPA.facet_update_policy,
+ source_facet: 'search',
+ dest_facet: spec.name
+ }));
+
+ return spec;
+ };
+
+ that.prepare_association_spec = function(spec) {
+
+ spec.entity = entity;
+
+ var index = spec.name.indexOf('_');
+ spec.attribute_member = spec.attribute_member ||
+ spec.name.substring(0, index);
+ spec.other_entity = spec.other_entity ||
+ spec.name.substring(index+1);
+
+ spec.add_title = IPA.messages.association.add[spec.attribute_member];
+ spec.remove_title = IPA.messages.association.remove[spec.attribute_member];
+
+ spec.facet_group = spec.facet_group || spec.attribute_member;
+
+ spec.factory = spec.factory || IPA.association_facet;
+
+ spec.label = spec.label || entity.metadata.label_singular;
+ spec.tab_label = spec.tab_label ||
+ (IPA.metadata.objects[spec.other_entity] ?
+ IPA.metadata.objects[spec.other_entity].label : spec.other_entity);
+
+ if (that.has_indirect_attribute_member(spec)) {
+
+ spec.indirect_attribute_member = spec.attribute_member + 'indirect';
+ }
+
+ if (spec.facet_group === 'memberindirect' ||
+ spec.facet_group === 'memberofindirect') {
+
+ spec.read_only = true;
+ }
+
+ entity.policies.add_policy(IPA.build({
+ factory: IPA.facet_update_policy,
+ source_facet: 'search',
+ dest_facet: spec.name
+ }));
+
+ return spec;
+ };
+
+ that.has_indirect_attribute_member = function(spec) {
+
+ var indirect_members = entity.metadata.attribute_members[spec.attribute_member + 'indirect'];
+ if (indirect_members) {
+ if (indirect_members.indexOf(spec.other_entity) > -1) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.action = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.label = spec.label;
+
+ that.enabled = spec.enabled !== undefined ? spec.enabled : true;
+ that.enable_cond = spec.enable_cond || [];
+ that.disable_cond = spec.disable_cond || [];
+ that.enabled_changed = IPA.observer();
+
+ that.visible = spec.visible !== undefined ? spec.visible : true;
+ that.show_cond = spec.show_cond || [];
+ that.hide_cond = spec.hide_cond || [];
+ that.visible_changed = IPA.observer();
+
+ that.handler = spec.handler;
+
+ that.needs_confirm = spec.needs_confirm !== undefined ? spec.needs_confirm : false;
+ that.confirm_msg = spec.confirm_msg || IPA.messages.actions.confirm;
+
+ that.confirm_dialog = spec.confirm_dialog !== undefined ? spec.confirm_dialog :
+ IPA.confirm_dialog;
+
+
+
+ that.execute_action = function(facet, on_success, on_error) {
+
+ if (that.handler) {
+ that.handler(facet, on_success, on_error);
+ }
+ };
+
+ that.execute = function(facet, on_success, on_error) {
+
+ if (!that.enabled || !that.visible) return;
+
+ if (that.needs_confirm) {
+
+ var confirmed = false;
+
+ if (that.confirm_dialog) {
+
+ that.dialog = IPA.build(that.confirm_dialog);
+ that.update_confirm_dialog(facet);
+ that.dialog.on_ok = function () {
+ that.execute_action(facet, on_success, on_error);
+ };
+ that.dialog.open();
+ } else {
+ var msg = that.get_confirm_message(facet);
+ confirmed = IPA.confirm(msg);
+ }
+
+ if (!confirmed) return;
+ }
+
+ that.execute_action(facet, on_success, on_error);
+ };
+
+ that.update_confirm_dialog = function(facet) {
+ that.dialog.message = that.get_confirm_message(facet);
+ };
+
+ that.get_confirm_message = function(facet) {
+ return that.confirm_msg;
+ };
+
+ that.set_enabled = function(enabled) {
+
+ var old = that.enabled;
+
+ that.enabled = enabled;
+
+ if (old !== that.enabled) {
+ that.enabled_changed.notify([that.enabled], that);
+ }
+ };
+
+ that.set_visible = function(visible) {
+
+ var old = that.visible;
+
+ that.visible = visible;
+
+ if (old !== that.visible) {
+ that.visible_changed.notify([that.visible], that);
+ }
+ };
+
+ return that;
+};
+
+IPA.action_builder = function(spec) {
+
+ spec = spec || {};
+ spec.factory = spec.factory || IPA.action;
+ var that = IPA.builder(spec);
+ return that;
+};
+
+
+IPA.action_holder = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.actions = $.ordered_map();
+
+ that.init = function(facet) {
+
+ var i, action, actions;
+
+ that.facet = facet;
+ actions = IPA.build(spec.actions, IPA.action_builder) || [];
+
+ for (i=0; i<actions.length; i++) {
+ action = actions[i];
+ that.actions.put(action.name, action);
+ }
+
+ that.facet.action_state.changed.attach(that.state_changed);
+ that.facet.post_load.attach(that.on_load);
+ };
+
+ that.state_changed = function(state) {
+
+ var actions, action, i, enabled, visible;
+
+ actions = that.actions.values;
+
+ for (i=0; i<actions.length; i++) {
+
+ action = actions[i];
+
+ enabled = IPA.eval_cond(action.enable_cond, action.disable_cond, state);
+ visible = IPA.eval_cond(action.show_cond, action.hide_cond, state);
+ action.set_enabled(enabled);
+ action.set_visible(visible);
+ }
+ };
+
+ that.get = function(name) {
+ return that.actions.get(name);
+ };
+
+ that.add = function(action) {
+ that.actions.put(action.name, action);
+ };
+
+ that.on_load = function() {
+ var state = that.facet.action_state.get();
+ that.state_changed(state);
+ };
+
+ return that;
+};
+
+IPA.action_holder_builder = function(spec) {
+
+ spec = spec || {};
+ spec.factory = spec.factory || IPA.action_holder;
+ var that = IPA.builder(spec);
+ return that;
+};
+
+
+IPA.state = function(spec) {
+
+ spec = spec || {};
+ spec.summary_evaluator = spec.summary_evaluator || IPA.summary_evaluator;
+
+ var that = {};
+
+ that.state = $.ordered_map();
+
+ //when state changes. Params: state, Context: this
+ that.changed = IPA.observer();
+
+ that.evaluators = IPA.build(spec.evaluators, IPA.state_evaluator_builder) || [];
+ that.summary_evaluator = IPA.build(spec.summary_evaluator);
+
+ that.summary_conditions = spec.summary_conditions || [];
+
+ that.init = function(facet) {
+
+ var i, evaluator;
+
+ that.facet = facet;
+
+ for (i=0; i<that.evaluators.length; i++) {
+ evaluator = that.evaluators[i];
+ evaluator.init(facet);
+ evaluator.changed.attach(that.on_eval_changed);
+ }
+ };
+
+ that.on_eval_changed = function() {
+
+ var evaluator = this;
+
+ that.state.put(evaluator.name, evaluator.state);
+
+ that.notify();
+ };
+
+ that.get = function() {
+
+ var state, i;
+
+ state = [];
+
+ var values = that.state.values;
+
+ for (i=0; i<values.length; i++) {
+ $.merge(state, values[i]);
+ }
+
+ return state;
+ };
+
+ that.summary = function() {
+
+ var summary = that.summary_evaluator.evaluate(that);
+ return summary;
+ };
+
+ that.notify = function(state) {
+
+ state = state || that.get();
+
+ that.changed.notify([state], that);
+ };
+
+ return that;
+};
+
+IPA.summary_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.evaluate = function(state) {
+
+ var conds, cond, i, summary, state_a;
+
+ conds = state.summary_conditions;
+ state_a = state.get();
+
+ for (i=0; i<conds.length; i++) {
+ cond = conds[i];
+ if (IPA.eval_cond(cond.pos, cond.neg, state_a)) {
+ summary = {
+ state: cond.state,
+ description: cond.description
+ };
+ break;
+ }
+ }
+
+ summary = summary || {
+ state: state_a,
+ description: ''
+ };
+
+ return summary;
+ };
+
+ return that;
+};
+
+IPA.state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name || 'state_evaluator';
+ that.event_name = spec.event;
+
+ //when state changes. Params: state, Context: this
+ that.changed = IPA.observer();
+ that.state = [];
+ that.first_pass = true;
+
+ that.init = function(facet) {
+
+ if (that.event_name && facet[that.event_name]) {
+ facet[that.event_name].attach(that.on_event);
+ }
+ };
+
+ that.on_event = function() {
+ };
+
+ that.notify_on_change = function(old_state) {
+
+ if (that.first_pass || IPA.array_diff(that.state, old_state)) {
+ that.changed.notify([that.state], that);
+ that.first_pass = false;
+ }
+ };
+
+ return that;
+};
+
+IPA.state_evaluator_builder = function(spec) {
+
+ spec = spec || {};
+ spec.factory = spec.factory || IPA.state_evaluator;
+ var that = IPA.builder(spec);
+ return that;
+};
+
+IPA.dirty_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.event = spec.event || 'dirty_changed';
+
+ var that = IPA.state_evaluator(spec);
+ that.name = spec.name || 'dirty_state_evaluator';
+
+ that.on_event = function(dirty) {
+
+ var old_state = that.state;
+ that.state = [];
+
+ if (dirty) {
+ that.state.push('dirty');
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.selected_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.event = spec.event || 'select_changed';
+
+ var that = IPA.state_evaluator(spec);
+ that.name = spec.name || 'selected_state_evaluator';
+
+ that.on_event = function(selected) {
+
+ var old_state = that.state;
+ that.state = [];
+
+ if (selected && selected.length > 0) {
+ that.state.push('item-selected');
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.self_service_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+ that.name = spec.name || 'self_service_state_evaluator';
+
+ that.on_event = function() {
+
+ var old_state = that.state;
+ that.state = [];
+
+ var self_service = IPA.nav.name === 'self-service';
+
+ if (self_service) {
+ that.state.push('self-service');
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.facet_attr_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.event = spec.event || 'post_load';
+
+ var that = IPA.state_evaluator(spec);
+ that.name = spec.name || 'facet_attr_se';
+ that.attribute = spec.attribute;
+ that.value = spec.value;
+ that.state_value = spec.state_value;
+
+ that.on_event = function() {
+
+ var old_state = that.state;
+ that.state = [];
+
+ var facet = this;
+
+ if (facet[that.attribute] === that.value) {
+ that.state.push(that.state_value);
+ }
+
+ that.notify_on_change(old_state);
+ };
+
+ return that;
+};
+
+IPA.read_only_state_evaluator = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'read_only_se';
+ spec.attribute = spec.attribute || 'read_only';
+ spec.state_value = spec.state_value || 'read-only';
+ spec.value = spec.value !== undefined ? spec.value : true;
+
+ var that = IPA.facet_attr_state_evaluator(spec);
+ return that;
+};
+
+IPA.association_type_state_evaluator = function(spec) {
+
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'association_type_se';
+ spec.attribute = spec.attribute || 'association_type';
+ spec.state_value = spec.state_value || 'direct';
+ spec.value = spec.value !== undefined ? spec.value : 'direct';
+
+ var that = IPA.facet_attr_state_evaluator(spec);
+ return that;
+};
+
+IPA.action_button_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.name = spec.name;
+ that.label = spec.label;
+ that.tooltip = spec.tooltip;
+ that.href = spec.href || that.name;
+ that.icon = spec.icon;
+
+ that.action_name = spec.action || that.name;
+
+ that.enabled = spec.enabled !== undefined ? spec.enabled : true;
+ that.visible = spec.visible !== undefined ? spec.visible : true;
+
+ that.show_cond = spec.show_cond || [];
+ that.hide_cond = spec.hide_cond || [];
+
+ that.init = function(facet) {
+
+ that.facet = facet;
+ that.action = that.facet.actions.get(that.action_name);
+ that.action.enabled_changed.attach(that.set_enabled);
+ that.action.visible_changed.attach(that.set_visible);
+ };
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.button_element = IPA.action_button({
+ name: that.name,
+ href: that.href,
+ label: that.label,
+ icon: that.icon,
+ click: function() {
+ that.on_click();
+ return false;
+ }
+ }).appendTo(container);
+
+ that.set_enabled(that.action.enabled);
+ that.set_visible(that.action.visible);
+ };
+
+ that.on_click = function() {
+
+ if (!that.enabled) return;
+
+ that.action.execute(that.facet);
+ };
+
+ that.set_enabled = function(enabled) {
+ that.enabled = enabled;
+
+ if (that.button_element) {
+ if (enabled) {
+ that.button_element.removeClass('action-button-disabled');
+ } else {
+ that.button_element.addClass('action-button-disabled');
+ }
+ }
+ };
+
+ that.set_visible = function(visible) {
+
+ that.visible = visible;
+
+ if (that.button_element) {
+ if (visible) {
+ that.button_element.show();
+ } else {
+ that.button_element.hide();
+ }
+ }
+ };
+
+ return that;
+};
+
+IPA.action_button_widget_builder = function(spec) {
+
+ spec = spec || {};
+ spec.factory = spec.factory || IPA.action_button_widget;
+ var that = IPA.builder(spec);
+ return that;
+};
+
+IPA.control_buttons_widget = function(spec) {
+
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.buttons = IPA.build(spec.buttons, IPA.action_button_widget_builder) || [];
+
+ that.init = function(facet) {
+
+ var i;
+
+ for (i=0; i<that.buttons.length; i++) {
+
+ var button = that.buttons[i];
+ button.init(facet);
+ }
+ };
+
+ that.create = function(container) {
+
+ that.container = $('<div/>', {
+ 'class': that['class']
+ }).appendTo(container);
+
+ for (var i=0; i<that.buttons.length; i++) {
+
+ var button = that.buttons[i];
+ button.create(that.container);
+ }
+ };
+
+ return that;
+};
+
+IPA.eval_cond = function(enable_cond, disable_cond, state) {
+
+ var i, cond;
+
+ if (disable_cond) {
+ for (i=0; i<disable_cond.length; i++) {
+ cond = disable_cond[i];
+ if (state.indexOf(cond) > -1) {
+ return false;
+ }
+ }
+ }
+
+ if (enable_cond) {
+ for (i=0; i<enable_cond.length; i++) {
+ cond = enable_cond[i];
+ if (state.indexOf(cond) < 0) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+};
+
+
+IPA.action_list_widget = function(spec) {
+
+ spec = spec || {};
+
+ spec.widgets = spec.widgets || [
+ {
+ type: 'html',
+ css_class: 'separator'
+ },
+ {
+ type: 'select',
+ name: 'action',
+ undo: false
+ },
+ {
+ type: 'button',
+ name: 'apply',
+ label: IPA.messages.actions.apply
+ }
+ ];
+
+ var that = IPA.composite_widget(spec);
+
+ that.action_names = spec.actions || [];
+ that.actions = $.ordered_map();
+
+ that.init = function(facet) {
+
+ var options, actions, action, name, i;
+
+ that.facet = facet;
+
+ that.action_select = that.widgets.get_widget('action');
+ that.apply_button = that.widgets.get_widget('apply');
+
+ that.action_select.value_changed.attach(that.on_action_change);
+ that.apply_button.click = that.on_apply;
+
+ for (i=0; i<that.action_names.length; i++) {
+ name = that.action_names[i];
+ action = that.facet.actions.get(name);
+ that.add_action(action, true);
+ }
+
+ that.init_options();
+ };
+
+ that.add_action = function(action, batch) {
+ that.actions.put(action.name, action);
+ action.enabled_changed.attach(that.action_enabled_changed);
+ action.visible_changed.attach(that.action_visible_changed);
+
+ if(!batch) {
+ that.init_options();
+ that.recreate_options();
+ that.select_first_enabled();
+ }
+ };
+
+ that.init_options = function() {
+
+ var options, actions, action, i;
+
+ options = [];
+ actions = that.actions.values;
+
+ for (i=0; i< actions.length; i++) {
+ action = actions[i];
+ options.push({
+ label: action.label,
+ value: action.name
+ });
+ }
+
+ that.action_select.options = options;
+ };
+
+ that.recreate_options = function() {
+
+ that.action_select.create_options();
+ };
+
+ that.on_action_change = function() {
+
+ var action = that.get_selected();
+ that.apply_button.set_enabled(action.enabled);
+ };
+
+ that.on_apply = function() {
+
+ var action = that.get_selected();
+
+ if (action.enabled) {
+ action.execute(that.facet,
+ that.on_action_success,
+ that.on_action_error);
+ }
+ };
+
+ that.on_action_success = function() {
+
+ that.facet.refresh();
+ };
+
+ that.on_action_error = function() {
+
+ that.facet.refresh();
+ };
+
+ that.action_enabled_changed = function(enabled) {
+ var action = this;
+ var selected_action = that.get_selected();
+ that.action_select.set_options_enabled(action.enabled, [action.name]);
+
+ if (!action.enabled && action === selected_action) {
+ that.select_first_enabled();
+ }
+ };
+
+ that.get_selected = function() {
+ var selected = that.action_select.save()[0];
+ var action = that.actions.get(selected);
+ return action;
+ };
+
+ that.get_disabled = function() {
+
+ var disabled = [];
+ var actions = that.action.values;
+
+ for (var i=0; i< actions.length; i++) {
+ var action = actions[i];
+ if (!that.action.enabled) {
+ disabled.push(action.name);
+ }
+ }
+
+ return disabled;
+ };
+
+ that.select_first_enabled = function() {
+
+ var actions = that.actions.values;
+
+ var first = actions[0].name;
+
+ for (var i=0; i< actions.length; i++) {
+ var action = actions[i];
+ if (action.enabled) {
+ first = action.name;
+ break;
+ }
+ }
+
+ that.action_select.update([first]);
+ };
+
+ that.clear = function() {
+
+ that.select_first_enabled();
+ };
+
+ return that;
+}; \ No newline at end of file
diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js
new file mode 100644
index 000000000..ff807dcfc
--- /dev/null
+++ b/install/ui/src/freeipa/field.js
@@ -0,0 +1,951 @@
+/*jsl:import ipa.js */
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Pavel Zuna <pzuna@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2011 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, widget.js */
+
+IPA.field = function(spec) {
+ spec = spec || {};
+
+ var that = {};
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.container = null;
+ that.name = spec.name;
+ that.param = spec.param || spec.name;
+ that.label = spec.label;
+ that.tooltip = spec.tooltip;
+ that.measurement_unit = spec.measurement_unit;
+ that.formatter = spec.formatter;
+
+ that.widget = null;
+ that.widget_name = spec.widget;
+
+ // override the required flag in metadata
+ that.required = spec.required;
+
+ // read_only is set when widget is created
+ that.read_only = spec.read_only;
+
+ // writable is set during load
+ that.writable = true;
+
+ that.enabled = spec.enabled === undefined ? true : spec.enabled;
+ that.flags = spec.flags || [];
+
+ that.undo = spec.undo === undefined ? true : spec.undo;
+
+ that.metadata = spec.metadata;
+ that.validators = spec.validators || [];
+
+ that.priority = spec.priority;
+
+ that.values = [];
+ that.dirty = false;
+ that.valid = true;
+
+ that.dirty_changed = IPA.observer();
+
+ var init = function() {
+ if (!that.metadata && that.entity) {
+ that.metadata = IPA.get_entity_param(that.entity.name, that.param);
+ }
+ if (that.metadata) {
+ if (that.label === undefined) {
+ that.label = that.metadata.label;
+ }
+ if (that.tooltip === undefined) {
+ that.tooltip = that.metadata.doc;
+ }
+ }
+
+ that.validators.push(IPA.metadata_validator());
+ };
+
+ that.is_required = function() {
+ if (that.read_only) return false;
+ if (!that.writable) return false;
+
+ if (that.required !== undefined) return that.required;
+ return that.metadata && that.metadata.required;
+ };
+
+ that.set_required = function(required) {
+ that.required = required;
+
+ that.update_required();
+ };
+
+ that.update_required = function() {
+ if(that.widget && that.widget.set_required) {
+ that.widget.set_required(that.is_required());
+ }
+ };
+
+ that.validate_required = function() {
+ var values = that.save();
+ if (IPA.is_empty(values) && that.is_required() && that.enabled) {
+ that.valid = false;
+ var message = IPA.get_message('widget.validation.required',
+ "Required field");
+ that.show_error(message);
+ return false;
+ }
+ return true;
+ };
+
+ /**
+ * Returns true and clears the error message if the field value passes
+ * the validation pattern. If the field value does not pass validation,
+ * displays the error message and returns false.
+ */
+ that.validate = function() {
+ that.hide_error();
+ that.valid = true;
+
+ if (!that.enabled) return that.valid;
+
+ var values = that.save();
+
+ if (IPA.is_empty(values)) {
+ return that.valid;
+ }
+
+ var value = values[0];
+
+ for (var i=0; i<that.validators.length; i++) {
+ var validation_result = that.validators[i].validate(value, that);
+ that.valid = validation_result.valid;
+ if (!that.valid) {
+ that.show_error(validation_result.message);
+ break;
+ }
+ }
+
+ return that.valid;
+ };
+
+ /**
+ * This function stores the entire record and the values
+ * of the field, then invoke reset() to update the UI.
+ */
+ that.load = function(record) {
+ that.record = record;
+
+ that.values = that.get_value(record, that.param);
+
+ that.load_writable(record);
+
+ that.reset();
+ };
+
+ that.get_value = function(record, name) {
+
+ var value = record[name];
+
+ if (!(value instanceof Array)) {
+ value = value !== undefined ? [value] : [];
+ }
+
+ if (!value.length) {
+ value = [''];
+ }
+
+ return value;
+ };
+
+ that.load_writable = function(record) {
+
+ that.writable = true;
+
+ if (that.metadata) {
+ if (that.metadata.primary_key) {
+ that.writable = false;
+ }
+
+ if (that.metadata.flags && 'no_update' in that.metadata.flags) {
+ that.writable = false;
+ }
+ }
+
+ if (record.attributelevelrights) {
+ var rights = record.attributelevelrights[that.param];
+ var oc_rights= record.attributelevelrights['objectclass'];
+ var write_oc = oc_rights && oc_rights.indexOf('w') > -1;
+
+ // Some objects in LDAP may not have set proper object class and
+ // therefore server doesn't send proper attribute rights. Flag
+ // 'w_if_no_aci' should be used when we want to ensure that UI
+ // shows edit interface in such cases. Usable only when user can
+ // modify object classes.
+ // For all others, lack of rights means no write.
+ if ((!rights && !(that.flags.indexOf('w_if_no_aci') > -1 && write_oc)) ||
+ (rights && rights.indexOf('w') < 0)) {
+ that.writable = false;
+ }
+ }
+ };
+
+ that.reset = function() {
+ that.set_widget_flags();
+ that.update_required();
+ that.update();
+ that.validate();
+ that.set_dirty(false);
+ };
+
+ that.update = function() {
+
+ if (!that.widget || !that.widget.update) return;
+
+ var formatted_values;
+
+ // The formatter is currently only used on read-only fields only
+ // because it cannot parse formatted values back to internal values.
+ if (that.formatter && that.read_only) {
+ formatted_values = [];
+ for (var i=0; that.values && i<that.values.length; i++) {
+ var value = that.values[i];
+ var formatted_value = that.formatter.format(value);
+ formatted_values.push(formatted_value);
+ }
+ } else {
+ formatted_values = that.values;
+ }
+
+ that.widget.update(formatted_values);
+ };
+
+ that.get_update_info = function() {
+
+ var update_info = IPA.update_info_builder.new_update_info();
+ if (that.is_dirty()) {
+ var values = that.save();
+ var field_info = IPA.update_info_builder.new_field_info(that, values);
+ update_info.fields.push(field_info);
+ }
+ return update_info;
+ };
+
+ /**
+ * This function saves the values entered in the UI.
+ * It returns the values in an array, or null if
+ * the field should not be saved.
+ */
+ that.save = function(record) {
+
+ var values = that.values;
+
+ if(!that.enabled) return [''];
+
+ if(that.widget) {
+ values = that.widget.save();
+ }
+
+ if(record) {
+ record[that.param] = values;
+ }
+
+ return values;
+ };
+
+ /**
+ * This function compares the original values and the
+ * values entered in the UI. If the values have changed
+ * it will return true.
+ */
+ that.test_dirty = function() {
+
+ if (that.read_only) return false;
+
+ var values = that.save();
+
+ //check for empty value: null, [''], '', []
+ var orig_empty = IPA.is_empty(that.values);
+ var new_empty= IPA.is_empty(values);
+ if (orig_empty && new_empty) return false;
+ if (orig_empty != new_empty) return true;
+
+ //strict equality - checks object's ref equality, numbers, strings
+ if (values === that.values) return false;
+
+ //compare values in array
+ if (values.length !== that.values.length) return true;
+
+ return !that.dirty_are_equal(that.values, values);
+ };
+
+ that.dirty_are_equal = function(orig_vals, new_vals) {
+
+ orig_vals.sort();
+ new_vals.sort();
+
+ for (var i=0; i<orig_vals.length; i++) {
+ if (orig_vals[i] !== new_vals[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ /**
+ * This function compares the original values and the
+ * values entered in the UI. If the values have changed
+ * it will return true.
+ */
+ that.is_dirty = function() {
+ return that.dirty;
+ };
+
+ that.set_dirty = function(dirty) {
+ var old = that.dirty;
+ that.dirty = dirty;
+ if (that.undo) {
+ that.show_undo(dirty);
+ }
+
+ if (old !== dirty) {
+ that.dirty_changed.notify([], that);
+ }
+ };
+
+
+ that.show_error = function(message) {
+ if (that.widget && that.widget.show_error) that.widget.show_error(message);
+ };
+
+ that.hide_error = function() {
+ if (that.widget && that.widget.hide_error) that.widget.hide_error();
+ };
+
+ that.show_undo = function(value) {
+ if (that.widget && that.widget.show_undo) {
+ if(value) { that.widget.show_undo(); }
+ else { that.widget.hide_undo(); }
+ }
+ };
+
+ that.set_enabled = function(value) {
+ that.enabled = value;
+ if (that.widget && that.widget.set_enabled) {
+ that.widget.set_enabled(value);
+ }
+ };
+
+ that.refresh = function() {
+ };
+
+ that.set_widget_flags = function() {
+
+ if (that.widget) {
+ if (that.label) that.widget.label = that.label;
+ if (that.tooltip) that.widget.tooltip = that.tooltip;
+ if (that.measurement_unit) that.widget.measurement_unit = that.measurement_unit;
+ that.widget.undo = that.undo;
+ that.widget.writable = that.writable;
+ that.widget.read_only = that.read_only;
+ }
+ };
+
+ that.widgets_created = function() {
+
+ that.widget = that.container.widgets.get_widget(that.widget_name);
+
+ if(that.widget) {
+ that.set_widget_flags();
+
+ that.widget.value_changed.attach(that.widget_value_changed);
+ that.widget.undo_clicked.attach(that.widget_undo_clicked);
+ }
+ };
+
+ that.widget_value_changed = function() {
+ that.set_dirty(that.test_dirty());
+ that.validate();
+ };
+
+ that.widget_undo_clicked = function() {
+ that.reset();
+ };
+
+ init();
+
+ // methods that should be invoked by subclasses
+ that.field_dirty_are_equal = that.dirty_are_equal;
+ that.field_load = that.load;
+ that.field_reset = that.reset;
+ that.field_save = that.save;
+ that.field_set_dirty = that.set_dirty;
+ that.field_show_error = that.show_error;
+ that.field_test_dirty = that.test_dirty;
+ that.field_widgets_created = that.widgets_created;
+
+ return that;
+};
+
+IPA.validator = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.message = spec.message || IPA.get_message('widget.validation.error');
+
+ that.false_result = function(message) {
+ return {
+ valid: false,
+ message: message || that.message
+ };
+ };
+
+ that.true_result = function() {
+ return {
+ valid: true
+ };
+ };
+
+ that.validate = function() {
+ return that.true_result();
+ };
+
+ return that;
+};
+
+IPA.metadata_validator = function(spec) {
+
+ var that = IPA.validator(spec);
+
+ that.validate = function(value, context) {
+
+ var message;
+ var metadata = context.metadata;
+ var number = false;
+
+ if (!metadata || IPA.is_empty(value)) return that.true_result();
+
+ if (metadata.type === 'int') {
+ number = true;
+ if (!value.match(/^-?\d+$/)) {
+ return that.false_result(IPA.messages.widget.validation.integer);
+ }
+ } else if (metadata.type === 'Decimal') {
+ number = true;
+ if (!value.match(/^-?\d+(\.\d+)?$/)) {
+ return that.false_result(IPA.messages.widget.validation.decimal);
+ }
+ }
+
+ if (number) {
+
+ if (IPA.defined(metadata.minvalue, true) && Number(value) < Number(metadata.minvalue)) {
+ message = IPA.messages.widget.validation.min_value;
+ message = message.replace('${value}', metadata.minvalue);
+ return that.false_result(message);
+ }
+
+ if (IPA.defined(metadata.maxvalue, true) && Number(value) > Number(metadata.maxvalue)) {
+ message = IPA.messages.widget.validation.max_value;
+ message = message.replace('${value}', metadata.maxvalue);
+ return that.false_result(message);
+ }
+ }
+
+ if (metadata.pattern) {
+ var regex = new RegExp(metadata.pattern);
+ if (!value.match(regex)) {
+ return that.false_result(metadata.pattern_errmsg);
+ }
+ }
+
+ return that.true_result();
+ };
+
+ return that;
+};
+
+IPA.unsupported_validator = function(spec) {
+
+ var that = IPA.validator(spec);
+
+ that.unsupported = spec.unsupported || [];
+ that.message = spec.message || IPA.messages.widget.validation.unsupported;
+
+ that.validate = function(value, context) {
+
+ if (IPA.is_empty(value)) return that.true_result();
+
+ if (that.unsupported.indexOf(value) > -1) return that.false_result();
+
+ return that.true_result();
+ };
+
+ return that;
+};
+
+IPA.same_password_validator = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.validator(spec);
+ that.other_field = spec.other_field;
+
+ that.message = spec.message || IPA.get_message('password.password_must_match',
+ "Passwords must match");
+ that.validate = function(value, context) {
+
+ var other_field = context.container.fields.get_field(that.other_field);
+ var other_value = other_field.save();
+ var this_value = context.save();
+
+ if (IPA.array_diff(this_value, other_value)) return that.false_result();
+
+ return that.true_result();
+ };
+
+ return that;
+};
+
+IPA.checkbox_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.checked = spec.checked || false;
+ that.boolean_formatter = IPA.boolean_formatter();
+
+ that.load = function(record) {
+
+ that.record = record;
+
+ that.values = that.get_value(record, that.param);
+
+ var value = that.boolean_formatter.parse(that.values);
+ if (value === '') value = that.widget.checked; //default value
+
+ that.values = [value];
+
+ that.load_writable(record);
+
+ that.reset();
+ };
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ that.widget.checked = that.checked;
+ };
+
+ // a checkbox will always have a value, so it's never required
+ that.is_required = function() {
+ return false;
+ };
+
+ that.checkbox_load = that.load;
+
+ return that;
+};
+
+IPA.checkboxes_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ return that;
+};
+
+IPA.radio_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ // a radio will always have a value, so it's never required
+ that.is_required = function() {
+ return false;
+ };
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ };
+
+ return that;
+};
+
+IPA.multivalued_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.load = function(record) {
+
+ that.field_load(record);
+ };
+
+ that.test_dirty = function() {
+ var dirty = that.field_test_dirty();
+ dirty = dirty || that.widget.test_dirty(); //also checks order
+ return dirty;
+ };
+
+ that.validate = function() {
+
+ var values = that.save();
+
+ return that.validate_core(values);
+ };
+
+ that.validate_core = function(values) {
+
+ that.hide_error();
+ that.valid = true;
+
+ if (IPA.is_empty(values)) {
+ return that.valid;
+ }
+
+ for (var i=0; i<values.length; i++) {
+
+ for (var j=0; j<that.validators.length; j++) {
+
+ var validation_result = that.validators[j].validate(values[i], that);
+ if (!validation_result.valid) {
+ that.valid = false;
+ var row_index = that.widget.get_saved_value_row_index(i);
+ that.widget.show_child_error(row_index, validation_result.message);
+ break;
+ }
+ }
+ }
+
+ return that.valid;
+ };
+
+ return that;
+};
+
+IPA.sshkeys_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.multivalued_field(spec);
+
+ // Fixes upgrade issue. When attr rights are missing due to lack of object class.
+ that.flags = spec.flags || ['w_if_no_aci'];
+
+ that.sshfp_attr = spec.sshfp_attr || 'sshpubkeyfp';
+
+ that.load = function(record) {
+
+ var keys = that.get_value(record, that.param);
+ var fingerprints = that.get_value(record, that.sshfp_attr);
+
+ var values = [];
+
+ if (keys.length === fingerprints.length) {
+ for (var i=0; i<keys.length; i++) {
+
+ if (keys[i] === '') continue;
+
+ var value = {
+ key: keys[i],
+ fingerprint: fingerprints[i]
+ };
+ values.push(value);
+ }
+ }
+
+ that.values = values;
+
+ that.load_writable(record);
+
+ that.reset();
+ };
+
+ that.dirty_are_equal = function(orig_vals, new_vals) {
+
+ var i;
+ var orig_keys = [];
+
+ for (i=0; i<orig_vals.length; i++) {
+ orig_keys.push(orig_vals[i].key);
+ }
+
+ return that.field_dirty_are_equal(orig_keys, new_vals);
+ };
+
+ return that;
+};
+
+IPA.select_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ };
+
+ return that;
+};
+
+
+IPA.combobox_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.widgets_created = function() {
+
+ that.field_widgets_created();
+ that.widget.input_field_changed.attach(that.on_input_field_changed);
+ };
+
+ that.on_input_field_changed = function() {
+ that.validate();
+ };
+
+ return that;
+};
+
+IPA.link_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+
+ function other_pkeys () {
+ return that.entity.get_primary_key();
+ }
+ that.other_pkeys = spec.other_pkeys || other_pkeys;
+
+ that.on_link_clicked = function() {
+
+ IPA.nav.show_entity_page(
+ that.other_entity,
+ 'default',
+ that.other_pkeys());
+ };
+
+ that.load = function(record) {
+
+ that.field_load(record);
+ that.check_entity_link();
+ };
+
+ that.check_entity_link = function() {
+
+ //In some cases other entity may not be present.
+ //For example when DNS is not configured.
+ if (!that.other_entity) {
+ that.widget.is_link = false;
+ that.widget.update(that.values);
+ return;
+ }
+
+ IPA.command({
+ entity: that.other_entity.name,
+ method: 'show',
+ args: that.other_pkeys(),
+ options: {},
+ retry: false,
+ on_success: function(data) {
+ that.widget.is_link = data.result && data.result.result;
+ that.widget.update(that.values);
+ },
+ on_error: function() {
+ that.widget.is_link = false;
+ that.widget.update(that.values);
+ }
+ }).execute();
+ };
+
+ that.widgets_created = function() {
+ that.field_widgets_created();
+ that.widget.link_clicked.attach(that.on_link_clicked);
+ };
+
+
+ return that;
+};
+
+IPA.enable_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.radio_field(spec);
+
+ that.enable_method = spec.enable_method || 'enable';
+ that.disable_method = spec.enable_method || 'disable';
+ that.enable_option = spec.enable_option || 'TRUE';
+
+ that.get_update_info = function() {
+
+ var info = IPA.update_info_builder.new_update_info();
+ if(that.test_dirty()) {
+ var values = that.save();
+ var method = that.disable_method;
+
+ if(values[0] === that.enable_option) {
+ method = that.enable_method;
+ }
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: method,
+ args: that.entity.get_primary_key(),
+ options: {all: true, rights: true}
+ });
+
+
+ info.append_command(command, that.priority);
+ }
+
+ return info;
+ };
+
+ return that;
+};
+
+// TODO: Add support for nested fields
+IPA.field_container = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.container = spec.container; //usually facet or dialog
+
+ that.fields = $.ordered_map();
+
+ that.get_field = function(name) {
+ return that.fields.get(name);
+ };
+
+ that.get_fields = function(name) {
+ return that.fields.values;
+ };
+
+ that.add_field = function(field) {
+ field.container = that.container;
+ that.fields.put(field.name, field);
+ };
+
+ that.widgets_created = function() {
+ var fields = that.fields.values;
+
+ for (var i=0; i<fields.length; i++) {
+ fields[i].widgets_created();
+ }
+ };
+
+ that.container_add_field = that.add_field;
+
+ return that;
+};
+
+IPA.field_builder = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.default_factory = spec.default_factory || IPA.field;
+ that.container = spec.container;
+ that.field_options = spec.field_options || {};
+
+ that.get_field_factory = function(spec) {
+
+ var factory;
+ if (spec.factory) {
+ factory = spec.factory;
+ } else if(spec.type) {
+ factory = IPA.field_factories[spec.type];
+ }
+
+ if (!factory) {
+ factory = that.default_factory;
+ }
+
+ return factory;
+ };
+
+ that.build_field = function(spec, container) {
+
+ container = container || that.container;
+
+ if(!(spec instanceof Object)) {
+ spec = { name: spec };
+ }
+
+ if(that.field_options) {
+ $.extend(spec, that.field_options);
+ }
+
+ var factory = that.get_field_factory(spec);
+
+ var field = factory(spec);
+
+ if(container) {
+ container.add_field(field);
+ }
+
+ return field;
+ };
+
+ that.build_fields = function(specs, container) {
+
+ container = container || that.container;
+
+ for(var i=0; i<specs.length; i++) {
+ that.build_field(specs[i], container);
+ }
+ };
+
+ return that;
+};
+
+IPA.field_factories['checkbox'] = IPA.checkbox_field;
+IPA.field_factories['checkboxes'] = IPA.checkboxes_field;
+IPA.field_factories['combobox'] = IPA.combobox_field;
+IPA.field_factories['enable'] = IPA.enable_field;
+IPA.field_factories['entity_select'] = IPA.combobox_field;
+IPA.field_factories['field'] = IPA.field;
+IPA.field_factories['link'] = IPA.link_field;
+IPA.field_factories['multivalued'] = IPA.multivalued_field;
+IPA.field_factories['password'] = IPA.field;
+IPA.field_factories['radio'] = IPA.radio_field;
+IPA.field_factories['select'] = IPA.select_field;
+IPA.field_factories['sshkeys'] = IPA.sshkeys_field;
+IPA.field_factories['textarea'] = IPA.field;
+IPA.field_factories['text'] = IPA.field;
+IPA.field_factories['value_map'] = IPA.field; \ No newline at end of file
diff --git a/install/ui/src/freeipa/group.js b/install/ui/src/freeipa/group.js
new file mode 100644
index 000000000..8317d679f
--- /dev/null
+++ b/install/ui/src/freeipa/group.js
@@ -0,0 +1,259 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.group = {};
+
+IPA.group.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'gidnumber',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'details',
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ },
+ {
+ type: 'value_map',
+ name: 'external',
+ param: 'objectclass',
+ label: IPA.messages.objects.group.type,
+ default_label: IPA.messages.objects.group.normal,
+ value_map: {
+ ipaexternalgroup: IPA.messages.objects.group.external,
+ posixgroup: IPA.messages.objects.group.posix
+ }
+ },
+ 'gidnumber'
+ ]
+ }
+ ],
+ actions: [
+ IPA.select_action,
+ IPA.group.make_posix_action,
+ IPA.group.make_external_action,
+ IPA.delete_action
+ ],
+ header_actions: ['select_action', 'make_posix', 'make_external', 'delete'],
+ state: {
+ evaluators: [
+ IPA.object_class_evaluator
+ ]
+ }
+ }).
+ association_facet({
+ name: 'member_user',
+ columns:[
+ 'uid',
+ 'uidnumber',
+ 'mail',
+ 'telephonenumber',
+ 'title'
+ ],
+ adder_columns:[
+ {
+ name: 'cn',
+ width: '100px'
+ },
+ {
+ name: 'uid',
+ primary_key: true,
+ width: '100px'
+ }
+ ]
+ }).
+ association_facet({
+ name: 'member_group'
+ }).
+ attribute_facet({
+ name: 'member_external',
+ attribute: 'ipaexternalmember',
+ tab_label: 'External',
+ facet_group: 'member',
+ columns: [
+ {
+ name: 'ipaexternalmember',
+ label: IPA.get_command_option('group_add_member', 'ipaexternalmember').label
+ }
+ ]
+
+ }).
+ association_facet({
+ name: 'memberof_group',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_netgroup',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_role',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_hbacrule',
+ associator: IPA.serial_associator,
+ add_method: 'add_user',
+ remove_method: 'remove_user'
+ }).
+ association_facet({
+ name: 'memberof_sudorule',
+ associator: IPA.serial_associator,
+ add_method: 'add_user',
+ remove_method: 'remove_user'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ factory: IPA.group_adder_dialog,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ },
+ {
+ type: 'radio',
+ name: 'type',
+ label: IPA.messages.objects.group.type,
+ flags: ['no_command'],
+ default_value: 'posix',
+ options: [
+ {
+ value: 'normal',
+ label: IPA.messages.objects.group.normal
+ },
+ {
+ value: 'external',
+ label: IPA.messages.objects.group.external
+ },
+ {
+ value: 'posix',
+ label: IPA.messages.objects.group.posix
+ }
+ ]
+ },
+ 'gidnumber'
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.group_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ var init = function() {
+
+ var type_field = that.fields.get_field('type');
+ type_field.widget.value_changed.attach(that.on_type_change);
+ };
+
+ that.on_type_change = function(value) {
+
+ var gid_field = that.fields.get_field('gidnumber');
+ var external_field = that.fields.get_field('external');
+
+ var posix = value[0] === 'posix';
+
+ if (!posix) {
+ gid_field.reset();
+ }
+
+ gid_field.set_enabled(posix);
+ };
+
+ that.create_add_command = function(record) {
+
+ var command = that.entity_adder_dialog_create_add_command(record);
+
+ var type_field = that.fields.get_field('type');
+ var type = type_field.save()[0];
+
+ if (type === 'normal') {
+ command.set_option('nonposix', true);
+ } else if (type === 'external') {
+ command.set_option('external', true);
+ }
+
+ return command;
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.group.make_posix_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'make_posix';
+ spec.method = spec.method || 'mod';
+ spec.label = spec.label || IPA.messages.objects.group.make_posix;
+ spec.disable_cond = spec.disable_cond || ['oc_posixgroup', 'oc_ipaexternalgroup'];
+ spec.options = spec.options || {
+ posix: true
+ };
+
+ var that = IPA.object_action(spec);
+
+ return that;
+};
+
+IPA.group.make_external_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'make_external';
+ spec.method = spec.method || 'mod';
+ spec.label = spec.label || IPA.messages.objects.group.make_external;
+ spec.disable_cond = spec.disable_cond || ['oc_posixgroup','oc_ipaexternalgroup'];
+ spec.options = spec.options || {
+ external: true
+ };
+
+ var that = IPA.object_action(spec);
+
+ return that;
+};
+
+IPA.register('group', IPA.group.entity);
diff --git a/install/ui/src/freeipa/hbac.js b/install/ui/src/freeipa/hbac.js
new file mode 100644
index 000000000..63c928aab
--- /dev/null
+++ b/install/ui/src/freeipa/hbac.js
@@ -0,0 +1,553 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.hbac = {
+ //priority of commands in details facet
+ remove_method_priority: IPA.config.default_priority - 1
+};
+
+IPA.hbac.rule_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ row_enabled_attribute: 'ipaenabledflag',
+ search_all_attributes: true,
+ columns: [
+ 'cn',
+ {
+ name: 'ipaenabledflag',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ },
+ 'description'
+ ],
+ actions: [
+ IPA.batch_disable_action,
+ IPA.batch_enable_action
+ ],
+ control_buttons: [
+ {
+ name: 'disable',
+ label: IPA.messages.buttons.disable,
+ icon: 'disabled-icon'
+ },
+ {
+ name: 'enable',
+ label: IPA.messages.buttons.enable,
+ icon: 'enabled-icon'
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.hbacrule_details_facet,
+ entity: that,
+ command_mode: 'info',
+ actions: [
+ IPA.select_action,
+ IPA.enable_action,
+ IPA.disable_action,
+ IPA.delete_action
+ ],
+ header_actions: ['select_action', 'enable', 'disable', 'delete'],
+ state: {
+ evaluators: [
+ {
+ factory: IPA.enable_state_evaluator,
+ field: 'ipaenabledflag'
+ }
+ ],
+ summary_conditions: [
+ IPA.enabled_summary_cond(),
+ IPA.disabled_summary_cond()
+ ]
+ }
+ }).
+ adder_dialog({
+ fields: [ 'cn' ]
+ });
+ };
+
+ return that;
+};
+
+IPA.hbac.service_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'memberof_hbacsvcgroup',
+ associator: IPA.serial_associator,
+ columns:[
+ 'cn',
+ 'description'
+ ],
+ adder_columns: [
+ {
+ name: 'cn',
+ primary_key: true,
+ width: '100px'
+ },
+ {
+ name: 'description',
+ width: '100px'
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.hbac.service_group_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'member_hbacsvc',
+ columns:[
+ 'cn',
+ 'description'
+ ],
+ adder_columns: [
+ {
+ name: 'cn',
+ primary_key: true,
+ width: '100px'
+ },
+ {
+ name: 'description',
+ width: '100px'
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.hbacrule_details_facet = function(spec) {
+
+ var entity_name = spec.entity.name;
+
+ //
+ // General
+ //
+
+ spec.fields = [
+ {
+ name: 'cn',
+ read_only: true,
+ widget: 'general.cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description',
+ widget: 'general.description'
+ }
+ ];
+
+ spec.widgets = [
+ {
+ type: 'details_table_section',
+ name: 'general',
+ label: IPA.messages.details.general,
+ widgets: [
+ {
+ name: 'cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ];
+
+ //
+ // Users
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'usercategory',
+ widget: 'user.rule.usercategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_user',
+ widget: 'user.rule.memberuser_user',
+ priority: IPA.hbac.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_group',
+ widget: 'user.rule.memberuser_group',
+ priority: IPA.hbac.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'user',
+ label: IPA.messages.objects.hbacrule.user,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'usercategory',
+ options: [
+ { value: 'all',
+ label: IPA.messages.objects.hbacrule.anyone },
+ { value: '',
+ label: IPA.messages.objects.hbacrule.specified_users }
+ ],
+ tables: [
+ { name: 'memberuser_user' },
+ { name: 'memberuser_group' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberuser_user',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberuser_group',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Hosts
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'hostcategory',
+ widget: 'host.rule.hostcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_host',
+ widget: 'host.rule.memberhost_host',
+ priority: IPA.hbac.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_hostgroup',
+ widget: 'host.rule.memberhost_hostgroup',
+ priority: IPA.hbac.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'host',
+ label: IPA.messages.objects.hbacrule.host,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'hostcategory',
+ options: [
+ {
+ 'value': 'all',
+ 'label': IPA.messages.objects.hbacrule.any_host
+ },
+ {
+ 'value': '',
+ 'label': IPA.messages.objects.hbacrule.specified_hosts
+ }
+ ],
+ tables: [
+ { 'name': 'memberhost_host' },
+ { 'name': 'memberhost_hostgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberhost_host',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberhost_hostgroup',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Service
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'servicecategory',
+ widget: 'service.rule.servicecategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberservice_hbacsvc',
+ widget: 'service.rule.memberservice_hbacsvc',
+ priority: IPA.hbac.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberservice_hbacsvcgroup',
+ widget: 'service.rule.memberservice_hbacsvcgroup',
+ priority: IPA.hbac.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'service',
+ label: IPA.messages.objects.hbacrule.service,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'servicecategory',
+ options: [
+ { 'value': 'all', 'label': IPA.messages.objects.hbacrule.any_service },
+ { 'value': '', 'label': IPA.messages.objects.hbacrule.specified_services }
+ ],
+ tables: [
+ { 'name': 'memberservice_hbacsvc' },
+ { 'name': 'memberservice_hbacsvcgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberservice_hbacsvc',
+ add_method: 'add_service',
+ remove_method: 'remove_service',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberservice_hbacsvcgroup',
+ add_method: 'add_service',
+ remove_method: 'remove_service',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Source host
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'sourcehostcategory',
+ widget: 'sourcehost.rule.sourcehostcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'sourcehost_host',
+ widget: 'sourcehost.rule.sourcehost_host',
+ priority: IPA.hbac.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'sourcehost_hostgroup',
+ widget: 'sourcehost.rule.sourcehost_hostgroup',
+ priority: IPA.hbac.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'sourcehost',
+ label: IPA.messages.objects.hbacrule.sourcehost,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'sourcehostcategory',
+ options: [
+ { 'value': 'all', 'label': IPA.messages.objects.hbacrule.any_host },
+ { 'value': '', 'label': IPA.messages.objects.hbacrule.specified_hosts }
+ ],
+ tables: [
+ { 'name': 'sourcehost_host' },
+ { 'name': 'sourcehost_hostgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'sourcehost_host',
+ add_method: 'add_sourcehost',
+ remove_method: 'remove_sourcehost',
+ add_title: IPA.messages.association.add.sourcehost,
+ remove_title: IPA.messages.association.remove.sourcehost
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'sourcehost_hostgroup',
+ add_method: 'add_sourcehost',
+ remove_method: 'remove_sourcehost',
+ add_title: IPA.messages.association.add.sourcehost,
+ remove_title: IPA.messages.association.remove.sourcehost
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ var that = IPA.details_facet(spec);
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.refresh();
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ that.refresh();
+ };
+
+ return that;
+};
+
+IPA.register('hbacrule', IPA.hbac.rule_entity);
+IPA.register('hbacsvc', IPA.hbac.service_entity);
+IPA.register('hbacsvcgroup', IPA.hbac.service_group_entity);
diff --git a/install/ui/src/freeipa/hbactest.js b/install/ui/src/freeipa/hbactest.js
new file mode 100644
index 000000000..93d17c719
--- /dev/null
+++ b/install/ui/src/freeipa/hbactest.js
@@ -0,0 +1,842 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js,hbac.js */
+
+IPA.hbac.test_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.get_default_metadata = function() {
+ return IPA.metadata.commands[that.name];
+ };
+
+ that.init = function() {
+ that.entity_init();
+
+ that.label = IPA.messages.objects.hbactest.label;
+
+ that.builder.facet_groups([ 'default' ]).
+ facet({
+ factory: IPA.hbac.test_select_facet,
+ name: 'user',
+ label: IPA.messages.objects.hbacrule.user,
+ managed_entity: 'user',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ row_disabled_attribute: 'nsaccountlock',
+ columns: [
+ 'uid',
+ 'givenname',
+ 'sn',
+ {
+ name: 'nsaccountlock',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter({
+ invert_value: true
+ })
+ }
+ ]
+ }).
+ facet({
+ factory: IPA.hbac.test_select_facet,
+ name: 'targethost',
+ label: IPA.messages.objects.hbacrule.host,
+ managed_entity: 'host',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ columns: [
+ 'fqdn',
+ 'description',
+ {
+ name: 'has_keytab',
+ label: IPA.messages.objects.host.enrolled,
+ formatter: IPA.boolean_formatter()
+ }
+ ]
+ }).
+ facet({
+ factory: IPA.hbac.test_select_facet,
+ name: 'service',
+ label: IPA.messages.objects.hbacrule.service,
+ managed_entity: 'hbacsvc',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ facet({
+ factory: IPA.hbac.test_select_facet,
+ name: 'sourcehost',
+ label: IPA.messages.objects.hbacrule.sourcehost,
+ managed_entity: 'host',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ columns: [
+ 'fqdn',
+ 'description',
+ {
+ name: 'has_keytab',
+ label: IPA.messages.objects.host.enrolled,
+ formatter: IPA.boolean_formatter()
+ }
+ ]
+ }).
+ facet({
+ factory: IPA.hbac.test_rules_facet,
+ name: 'rules',
+ label: IPA.messages.objects.hbactest.rules,
+ managed_entity: 'hbacrule',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ row_enabled_attribute: 'ipaenabledflag',
+ columns: [
+ 'cn',
+ {
+ name: 'ipaenabledflag',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ },
+ 'description'
+ ]
+ }).
+ facet({
+ factory: IPA.hbac.test_run_facet,
+ name: 'run_test',
+ label: IPA.messages.objects.hbactest.run_test,
+ managed_entity: 'hbacrule',
+ disable_breadcrumb: true,
+ facet_group: 'default',
+ row_enabled_attribute: 'ipaenabledflag',
+ columns: [
+ 'cn',
+ {
+ name: 'matched',
+ label: IPA.messages.objects.hbactest.matched,
+ formatter: IPA.boolean_formatter()
+ },
+ {
+ name: 'ipaenabledflag',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ },
+ 'description'
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.hbac.test_facet = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.table_facet(spec);
+
+ var init = function() {
+
+ that.managed_entity = IPA.get_entity(that.managed_entity);
+
+ var columns = that.columns.values;
+ for (var i=0; i<columns.length; i++) {
+ var column = columns[i];
+
+ var metadata = IPA.get_entity_param(that.managed_entity.name, column.name);
+ column.primary_key = metadata && metadata.primary_key;
+ column.link = column.primary_key;
+ }
+
+ that.init_table(that.managed_entity);
+ };
+
+ that.create_buttons = function(container) {
+
+ var buttons = $('<div/>', {
+ 'class': 'hbac-test-navigation-buttons'
+ }).appendTo(container);
+
+ var facet_group = that.entity.get_facet_group('default');
+ var index = facet_group.get_facet_index(that.name);
+
+ if (index > 0) {
+ that.prev_button = IPA.button({
+ name: 'prev',
+ label: IPA.messages.widget.prev,
+ icon: 'ui-icon ui-icon-triangle-1-w',
+ click: function() {
+ if (!that.prev_button.hasClass('action-button-disabled')) {
+ that.prev();
+ }
+ return false;
+ }
+ }).appendTo(buttons);
+
+ buttons.append(' ');
+ }
+
+ that.next_button = IPA.button({
+ name: 'next',
+ label: IPA.messages.widget.next,
+ icon: 'ui-icon ui-icon-triangle-1-e',
+ click: function() {
+ if (!that.next_button.hasClass('action-button-disabled')) {
+ that.next();
+ }
+ return false;
+ }
+ }).appendTo(buttons);
+ };
+
+ that.prev = function() {
+ var facet_group = that.entity.get_facet_group('default');
+ var index = facet_group.get_facet_index(that.name);
+ if (index <= 0) return;
+
+ var facet = facet_group.get_facet_by_index(index - 1);
+
+ var state = {};
+ state[that.entity.name+'-facet'] = facet.name;
+ IPA.nav.push_state(state);
+ };
+
+ that.next = function() {
+ var facet_group = that.entity.get_facet_group('default');
+ var index = facet_group.get_facet_index(that.name);
+ if (index >= facet_group.get_facet_count() - 1) return;
+
+ var facet = facet_group.get_facet_by_index(index + 1);
+
+ var state = {};
+ state[that.entity.name+'-facet'] = facet.name;
+ IPA.nav.push_state(state);
+ };
+
+ that.get_search_command_name = function() {
+ return that.managed_entity.name + '_find' + (that.pagination ? '_pkeys' : '');
+ };
+
+ that.refresh = function() {
+
+ var filter = IPA.nav.get_state(that.entity.name+'-'+that.name+'-filter');
+
+ var command = IPA.command({
+ name: that.get_search_command_name(),
+ entity: that.managed_entity.name,
+ method: 'find',
+ args: [filter]
+ });
+
+ if (that.pagination) {
+ command.set_option('pkey_only', true);
+ command.set_option('sizelimit', 0);
+ }
+
+ command.on_success = function(data, text_status, xhr) {
+ that.load(data);
+ that.show_content();
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.report_error(error_thrown);
+ };
+
+ command.execute();
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.hbac.test_select_facet = function(spec) {
+
+ var that = IPA.hbac.test_facet(spec);
+
+ var init = function() {
+ that.table.multivalued = false;
+
+ that.table.set_values = function(values) {
+ if (values && values.length && values[0] === '__external__') {
+ if (that.external_radio) that.external_radio.prop('checked', true);
+ } else {
+ that.table.table_set_values(values);
+ }
+ };
+ };
+
+ that.create_content = function(container) {
+
+ var header = $('<div/>', {
+ 'class': 'hbac-test-header'
+ }).appendTo(container);
+
+ var title = $('<span/>', {
+ text: that.label,
+ 'class': 'hbac-test-title'
+ }).appendTo(header);
+
+ var filter_container = $('<div/>', {
+ 'class': 'search-filter'
+ }).appendTo(header);
+
+ that.filter = $('<input/>', {
+ type: 'text',
+ name: 'filter'
+ }).appendTo(filter_container);
+
+ that.filter.keypress(function(e) {
+ /* if the key pressed is the enter key */
+ if (e.which == 13) {
+ that.find();
+ }
+ });
+
+ that.find_button = IPA.action_button({
+ name: 'find',
+ icon: 'search-icon',
+ click: function() {
+ that.find();
+ return false;
+ }
+ }).appendTo(filter_container);
+
+ header.append(IPA.create_network_spinner());
+
+ var content = $('<div/>', {
+ 'class': 'hbac-test-content'
+ }).appendTo(container);
+
+ that.table.create(content);
+
+ var id = that.entity.name+'-'+that.name+'-external';
+ var pkey_name = that.managed_entity.metadata.primary_key;
+
+ var tr = $('<tr/>').appendTo(that.table.tfoot);
+
+ var td = $('<td/>', {
+ name: 'external'
+ }).appendTo(tr);
+
+ that.external_radio = $('<input/>', {
+ id: id,
+ type: 'radio',
+ name: pkey_name,
+ value: '__external__',
+ click: function() {
+ that.selected_values = [ that.external_radio.val() ];
+ }
+ }).appendTo(td);
+
+ var message = IPA.messages.objects.hbactest.specify_external;
+ message = message.replace('${entity}', that.managed_entity.metadata.label_singular);
+
+ $('<label/>', {
+ text: message+':',
+ 'for': id
+ }).appendTo(td);
+
+ td.append(' ');
+
+ that.external_text = $('<input/>', {
+ name: id,
+ focus: function() {
+ that.external_radio.click();
+ }
+ }).appendTo(td);
+
+ var footer = $('<div/>', {
+ 'class': 'hbac-test-footer'
+ }).appendTo(container);
+
+ that.create_buttons(footer);
+ };
+
+ that.find = function() {
+
+ var old_filter = IPA.nav.get_state(that.entity.name+'-'+that.name+'-filter');
+ var filter = that.filter.val();
+
+ that.set_expired_flag();
+
+ if (old_filter === filter) {
+ that.refresh();
+ } else {
+ var state = {};
+ state[that.entity.name+'-'+that.name+'-filter'] = filter;
+ IPA.nav.push_state(state);
+ }
+ };
+
+ that.get_selected_values = function() {
+ var values = that.table.get_selected_values();
+ if (values && values.length) return values;
+
+ if (that.external_radio && that.external_radio.is(':checked')) {
+ return [ that.external_radio.val() ];
+ }
+
+ return [];
+ };
+
+ that.reset = function() {
+ delete that.selected_values;
+ if (that.external_radio) that.external_radio.prop('checked', false);
+ if (that.external_text) that.external_text.val('');
+ };
+
+ that.save = function(record) {
+ if (that.selected_values && that.selected_values.length) {
+ var value = that.selected_values[0];
+ if (that.external_radio && value === that.external_radio.val()) {
+ record[that.name] = that.external_text.val();
+ } else {
+ record[that.name] = value;
+ }
+ }
+ };
+
+ that.validate = function(record) {
+ if (record[that.name]) return true;
+
+ return false;
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.hbac.test_rules_facet = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.hbac.test_facet(spec);
+
+ var init = function() {
+ };
+
+ that.create_content = function(container) {
+
+ var header = $('<div/>', {
+ 'class': 'hbac-test-header'
+ }).appendTo(container);
+
+ var title = $('<span/>', {
+ text: that.label,
+ 'class': 'hbac-test-title'
+ }).appendTo(header);
+
+ header.append(' ');
+
+ that.enabled = $('<input/>', {
+ id: 'hbactest-rules-include-enabled',
+ type: 'checkbox',
+ name: 'enabled'
+ }).appendTo(header);
+
+ $('<label/>', {
+ 'for': 'hbactest-rules-include-enabled',
+ text: IPA.messages.objects.hbactest.include_enabled
+ }).appendTo(header);
+
+ that.disabled = $('<input/>', {
+ id: 'hbactest-rules-include-disabled',
+ type: 'checkbox',
+ name: 'disabled'
+ }).appendTo(header);
+
+ $('<label/>', {
+ 'for': 'hbactest-rules-include-disabled',
+ text: IPA.messages.objects.hbactest.include_disabled
+ }).appendTo(header);
+
+ var content = $('<div/>', {
+ 'class': 'hbac-test-content'
+ }).appendTo(container);
+
+ that.table.create(content);
+
+ var footer = $('<div/>', {
+ 'class': 'hbac-test-footer'
+ }).appendTo(container);
+
+ that.create_buttons(footer);
+ };
+
+ that.get_selected_values = function() {
+ return that.table.get_selected_values();
+ };
+
+ that.reset = function() {
+ delete that.selected_values;
+ if (that.enabled) that.enabled.prop('checked', false);
+ if (that.disabled) that.disabled.prop('checked', false);
+ };
+
+ that.save = function(record) {
+ if (that.selected_values && that.selected_values.length) {
+ record[that.name] = that.selected_values;
+ }
+ if (that.enabled && that.enabled.is(':checked')) {
+ record['enabled'] = true;
+ }
+ if (that.disabled && that.disabled.is(':checked')) {
+ record['disabled'] = true;
+ }
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.hbac.test_run_facet = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.hbac.test_facet(spec);
+
+ var init = function() {
+ that.table.selectable = false;
+ that.show_matched = true;
+ that.show_unmatched = true;
+ };
+
+ that.create_content = function(container) {
+
+ var header = $('<div/>', {
+ 'class': 'hbac-test-header'
+ }).appendTo(container);
+
+ var top_panel = $('<div/>', {
+ 'class': 'hbac-test-top-panel'
+ }).appendTo(header);
+
+ var button_panel = $('<div/>', {
+ 'class': 'hbac-test-button-panel'
+ }).appendTo(top_panel);
+
+ that.run_button = IPA.button({
+ name: 'run_test',
+ label: IPA.messages.objects.hbactest.run_test,
+ click: function() {
+ if (!that.run_button.hasClass('action-button-disabled')) {
+ that.run();
+ }
+ return false;
+ }
+ }).appendTo(button_panel);
+
+ var result_panel = $('<div/>', {
+ 'class': 'hbac-test-result-panel'
+ }).appendTo(top_panel);
+
+ that.test_result = $('<p/>', {
+ 'class': 'hbac-test-title'
+ }).appendTo(result_panel);
+
+ var title = $('<span/>', {
+ text: IPA.messages.objects.hbactest.rules,
+ 'class': 'hbac-test-title'
+ }).appendTo(header);
+
+ header.append(' ');
+
+ that.matched_checkbox = $('<input/>', {
+ id: 'hbactest-rules-matched',
+ type: 'checkbox',
+ name: 'matched',
+ checked: true,
+ change: function() {
+ that.show_matched = that.matched_checkbox.is(':checked');
+ that.refresh();
+ }
+ }).appendTo(header);
+
+ $('<label/>', {
+ 'for': 'hbactest-rules-matched',
+ text: IPA.messages.objects.hbactest.matched
+ }).appendTo(header);
+
+ that.unmatched_checkbox = $('<input/>', {
+ id: 'hbactest-rules-unmatched',
+ type: 'checkbox',
+ name: 'unmatched',
+ checked: true,
+ change: function() {
+ that.show_unmatched = that.unmatched_checkbox.is(':checked');
+ that.refresh();
+ }
+ }).appendTo(header);
+
+ $('<label/>', {
+ 'for': 'hbactest-rules-unmatched',
+ text: IPA.messages.objects.hbactest.unmatched
+ }).appendTo(header);
+
+ var content = $('<div/>', {
+ 'class': 'hbac-test-content'
+ }).appendTo(container);
+
+ that.table.create(content);
+
+ var footer = $('<div/>', {
+ 'class': 'hbac-test-footer'
+ }).appendTo(container);
+
+ var buttons = $('<div/>', {
+ 'class': 'hbac-test-navigation-buttons'
+ }).appendTo(footer);
+
+ that.prev_button = IPA.button({
+ name: 'prev',
+ label: IPA.messages.widget.prev,
+ icon: 'ui-icon ui-icon-triangle-1-w',
+ click: function() {
+ if (!that.prev_button.hasClass('action-button-disabled')) {
+ that.prev();
+ }
+ return false;
+ }
+ }).appendTo(buttons);
+
+ buttons.append(' ');
+
+ that.new_test_button = IPA.button({
+ name: 'new_test',
+ label: IPA.messages.objects.hbactest.new_test,
+ click: function() {
+ if (!that.new_test_button.hasClass('action-button-disabled')) {
+ that.new_test();
+ }
+ return false;
+ }
+ }).appendTo(buttons);
+ };
+
+ that.new_test = function() {
+ var facet = that.entity.get_facet('user');
+ facet.reset();
+
+ facet = that.entity.get_facet('targethost');
+ facet.reset();
+
+ facet = that.entity.get_facet('service');
+ facet.reset();
+
+ facet = that.entity.get_facet('sourcehost');
+ facet.reset();
+
+ facet = that.entity.get_facet('rules');
+ facet.reset();
+
+ facet = that.entity.get_facet('run_test');
+ facet.reset();
+
+ var state = {};
+ state[that.entity.name+'-facet'] = 'user';
+ IPA.nav.push_state(state);
+ };
+
+ that.reset = function() {
+ delete that.data;
+ that.show_matched = true;
+ that.show_unmatched = true;
+ if (that.matched_checkbox) that.matched_checkbox.prop('checked', true);
+ if (that.unmatched_checkbox) that.unmatched_checkbox.prop('checked', true);
+ that.refresh();
+ };
+
+ that.refresh = function() {
+ if (that.data) {
+ var message = that.data.result.value ?
+ IPA.messages.objects.hbactest.access_granted :
+ IPA.messages.objects.hbactest.access_denied;
+ that.test_result.text(message);
+
+ } else {
+ that.test_result.text('');
+ }
+
+ that.load(that.data);
+ };
+
+ that.run = function() {
+
+ var command = IPA.command({ method: 'hbactest' });
+
+ var options = {};
+ var validation_results = {
+ valid: true,
+ invalid_facets: []
+ };
+
+ var facet = that.entity.get_facet('user');
+ facet.save(options);
+ that.validate_facet(facet, options, validation_results);
+
+ facet = that.entity.get_facet('targethost');
+ facet.save(options);
+ that.validate_facet(facet, options, validation_results);
+
+ facet = that.entity.get_facet('service');
+ facet.save(options);
+ that.validate_facet(facet, options, validation_results);
+
+ facet = that.entity.get_facet('sourcehost');
+ facet.save(options);
+ that.validate_facet(facet, options, validation_results);
+
+ if (!validation_results.valid) {
+ var dialog = IPA.hbac.validation_dialog({
+ validation_results: validation_results
+ });
+ dialog.open();
+ return;
+ }
+
+ facet = that.entity.get_facet('rules');
+ facet.save(options);
+
+ command.set_options(options);
+
+ command.on_success = function(data, text_status, xhr) {
+ that.data = data;
+ that.refresh();
+ };
+
+ command.execute();
+ };
+
+ that.validate_facet = function(facet, options, validation_results) {
+
+ var facet_valid = facet.validate(options);
+
+ validation_results.valid = facet_valid && validation_results.valid;
+
+ if (!facet_valid) {
+ validation_results.invalid_facets.push(facet);
+ }
+ };
+
+ that.get_records_map = function(data) {
+
+ var records_map = $.ordered_map();
+
+ var matched = data.result.matched;
+ if (that.show_matched && matched) {
+ for (var i=0; i<matched.length; i++) {
+ var pkey = matched[i];
+ records_map.put(pkey, { matched: true });
+ }
+ }
+
+ var notmatched = data.result.notmatched;
+ if (that.show_unmatched && notmatched) {
+ for (i=0; i<notmatched.length; i++) {
+ pkey = notmatched[i];
+ records_map.put(pkey, { matched: false });
+ }
+ }
+
+ return records_map;
+ };
+
+ that.get_records_command_name = function() {
+ if (that.show_matched && !that.show_unmatched) {
+ return 'hbactest_matched';
+ }
+ if (!that.show_matched && that.show_unmatched) {
+ return 'hbactest_unmatched';
+ }
+ return that.managed_entity.name+'_get_records';
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.hbac.validation_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.title = spec.title || IPA.messages.dialogs.validation_title;
+ spec.message = spec.message || IPA.messages.dialogs.validation_message;
+
+ var that = IPA.message_dialog(spec);
+
+ that.validation_results = spec.validation_results;
+
+ that.create = function() {
+
+ if (that.message) {
+ that.message_dialog_create();
+ }
+
+ if (that.validation_results && that.validation_results.invalid_facets) {
+ var invalid_facets = that.validation_results.invalid_facets;
+
+ var ul;
+
+ if (invalid_facets.length > 0) {
+ var div = $('<div/>',{
+ text: IPA.messages.objects.hbactest.missing_values
+ }).appendTo(that.container);
+ ul = $('<ul/>').appendTo(that.container);
+ }
+
+ for (var i=0; i<invalid_facets.length; i++) {
+
+ var facet = invalid_facets[i];
+
+ var li = $('<li />').appendTo(ul);
+
+ var metadata = IPA.get_command_option('hbactest', facet.name);
+
+ $('<a />', {
+ href: '#'+facet.name,
+ text: metadata.label,
+ click: function(facet) {
+ return function() {
+ that.redirect_to_facet(facet);
+ return false;
+ };
+ }(facet)
+ }).appendTo(li);
+ }
+ }
+ };
+
+ that.redirect_to_facet = function(facet) {
+ that.close();
+ var state = {};
+ state[facet.entity.name+'-facet'] = facet.name;
+ IPA.nav.push_state(state);
+ };
+
+ return that;
+};
+
+IPA.register('hbactest', IPA.hbac.test_entity);
diff --git a/install/ui/src/freeipa/host.js b/install/ui/src/freeipa/host.js
new file mode 100644
index 000000000..30086b414
--- /dev/null
+++ b/install/ui/src/freeipa/host.js
@@ -0,0 +1,947 @@
+/*jsl:import ipa.js */
+/*jsl:import certificate.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.host = {};
+
+IPA.host.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'fqdn',
+ 'description',
+ {
+ name: 'has_keytab',
+ label: IPA.messages.objects.host.enrolled,
+ formatter: IPA.boolean_formatter()
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.host.details_facet,
+ sections: [
+ {
+ name: 'details',
+ fields: [
+ {
+ type: 'host_dnsrecord_entity_link',
+ name: 'fqdn',
+ other_entity: 'dnsrecord'
+ },
+ 'krbprincipalname',
+ {
+ type: 'textarea',
+ name: 'description'
+ },
+ 'l',
+ 'nshostlocation',
+ 'nshardwareplatform',
+ 'nsosversion',
+ {
+ type: 'sshkeys',
+ name: 'ipasshpubkey',
+ label: IPA.messages.objects.sshkeystore.keys
+ },
+ {
+ type: 'multivalued',
+ name: 'macaddress',
+ flags: ['w_if_no_aci']
+ }
+ ]
+ },
+ {
+ name: 'enrollment',
+ action_panel: {
+ factory: IPA.action_panel,
+ name: 'enrollment_actions',
+ actions: ['unprovision', 'set_otp', 'reset_otp']
+ },
+ fields: [
+ {
+ factory: IPA.host_keytab_widget,
+ name: 'has_keytab',
+ label: IPA.messages.objects.host.keytab
+ },
+ {
+ type: 'host_password',
+ name: 'has_password',
+ label: IPA.messages.objects.host.password
+ }
+ ]
+ },
+ {
+ name: 'certificate',
+ action_panel: {
+ factory: IPA.action_panel,
+ name: 'cert_actions',
+ actions: [
+ 'request_cert', 'view_cert', 'get_cert',
+ 'revoke_cert', 'restore_cert'
+ ]
+ },
+ fields: [
+ {
+ type: 'certificate_status',
+ name: 'certificate_status',
+ label: IPA.messages.objects.host.status
+ }
+ ]
+ }
+ ],
+ actions: [
+ IPA.host.unprovision_action,
+ {
+ factory: IPA.host.set_otp_action,
+ name: 'set_otp',
+ label: IPA.messages.objects.host.password_set_title,
+ status: 'missing',
+ hide_cond: ['has_password']
+ },
+ {
+ factory: IPA.host.set_otp_action,
+ name: 'reset_otp',
+ label: IPA.messages.objects.host.password_reset_title,
+ status: 'present',
+ show_cond: ['has_password']
+ },
+ IPA.cert.view_action,
+ IPA.cert.get_action,
+ IPA.cert.request_action,
+ IPA.cert.revoke_action,
+ IPA.cert.restore_action
+ ],
+ state: {
+ evaluators: [
+ IPA.host.has_password_evaluator,
+ IPA.host.has_keytab_evaluator,
+ IPA.host.userpassword_acl_evaluator,
+ IPA.host.krbprincipalkey_acl_evaluator,
+ IPA.cert.certificate_evaluator
+ ]
+ },
+ policies: [
+ IPA.host.enrollment_policy(),
+ IPA.host.certificate_policy()
+ ]
+ }).
+ association_facet({
+ name: 'managedby_host',
+ add_method: 'add_managedby',
+ remove_method: 'remove_managedby'
+ }).
+ association_facet({
+ name: 'memberof_hostgroup',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_netgroup',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_role',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_hbacrule',
+ associator: IPA.serial_associator,
+ add_method: 'add_host',
+ remove_method: 'remove_host'
+ }).
+ association_facet({
+ name: 'memberof_sudorule',
+ associator: IPA.serial_associator,
+ add_method: 'add_host',
+ remove_method: 'remove_host'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ factory: IPA.host_adder_dialog,
+ height: 300,
+ sections: [
+ {
+ factory: IPA.composite_widget,
+ name: 'fqdn',
+ fields: [
+ {
+ type: 'host_fqdn',
+ name: 'fqdn',
+ required: true
+ }
+ ]
+ },
+ {
+ name: 'other',
+ fields: [
+ {
+ name: 'ip_address',
+ validators: [ IPA.ip_address_validator() ],
+ metadata: IPA.get_command_option('host_add', 'ip_address')
+ },
+ {
+ type: 'force_host_add_checkbox',
+ name: 'force',
+ metadata: IPA.get_command_option('host_add', 'force')
+ }
+ ]
+ }
+ ]
+ }).
+ deleter_dialog({
+ factory: IPA.host_deleter_dialog
+ });
+ };
+
+ return that;
+};
+
+IPA.host.details_facet = function(spec, no_init) {
+
+ var that = IPA.details_facet(spec, true);
+ that.certificate_loaded = IPA.observer();
+
+ that.get_refresh_command_name = function() {
+ return that.entity.name+'_show_'+that.pkey;
+ };
+
+ if (!no_init) that.init_details_facet();
+
+ return that;
+};
+
+IPA.host_fqdn_widget = function(spec) {
+
+ spec = spec || {};
+
+ spec.widgets = [
+ {
+ type: 'text',
+ name: 'hostname',
+ label: IPA.messages.objects.service.host,
+ required: true
+ },
+ {
+ type: 'dnszone_select',
+ name: 'dnszone',
+ label: IPA.metadata.objects.dnszone.label_singular,
+ editable: true,
+ empty_option: false,
+ required: true,
+ searchable: true
+ }
+ ];
+
+ var that = IPA.composite_widget(spec);
+
+ that.create = function(container) {
+ that.container = container;
+
+ var hostname = that.widgets.get_widget('hostname');
+ var dnszone = that.widgets.get_widget('dnszone');
+
+ var table = $('<table/>', {
+ 'class': 'fqdn'
+ }).appendTo(that.container);
+
+ var tr = $('<tr/>').appendTo(table);
+
+ var th = $('<th/>', {
+ 'class': 'hostname',
+ title: hostname.label,
+ text: hostname.label
+ }).appendTo(tr);
+
+ $('<span/>', {
+ 'class': 'required-indicator',
+ text: IPA.required_indicator
+ }).appendTo(th);
+
+ th = $('<th/>', {
+ 'class': 'dnszone',
+ title: dnszone.label,
+ text: dnszone.label
+ }).appendTo(tr);
+
+ $('<span/>', {
+ 'class': 'required-indicator',
+ text: IPA.required_indicator
+ }).appendTo(th);
+
+ tr = $('<tr/>').appendTo(table);
+
+ var td = $('<td/>', {
+ 'class': 'hostname'
+ }).appendTo(tr);
+
+ var span = $('<span/>', {
+ name: hostname.name
+ }).appendTo(td);
+ hostname.create(span);
+
+ td = $('<td/>', {
+ 'class': 'dnszone'
+ }).appendTo(tr);
+
+ span = $('<span/>', {
+ name: dnszone.name
+ }).appendTo(td);
+ dnszone.create(span);
+
+ var hostname_input = $('input', hostname.container);
+ var dnszone_input = $('input', dnszone.container);
+
+ hostname_input.keyup(function(e) {
+ var value = hostname_input.val();
+ var i = value.indexOf('.');
+ if (i >= 0) {
+ var hostname = value.substr(0, i);
+ var dnszone = value.substr(i+1);
+ hostname_input.val(hostname);
+ if (dnszone) {
+ dnszone_input.val(dnszone);
+ dnszone_input.focus();
+ }
+ IPA.select_range(dnszone_input, 0, dnszone_input.val().length);
+ }
+ });
+ };
+
+ return that;
+};
+
+IPA.host_fqdn_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.validate_required = function() {
+
+ var hostname = that.hostname_widget.save();
+ var dnszone = that.dns_zone_widget.save();
+
+ var valid = true;
+
+ if(!hostname.length || hostname[0] === '') {
+ that.hostname_widget.show_error(IPA.messages.widget.validation.required);
+ that.valid = valid = false;
+ }
+
+ if(!dnszone.length || dnszone[0] === '') {
+ that.dns_zone_widget.show_error(IPA.messages.widget.validation.required);
+ that.valid = valid = false;
+ }
+
+ return valid;
+ };
+
+ that.hide_error = function() {
+ that.hostname_widget.hide_error();
+ that.dns_zone_widget.hide_error();
+ };
+
+ that.save = function(record) {
+
+ if(!record) record = {};
+
+ var hostname = that.hostname_widget.save()[0];
+ var dnszone = that.dns_zone_widget.save()[0];
+
+ record.fqdn = hostname && dnszone ? [ hostname+'.'+dnszone ] : [];
+
+ return record.fqdn;
+ };
+
+ that.reset = function() {
+
+ that.hostname_widget.update([]);
+ that.dns_zone_widget.update([]);
+ };
+
+ that.widgets_created = function() {
+
+ that.widget = that.container.widgets.get_widget(that.widget_name);
+ that.hostname_widget = that.widget.widgets.get_widget('hostname');
+ that.dns_zone_widget = that.widget.widgets.get_widget('dnszone');
+ };
+
+ return that;
+};
+
+IPA.field_factories['host_fqdn'] = IPA.host_fqdn_field;
+IPA.widget_factories['host_fqdn'] = IPA.host_fqdn_widget;
+
+IPA.host_adder_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.retry = spec.retry !== undefined ? spec.retry : false;
+
+ if (!IPA.dns_enabled) {
+
+ //When server is installed without DNS support, a use of host_fqdn_widget
+ //is bad because there are no DNS zones. IP address field is useless as
+ //well. Special section and IP address field should be removed and normal
+ //fqdn textbox has to be added.
+ spec.sections.shift();
+ spec.sections[0].fields.shift();
+ spec.sections[0].fields.unshift('fqdn');
+ delete spec.height;
+ }
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.create = function() {
+ that.entity_adder_dialog_create();
+ that.container.addClass('host-adder-dialog');
+ };
+
+ that.on_error = IPA.create_4304_error_handler(that);
+
+ return that;
+};
+
+IPA.host_deleter_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.search_deleter_dialog(spec);
+
+ that.create = function() {
+
+ that.deleter_dialog_create();
+
+ var metadata = IPA.get_command_option('host_del', 'updatedns');
+
+ that.updatedns = $('<input/>', {
+ type: 'checkbox',
+ name: 'updatedns',
+ title: metadata.doc
+ }).appendTo(that.container);
+
+ that.container.append(' ');
+
+ that.container.append(metadata.doc);
+ };
+
+ that.create_command = function() {
+ var batch = that.search_deleter_dialog_create_command();
+ var updatedns = that.updatedns.is(':checked');
+
+ for (var i=0; i<batch.commands.length; i++) {
+ var command = batch.commands[i];
+ command.set_option('updatedns', updatedns);
+ }
+
+ return batch;
+ };
+
+ return that;
+};
+
+IPA.dnszone_select_widget = function(spec) {
+
+ spec = spec || {};
+ spec.other_entity = 'dnszone';
+ spec.other_field = 'idnsname';
+
+ var that = IPA.entity_select_widget(spec);
+
+ that.create_search_command = function(filter) {
+ return IPA.command({
+ entity: that.other_entity.name,
+ method: 'find',
+ args: [filter],
+ options: {
+ forward_only: true
+ }
+ });
+ };
+
+ return that;
+};
+
+IPA.field_factories['dnszone_select'] = IPA.field;
+IPA.widget_factories['dnszone_select'] = IPA.dnszone_select_widget;
+
+IPA.host_dnsrecord_entity_link_field = function(spec){
+ var that = IPA.link_field(spec);
+
+ that.other_pkeys = function(){
+ var pkey = that.entity.get_primary_key()[0];
+ var first_dot = pkey.search(/\./);
+ var pkeys = [];
+ pkeys[1] = pkey.substring(0,first_dot);
+ pkeys[0] = pkey.substring(first_dot+1);
+ return pkeys;
+ };
+
+ return that;
+};
+
+IPA.field_factories['host_dnsrecord_entity_link'] = IPA.host_dnsrecord_entity_link_field;
+IPA.widget_factories['host_dnsrecord_entity_link'] = IPA.link_widget;
+
+IPA.force_host_add_checkbox_widget = function(spec) {
+ var metadata = IPA.get_command_option('host_add', spec.name);
+ spec.label = metadata.label;
+ spec.tooltip = metadata.doc;
+ return IPA.checkbox_widget(spec);
+};
+
+IPA.widget_factories['force_host_add_checkbox'] = IPA.force_host_add_checkbox_widget;
+IPA.field_factories['force_host_add_checkbox'] = IPA.checkbox_field;
+
+IPA.host.enrollment_policy = function(spec) {
+
+ var that = IPA.facet_policy();
+
+ that.init = function() {
+
+ var keytab_field = that.container.fields.get_field('has_keytab');
+ var password_field = that.container.fields.get_field('has_password');
+
+ var super_set_password = password_field.set_password;
+ password_field.set_password = function(password, on_success, on_error) {
+ super_set_password.call(
+ this,
+ password,
+ function(data, text_status, xhr) {
+ keytab_field.load(data.result.result);
+ if (on_success) on_success.call(this, data, text_status, xhr);
+ },
+ on_error);
+ };
+ };
+
+ return that;
+};
+
+IPA.host_keytab_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.missing_span = $('<span/>', {
+ name: 'missing',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/caution-icon.png',
+ 'class': 'status-icon'
+ }).appendTo(that.missing_span);
+
+ that.missing_span.append(' ');
+
+ that.missing_span.append(IPA.messages.objects.host.keytab_missing);
+
+ that.present_span = $('<span/>', {
+ name: 'present',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/check-icon.png',
+ 'class': 'status-icon'
+ }).appendTo(that.present_span);
+
+ that.present_span.append(' ');
+
+ that.present_span.append(IPA.messages.objects.host.keytab_present);
+ };
+
+ that.update = function(values) {
+ set_status(values[0] ? 'present' : 'missing');
+ };
+
+ that.clear = function() {
+ that.present_span.css('display', 'none');
+ that.missing_span.css('display', 'none');
+ };
+
+ function set_status(status) {
+ that.present_span.css('display', status == 'present' ? 'inline' : 'none');
+ that.missing_span.css('display', status == 'missing' ? 'inline' : 'none');
+ }
+
+ return that;
+};
+
+IPA.host_unprovision_dialog = function(spec) {
+
+ spec.title = spec.title || IPA.messages.objects.host.unprovision_title;
+
+ spec = spec || {};
+
+ var that = IPA.dialog(spec);
+ that.facet = spec.facet;
+
+ that.title = that.title.replace('${entity}', that.entity.metadata.label_singular);
+
+ that.create = function() {
+ that.container.append(IPA.messages.objects.host.unprovision_confirmation);
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'unprovision',
+ label: IPA.messages.objects.host.unprovision,
+ click: function() {
+ that.unprovision(
+ function(data, text_status, xhr) {
+ that.facet.refresh();
+ that.close();
+ IPA.notify_success(IPA.messages.objects.host.unprovisioned);
+ },
+ function(xhr, text_status, error_thrown) {
+ that.close();
+ }
+ );
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+ };
+
+ that.unprovision = function(on_success, on_error) {
+
+ var pkey = that.entity.get_primary_key();
+
+ var command = IPA.command({
+ name: that.entity.name+'_disable_'+pkey,
+ entity: that.entity.name,
+ method: 'disable',
+ args: pkey,
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.host.unprovision_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'unprovision';
+ spec.label = spec.label || IPA.messages.objects.host.unprovision;
+ spec.enable_cond = spec.enable_cond || ['has_keytab', 'krbprincipalkey_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var dialog = IPA.host_unprovision_dialog({
+ entity: facet.entity,
+ facet: facet
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.host.krbprincipalkey_acl_evaluator = function(spec) {
+
+ spec.name = spec.name || 'unprovision_acl_evaluator';
+ spec.attribute = spec.attribute || 'krbprincipalkey';
+
+ var that = IPA.acl_state_evaluator(spec);
+ return that;
+};
+
+IPA.host.has_keytab_evaluator = function(spec) {
+
+ spec.name = spec.name || 'has_keytab_evaluator';
+ spec.attribute = spec.attribute || 'has_keytab';
+ spec.value = spec.value || [true];
+ spec.representation = spec.representation || 'has_keytab';
+
+ var that = IPA.value_state_evaluator(spec);
+ return that;
+};
+
+IPA.host_password_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.missing_span = $('<span/>', {
+ name: 'missing'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/caution-icon.png',
+ 'class': 'status-icon'
+ }).appendTo(that.missing_span);
+
+ that.missing_span.append(' ');
+
+ that.missing_span.append(IPA.messages.objects.host.password_missing);
+
+ that.present_span = $('<span/>', {
+ name: 'present',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/check-icon.png',
+ 'class': 'status-icon'
+ }).appendTo(that.present_span);
+
+ that.present_span.append(' ');
+
+ that.present_span.append(IPA.messages.objects.host.password_present);
+ };
+
+ that.update = function(values) {
+ set_status(values[0] ? 'present' : 'missing');
+ };
+
+ that.clear = function() {
+ that.missing_span.css('display', 'none');
+ that.present_span.css('display', 'none');
+ };
+
+ function set_status(status) {
+
+ that.status = status;
+
+ if (status == 'missing') {
+ that.missing_span.css('display', 'inline');
+ that.present_span.css('display', 'none');
+ } else {
+ that.missing_span.css('display', 'none');
+ that.present_span.css('display', 'inline');
+ }
+ }
+
+ return that;
+};
+
+IPA.widget_factories['host_password'] = IPA.host_password_widget;
+IPA.field_factories['host_password'] = IPA.field;
+
+IPA.host.set_otp_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.width = spec.width || 400;
+ spec.sections = spec.sections || [
+ {
+ fields: [
+ {
+ name: 'password1',
+ label: IPA.messages.password.new_password,
+ type: 'password',
+ required: true
+ },
+ {
+ name: 'password2',
+ label: IPA.messages.password.verify_password,
+ type: 'password',
+ required: true,
+ validators: [IPA.same_password_validator({
+ other_field: 'password1'
+ })]
+ }
+ ]
+ }
+ ];
+
+ var that = IPA.dialog(spec);
+
+ IPA.confirm_mixin().apply(that);
+
+ that.facet = spec.facet;
+
+ that.set_status = function(status) {
+
+ var button = that.get_button('set_password');
+
+ if (status == 'missing') {
+ that.title = IPA.messages.objects.host.password_set_title;
+ button.label = IPA.messages.objects.host.password_set_button;
+ } else {
+ that.title = IPA.messages.objects.host.password_reset_title;
+ button.label = IPA.messages.objects.host.password_reset_button;
+ }
+ };
+
+ that.on_confirm = function() {
+
+ if (!that.validate()) return;
+
+ var new_password = that.fields.get_field('password1').save()[0];
+ that.set_otp(new_password);
+
+ that.close();
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'set_password',
+ label: IPA.messages.objects.host.password_set_button,
+ click: function() {
+ that.on_confirm();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+ };
+
+ that.set_otp = function(password) {
+ var pkey = that.entity.get_primary_key();
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: 'mod',
+ args: pkey,
+ options: {
+ all: true,
+ rights: true,
+ userpassword: password
+ },
+ on_success: function(data) {
+ that.facet.load(data);
+ that.close();
+ IPA.notify_success(IPA.messages.objects.host.password_set_success);
+ },
+ on_error: function() {
+ that.close();
+ }
+ });
+
+ command.execute();
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.host.set_otp_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'set_otp';
+ spec.label = spec.label || IPA.messages.objects.host.password_set_title;
+ spec.enable_cond = spec.enable_cond || ['userpassword_w'];
+
+ var that = IPA.action(spec);
+ that.status = spec.status || 'missing';
+
+ that.execute_action = function(facet) {
+
+ var dialog = IPA.host.set_otp_dialog({
+ entity: facet.entity,
+ facet: facet
+ });
+
+ dialog.set_status(that.status);
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.host.userpassword_acl_evaluator = function(spec) {
+
+ spec.name = spec.name || 'userpassword_acl_evaluator';
+ spec.attribute = spec.attribute || 'userpassword';
+
+ var that = IPA.acl_state_evaluator(spec);
+ return that;
+};
+
+IPA.host.has_password_evaluator = function(spec) {
+
+ spec.name = spec.name || 'has_password_evaluator';
+ spec.attribute = spec.attribute || 'has_password';
+ spec.value = spec.value || [true];
+ spec.representation = spec.representation || 'has_password';
+
+ var that = IPA.value_state_evaluator(spec);
+ return that;
+};
+
+IPA.host.certificate_policy = function(spec) {
+
+ spec = spec || {};
+
+ spec.get_pkey = spec.get_pkey || function(result) {
+ var values = result.fqdn;
+ return values ? values[0] : null;
+ };
+
+ spec.get_name = spec.get_name || function(result) {
+ var values = result.fqdn;
+ return values ? values[0] : null;
+ };
+
+ spec.get_principal = spec.get_principal || function(result) {
+ var values = result.krbprincipalname;
+ return values ? values[0] : null;
+ };
+
+ spec.get_hostname = spec.get_hostname || spec.get_name;
+
+ var that = IPA.cert.load_policy(spec);
+ return that;
+};
+
+IPA.register('host', IPA.host.entity);
diff --git a/install/ui/src/freeipa/hostgroup.js b/install/ui/src/freeipa/hostgroup.js
new file mode 100644
index 000000000..20e7179fb
--- /dev/null
+++ b/install/ui/src/freeipa/hostgroup.js
@@ -0,0 +1,90 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.hostgroup = {};
+
+IPA.hostgroup.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'identity',
+ label: IPA.messages.objects.hostgroup.identity,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'memberof_hostgroup',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_netgroup',
+ associator: IPA.serial_associator
+ }).
+ association_facet({
+ name: 'memberof_hbacrule',
+ associator: IPA.serial_associator,
+ add_method: 'add_host',
+ remove_method: 'remove_host'
+ }).
+ association_facet({
+ name: 'memberof_sudorule',
+ associator: IPA.serial_associator,
+ add_method: 'add_host',
+ remove_method: 'remove_host'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.register('hostgroup', IPA.hostgroup.entity);
diff --git a/install/ui/src/freeipa/idrange.js b/install/ui/src/freeipa/idrange.js
new file mode 100644
index 000000000..b2ce3169f
--- /dev/null
+++ b/install/ui/src/freeipa/idrange.js
@@ -0,0 +1,162 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.idrange = {};
+
+IPA.idrange.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'ipabaseid',
+ 'ipaidrangesize',
+ 'iparangetype'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'details',
+ fields: [
+ 'cn',
+ 'iparangetype',
+ {
+ name: 'ipabaseid',
+ label: IPA.messages.objects.idrange.ipabaseid,
+ tooltip: IPA.get_entity_param('idrange', 'ipabaseid').label
+ },
+ {
+ name: 'ipaidrangesize',
+ label: IPA.messages.objects.idrange.ipaidrangesize,
+ tooltip: IPA.get_entity_param('idrange', 'ipaidrangesize').label
+ },
+ {
+ name: 'ipabaserid',
+ label: IPA.messages.objects.idrange.ipabaserid,
+ tooltip: IPA.get_entity_param('idrange', 'ipabaserid').label
+ },
+ {
+ name: 'ipasecondarybaserid',
+ label: IPA.messages.objects.idrange.ipasecondarybaserid,
+ tooltip: IPA.get_entity_param('idrange', 'ipasecondarybaserid').label
+ },
+ {
+ name: 'ipanttrusteddomainsid',
+ label: IPA.messages.objects.idrange.ipanttrusteddomainsid,
+ tooltip: IPA.get_entity_param('idrange', 'ipanttrusteddomainsid').label
+ }
+ ]
+ }
+ ]
+ }).
+ adder_dialog({
+ fields: [
+ {
+ name: 'cn',
+ widget: 'idrange.cn'
+ },
+ {
+ name: 'ipabaseid',
+ label: IPA.messages.objects.idrange.ipabaseid,
+ tooltip: IPA.get_entity_param('idrange', 'ipabaseid').label,
+ widget: 'idrange.ipabaseid'
+ },
+ {
+ name: 'ipaidrangesize',
+ label: IPA.messages.objects.idrange.ipaidrangesize,
+ tooltip: IPA.get_entity_param('idrange', 'ipaidrangesize').label,
+ widget: 'idrange.ipaidrangesize'
+ },
+ {
+ name: 'ipabaserid',
+ label: IPA.messages.objects.idrange.ipabaserid,
+ tooltip: IPA.get_entity_param('idrange', 'ipabaserid').label,
+ widget: 'idrange.ipabaserid'
+ },
+ {
+ name: 'ipasecondarybaserid',
+ label: IPA.messages.objects.idrange.ipasecondarybaserid,
+ tooltip: IPA.get_entity_param('idrange', 'ipasecondarybaserid').label,
+ widget: 'type.ipasecondarybaserid'
+ },
+ {
+ name: 'ipanttrusteddomainsid',
+ label: IPA.messages.objects.idrange.ipanttrusteddomainsid,
+ tooltip: IPA.get_entity_param('idrange', 'ipanttrusteddomainsid').label,
+ widget: 'type.ipanttrusteddomainsid'
+ }
+ ],
+ widgets: [
+ {
+ type: 'details_table_section_nc',
+ name: 'idrange',
+ widgets: [
+ 'cn',
+ 'ipabaseid',
+ 'ipaidrangesize',
+ 'ipabaserid'
+ ]
+ },
+ {
+ type: 'multiple_choice_section',
+ name: 'type',
+ label: IPA.messages.objects.idrange.type,
+ choices: [
+ {
+ name: 'local',
+ label: IPA.messages.objects.idrange.type_local,
+ fields: ['ipasecondarybaserid'],
+ required: ['ipasecondarybaserid'],
+ enabled: true
+ },
+ {
+ name: 'ad',
+ label: IPA.messages.objects.idrange.type_ad,
+ fields: ['ipanttrusteddomainsid'],
+ required: ['ipanttrusteddomainsid']
+ }
+ ],
+ widgets: [
+ 'ipasecondarybaserid',
+ 'ipanttrusteddomainsid'
+ ]
+ }
+ ],
+ policies: [
+ IPA.multiple_choice_section_policy({
+ widget: 'type'
+ })
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.register('idrange', IPA.idrange.entity);
diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js
new file mode 100644
index 000000000..cc62f0897
--- /dev/null
+++ b/install/ui/src/freeipa/ipa.js
@@ -0,0 +1,2122 @@
+/*jsl:import jquery.ordered-map.js */
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Endi Dewata <edewata@redhat.com>
+ * John Dennis <jdennis@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+/* REQUIRES: jquery.ordered-map.js */
+/*global $:true, location:true */
+
+var IPA = function() {
+
+ var that = {
+ jsonrpc_id: 0
+ };
+
+ // live server path
+ that.url = '/ipa/ui/';
+
+ that.ajax_options = {
+ type: 'POST',
+ contentType: 'application/json',
+ dataType: 'json',
+ async: true,
+ processData: false
+ };
+
+ that.metadata = {};
+ that.messages = {};
+ that.whoami = {};
+
+ that.entities = $.ordered_map();
+ that.entity_factories = {};
+ that.field_factories = {};
+ that.widget_factories = {};
+
+ that.network_call_count = 0;
+
+ that.ui = {};
+
+ /* initialize the IPA JSON-RPC helper */
+ that.init = function(params) {
+
+ // if current path matches live server path, use live data
+ if (that.url && window.location.pathname.substring(0, that.url.length) === that.url) {
+ that.json_url = params.url || '/ipa/session/json';
+ that.login_url = params.url || '/ipa/session/login_kerberos';
+
+ } else { // otherwise use fixtures
+ that.json_path = params.url || "test/data";
+ // that.login_url is not needed for fixtures
+ }
+
+ $.ajaxSetup(that.ajax_options);
+
+ var batch = IPA.batch_command({
+ name: 'ipa_init',
+ retry: false,
+ on_success: function() {
+ that.init_metadata({
+ on_success: params.on_success,
+ on_error: params.on_error
+ });
+ },
+ on_error: function(xhr, text_status, error_thrown) {
+
+ // On IE the request is missing after authentication,
+ // so the request needs to be resent.
+ if (error_thrown.code === 909) {
+ batch.execute();
+
+ } else {
+ var ajax = this;
+
+ var dialog = IPA.error_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: error_thrown,
+ command: batch
+ });
+
+ dialog.on_cancel = function() {
+ dialog.close();
+ if (params.on_error) {
+ params.on_error.call(ajax, xhr, text_status, error_thrown);
+ }
+ };
+
+ dialog.open();
+ }
+ }
+ });
+
+ batch.add_command(IPA.command({
+ method: 'i18n_messages',
+ on_success: function(data, text_status, xhr) {
+ that.messages = data.messages;
+ }
+ }));
+
+ batch.add_command(IPA.command({
+ entity: 'config',
+ method: 'show',
+ on_success: function(data, text_status, xhr) {
+ that.server_config = data.result;
+ }
+ }));
+
+ batch.add_command(that.get_whoami_command(true));
+
+ batch.add_command(IPA.command({
+ method: 'env',
+ on_success: function(data, text_status, xhr) {
+ that.env = data.result;
+ that.version = that.env.version;
+ }
+ }));
+
+ batch.add_command(IPA.command({
+ entity: 'dns',
+ method: 'is_enabled',
+ on_success: function(data, text_status, xhr) {
+ that.dns_enabled = data.result;
+ }
+ }));
+
+
+
+ batch.execute();
+ };
+
+ that.get_whoami_command = function(batch) {
+ return IPA.command({
+ entity: 'user',
+ method: 'find',
+ options: {
+ whoami: true,
+ all: true
+ },
+ on_success: function(data, text_status, xhr) {
+ that.whoami = batch ? data.result[0] : data.result.result[0];
+ that.principal = that.whoami.krbprincipalname[0];
+ }
+ });
+ };
+
+ that.init_metadata = function(params) {
+
+ var objects = IPA.command({
+ name: 'ipa_init_objects',
+ method: 'json_metadata',
+ options: {
+ object: 'all'
+ },
+ on_success: function(data, text_status, xhr) {
+ that.metadata.objects = data.result.objects;
+ }
+ });
+
+ var commands = IPA.command({
+ name: 'ipa_init_commands',
+ method: 'json_metadata',
+ options: {
+ command: 'all'
+ },
+ on_success: function(data, text_status, xhr) {
+ that.metadata.commands = data.result.commands;
+ }
+ });
+
+ var metadata_command = IPA.concurrent_command({
+ commands: [
+ objects,
+ commands
+ ],
+ on_success: function(data, text_status, xhr) {
+ IPA.ui.initialized = true;
+ if (params.on_success) {
+ params.on_success.call(this, data, text_status, xhr);
+ }
+ },
+ on_error: params.on_error
+ });
+
+ metadata_command.execute();
+ };
+
+ that.register = function(name, factory) {
+ that.remove_entity(name);
+ that.entity_factories[name] = factory;
+ };
+
+ that.create_entity = function(name) {
+ var factory = that.entity_factories[name];
+ if (!factory) return null;
+
+ try {
+ var builder = IPA.entity_builder();
+
+ builder.entity({
+ factory: factory,
+ name: name
+ });
+
+ var entity = builder.build();
+ entity.init();
+
+ return entity;
+
+ } catch (e) {
+ if (e.expected) {
+ /*expected exceptions thrown by builder just mean that
+ entities are not to be registered. */
+ return null;
+ }
+
+ if (e.message) {
+ alert(e.message);
+ } else {
+ alert(e);
+ }
+
+ return null;
+ }
+ };
+
+ that.get_entities = function() {
+ return that.entities.values;
+ };
+
+ that.get_entity = function(name) {
+ if (typeof name === 'object') return name;
+ var entity = that.entities.get(name);
+ if (!entity) {
+ entity = that.create_entity(name);
+ if (entity) that.add_entity(entity);
+ }
+ return entity;
+ };
+
+ that.add_entity = function(entity) {
+ that.entities.put(entity.name, entity);
+ };
+
+ that.remove_entity = function(name) {
+ that.entities.remove(name);
+ };
+
+ that.display_activity_icon = function() {
+ that.network_call_count++;
+ $('.network-activity-indicator').css('visibility', 'visible');
+ };
+
+ that.hide_activity_icon = function() {
+ that.network_call_count--;
+
+ if (0 === that.network_call_count) {
+ $('.network-activity-indicator').css('visibility', 'hidden');
+ }
+ };
+
+ that.get_message = function(id, default_message) {
+ var messages = IPA.messages;
+ var keys = id.split(/\./);
+
+ for (var i=0; messages && i<keys.length; i++) {
+ var key = keys[i];
+ var value = messages[key];
+
+ // undefined key => not found
+ if (!value) return default_message;
+
+ // if value is string
+ if (typeof value === 'string') {
+
+ // and it's the last key => found
+ if (i === keys.length-1) return value;
+
+ // otherwise value should have been a container => not found
+ return default_message;
+ }
+
+ // value is container => check next key
+ messages = value;
+ }
+
+ // no more keys/messages => not found
+ return default_message;
+ };
+
+ return that;
+}();
+
+IPA.get_credentials = function() {
+ var status;
+
+ function error_handler(xhr, text_status, error_thrown) {
+ status = xhr.status;
+ IPA.ui.logged_kerberos = false;
+ }
+
+ function success_handler(data, text_status, xhr) {
+ status = xhr.status;
+ IPA.ui.logged_kerberos = true;
+ }
+
+ var request = {
+ url: IPA.login_url,
+ cache: false,
+ async: false,
+ type: "GET",
+ success: success_handler,
+ error: error_handler
+ };
+
+ $.ajax(request);
+
+ return status;
+};
+
+IPA.logout = function() {
+
+ function show_error(message) {
+ var dialog = IPA.message_dialog({
+ name: 'logout_error',
+ message: message,
+ title: IPA.messages.login.logout_error
+ });
+ dialog.open();
+ }
+
+ function redirect () {
+ window.location = 'logout.html';
+ }
+
+ function success_handler(data, text_status, xhr) {
+ if (data && data.error) {
+ show_error(data.error.message);
+ } else {
+ redirect();
+ }
+ }
+
+ function error_handler(xhr, text_status, error_thrown) {
+ if (xhr.status === 401) {
+ redirect();
+ } else {
+ show_error(text_status);
+ }
+ }
+
+ var command = {
+ method: 'session_logout',
+ params: [[], {}]
+ };
+
+ var request = {
+ url: IPA.json_url || IPA.json_path + '/session_logout.json',
+ data: JSON.stringify(command),
+ success: success_handler,
+ error: error_handler
+ };
+
+ $.ajax(request);
+};
+
+IPA.login_password = function(username, password) {
+
+ var result = 'invalid';
+
+ function success_handler(data, text_status, xhr) {
+ result = 'success';
+ IPA.ui.logged_password = true;
+ }
+
+ function error_handler(xhr, text_status, error_thrown) {
+
+ if (xhr.status === 401) {
+ var reason = xhr.getResponseHeader("X-IPA-Rejection-Reason");
+
+ //change result from invalid only if we have a header which we
+ //understand
+ if (reason === 'password-expired' || reason === 'denied') {
+ result = reason;
+ }
+ }
+
+ IPA.ui.logged_password = false;
+ }
+
+ var data = {
+ user: username,
+ password: password
+ };
+
+ var request = {
+ url: '/ipa/session/login_password',
+ data: data,
+ contentType: 'application/x-www-form-urlencoded',
+ processData: true,
+ dataType: 'html',
+ async: false,
+ type: 'POST',
+ success: success_handler,
+ error: error_handler
+ };
+
+ IPA.display_activity_icon();
+ $.ajax(request);
+ IPA.hide_activity_icon();
+
+ return result;
+};
+
+IPA.reset_password = function(username, old_password, new_password) {
+
+ //possible results: 'ok', 'invalid-password', 'policy-error'
+
+ var status, result, reason, invalid, failure, data, request;
+
+ status = 'invalid';
+ result = {
+ status: status,
+ message: IPA.get_message('password.reset_failure',
+ "Password reset was not successful.")
+ };
+
+ function success_handler(data, text_status, xhr) {
+
+ result.status = xhr.getResponseHeader("X-IPA-Pwchange-Result") || status;
+
+ if (result.status === 'policy-error') {
+ result.message = xhr.getResponseHeader("X-IPA-Pwchange-Policy-Error");
+ } else if (result.status === 'invalid-password') {
+ result.message = IPA.get_message('password.invalid_password',
+ "The password or username you entered is incorrect.");
+ }
+
+ return result;
+ }
+
+ function error_handler(xhr, text_status, error_thrown) {
+ return result;
+ }
+
+ data = {
+ user: username,
+ old_password: old_password,
+ new_password: new_password
+ };
+
+ request = {
+ url: '/ipa/session/change_password',
+ data: data,
+ contentType: 'application/x-www-form-urlencoded',
+ processData: true,
+ dataType: 'html',
+ async: false,
+ type: 'POST',
+ success: success_handler,
+ error: error_handler
+ };
+
+ IPA.display_activity_icon();
+ $.ajax(request);
+ IPA.hide_activity_icon();
+
+ return result;
+};
+
+IPA.update_password_expiration = function() {
+
+ var now, expires, notify_days, diff, message, container;
+
+ expires = IPA.whoami.krbpasswordexpiration;
+ expires = expires ? IPA.parse_utc_date(expires[0]) : null;
+
+ notify_days = IPA.server_config.ipapwdexpadvnotify;
+ notify_days = notify_days ? notify_days[0] : 0;
+
+ now = new Date();
+
+ container = $('.header-passwordexpires');
+ container.empty();
+
+ if (expires) {
+
+ diff = expires.getTime() - now.getTime();
+ diff = Math.floor(diff / 86400000);
+
+ if (diff <= notify_days) {
+ message = IPA.messages.password.expires_in;
+ message = message.replace('${days}', diff);
+ container.append(message + ' ');
+ $('<a/>', {
+ href: '#reset-password',
+ click: function() {
+ IPA.password_selfservice();
+ return false;
+ },
+ text: IPA.messages.password.reset_password_sentence,
+ title: IPA.messages.password.reset_password
+ }).appendTo(container);
+ }
+ }
+};
+
+IPA.password_selfservice = function() {
+ var reset_dialog = IPA.user_password_dialog({
+ self_service: true,
+ on_success: function() {
+ var command = IPA.get_whoami_command();
+ var orig_on_success = command.on_success;
+ command.on_success = function(data, text_status, xhr) {
+ orig_on_success.call(this, data, text_status, xhr);
+ IPA.update_password_expiration();
+ };
+ command.execute();
+
+ alert(IPA.messages.password.password_change_complete);
+ reset_dialog.close();
+ }
+ });
+ reset_dialog.open();
+};
+
+IPA.parse_utc_date = function(value) {
+
+ if (!value) return null;
+
+ // verify length
+ if (value.length != 'YYYYmmddHHMMSSZ'.length) {
+ return null;
+ }
+
+ // We only handle GMT
+ if (value.charAt(value.length -1) !== 'Z') {
+ return null;
+ }
+
+ var date = new Date();
+
+ date.setUTCFullYear(
+ value.substring(0, 4), // YYYY
+ value.substring(4, 6)-1, // mm (0-11)
+ value.substring(6, 8)); // dd (1-31)
+
+ date.setUTCHours(
+ value.substring(8, 10), // HH (0-23)
+ value.substring(10, 12), // MM (0-59)
+ value.substring(12, 14)); // SS (0-59)
+
+ return date;
+};
+
+/**
+ * Call an IPA command over JSON-RPC.
+ *
+ * Arguments:
+ * name - command name (optional)
+ * entity - command entity (optional)
+ * method - command method
+ * args - list of arguments, e.g. [username]
+ * options - dict of options, e.g. {givenname: 'Pavel'}
+ * on_success - callback function if command succeeds
+ * on_error - callback function if command fails
+ */
+IPA.command = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+
+ that.entity = spec.entity;
+ that.method = spec.method;
+
+ that.args = $.merge([], spec.args || []);
+ that.options = $.extend({}, spec.options || {});
+
+ that.on_success = spec.on_success;
+ that.on_error = spec.on_error;
+
+ that.retry = typeof spec.retry == 'undefined' ? true : spec.retry;
+
+ that.error_message = spec.error_message || IPA.get_message('dialogs.batch_error_message', 'Some operations failed.');
+ that.error_messages = $.ordered_map({
+ 911: 'Missing HTTP referer. <br/> You have to configure your browser to send HTTP referer header.'
+ });
+
+ that.get_command = function() {
+ return (that.entity ? that.entity+'_' : '') + that.method;
+ };
+
+ that.add_arg = function(arg) {
+ that.args.push(arg);
+ };
+
+ that.add_args = function(args) {
+ $.merge(that.args, args);
+ };
+
+ that.set_option = function(name, value) {
+ that.options[name] = value;
+ };
+
+ that.set_options = function(options) {
+ $.extend(that.options, options);
+ };
+
+ that.add_option = function(name, value) {
+ var values = that.options[name];
+ if (!values) {
+ values = [];
+ that.options[name] = values;
+ }
+ values.push(value);
+ };
+
+ that.get_option = function(name) {
+ return that.options[name];
+ };
+
+ that.remove_option = function(name) {
+ delete that.options[name];
+ };
+
+ that.execute = function() {
+
+ function dialog_open(xhr, text_status, error_thrown) {
+
+ var ajax = this;
+
+ var dialog = IPA.error_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: error_thrown,
+ command: that
+ });
+
+ dialog.on_cancel = function() {
+ dialog.close();
+ if (that.on_error) {
+ that.on_error.call(ajax, xhr, text_status, error_thrown);
+ }
+ };
+
+ dialog.open();
+ }
+
+ function auth_dialog_open(xhr, text_status, error_thrown) {
+
+ var ajax = this;
+
+ var dialog = IPA.unauthorized_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: error_thrown,
+ close_on_escape: false,
+ command: that
+ });
+
+ dialog.open();
+ }
+
+ /*
+ * Special error handler used the first time this command is
+ * submitted. It checks to see if the session credentials need
+ * to be acquired and if so sends a request to a special url
+ * to establish the sesion credentials. If acquiring the
+ * session credentials is successful it simply resubmits the
+ * exact same command after setting the error handler back to
+ * the normal error handler. If aquiring the session
+ * credentials fails the normal error handler is invoked to
+ * process the error returned from the attempt to aquire the
+ * session credentials.
+ */
+ function error_handler_login(xhr, text_status, error_thrown) {
+ if (xhr.status === 401) {
+ var login_status = IPA.get_credentials();
+
+ if (login_status === 200) {
+ that.request.error = error_handler;
+ $.ajax(that.request);
+ return;
+ }
+ }
+ // error_handler() calls IPA.hide_activity_icon()
+ error_handler.call(this, xhr, text_status, error_thrown);
+ }
+
+ /*
+ * Normal error handler, handles all errors.
+ * error_handler_login() is initially used to trap the
+ * special case need to aquire session credentials, this is
+ * not a true error, rather it's an indication an extra step
+ * needs to be taken before normal processing can continue.
+ */
+ function error_handler(xhr, text_status, error_thrown) {
+
+ IPA.hide_activity_icon();
+
+ if (xhr.status === 401) {
+ auth_dialog_open(xhr, text_status, error_thrown);
+ return;
+ } else if (!error_thrown) {
+ error_thrown = {
+ name: xhr.responseText || IPA.get_message('errors.unknown_error', 'Unknown Error'),
+ message: xhr.statusText || IPA.get_message('errors.unknown_error', 'Unknown Error')
+ };
+
+ } else if (typeof error_thrown == 'string') {
+ error_thrown = {
+ name: error_thrown,
+ message: error_thrown
+ };
+ }
+
+ // custom messages for set of codes
+ var error_msg = that.error_messages.get(error_thrown.code);
+ if (error_msg) {
+ error_msg = error_msg.replace('${message}', error_thrown.message);
+ error_thrown.message = error_msg;
+ }
+
+ // global specical cases error handlers section
+
+ // With trusts, user from trusted domain can use his ticket but he
+ // doesn't have rights for LDAP modify. It will throw internal errror.
+ // We should offer form base login.
+ if (xhr.status === 500 && IPA.ui.logged_kerberos && !IPA.ui.initialized) {
+ auth_dialog_open(xhr, text_status, error_thrown);
+ return;
+ }
+
+ if (that.retry) {
+ dialog_open.call(this, xhr, text_status, error_thrown);
+
+ } else if (that.on_error) {
+ //custom error handling, maintaining AJAX call's context
+ that.on_error.call(this, xhr, text_status, error_thrown);
+ }
+ }
+
+ function success_handler(data, text_status, xhr) {
+
+ if (!data) {
+ // error_handler() calls IPA.hide_activity_icon()
+ error_handler.call(this, xhr, text_status, /* error_thrown */ {
+ name: IPA.get_message('errors.http_error', 'HTTP Error')+' '+xhr.status,
+ url: this.url,
+ message: data ? xhr.statusText : IPA.get_message('errors.no_response', 'No response')
+ });
+
+ } else if (IPA.version && data.version && IPA.version !== data.version) {
+ window.location.reload();
+
+ } else if (IPA.principal && data.principal && IPA.principal !== data.principal) {
+ window.location.reload();
+
+ } else if (data.error) {
+ // error_handler() calls IPA.hide_activity_icon()
+ error_handler.call(this, xhr, text_status, /* error_thrown */ {
+ name: IPA.get_message('errors.ipa_error', 'IPA Error')+' '+data.error.code,
+ code: data.error.code,
+ message: data.error.message,
+ data: data
+ });
+
+ } else {
+ IPA.hide_activity_icon();
+
+ var ajax = this;
+ var failed = that.get_failed(that, data.result, text_status, xhr);
+ if (!failed.is_empty()) {
+ var dialog = IPA.error_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: {
+ name: IPA.get_message('dialogs.batch_error_title', 'Operations Error'),
+ message: that.error_message
+ },
+ command: that,
+ errors: failed.errors,
+ visible_buttons: ['ok']
+ });
+
+ dialog.on_ok = function() {
+ dialog.close();
+ if (that.on_success) that.on_success.call(ajax, data, text_status, xhr);
+ };
+
+ dialog.open();
+
+ } else {
+ //custom success handling, maintaining AJAX call's context
+ if (that.on_success) that.on_success.call(this, data, text_status, xhr);
+ }
+ }
+ }
+
+ that.data = {
+ method: that.get_command(),
+ params: [that.args, that.options]
+ };
+
+ that.request = {
+ url: IPA.json_url || IPA.json_path + '/' + (that.name || that.data.method) + '.json',
+ data: JSON.stringify(that.data),
+ success: success_handler,
+ error: error_handler_login
+ };
+
+ IPA.display_activity_icon();
+ $.ajax(that.request);
+ };
+
+ that.get_failed = function(command, result, text_status, xhr) {
+ var errors = IPA.error_list();
+ if(result && result.failed) {
+ for(var association in result.failed) {
+ for(var member_name in result.failed[association]) {
+ var member = result.failed[association][member_name];
+ for(var i = 0; i < member.length; i++) {
+ if(member[i].length > 1) {
+ var name = IPA.get_message('errors.ipa_error', 'IPA Error');
+ var message = member[i][1];
+ if(member[i][0])
+ message = member[i][0] + ': ' + message;
+ errors.add(command, name, message, text_status);
+ }
+ }
+ }
+ }
+ }
+ return errors;
+ };
+
+ that.check_option = function(option_name) {
+
+ var metadata = IPA.get_command_option(that.get_command(), option_name);
+ return metadata !== null;
+ };
+
+ that.to_json = function() {
+ var json = {};
+
+ json.method = that.get_command();
+
+ json.params = [];
+ json.params[0] = that.args || [];
+ json.params[1] = that.options || {};
+
+ return json;
+ };
+
+ that.to_string = function() {
+ var string = that.get_command().replace(/_/g, '-');
+
+ for (var i=0; i<that.args.length; i++) {
+ string += ' '+that.args[i];
+ }
+
+ for (var name in that.options) {
+ string += ' --'+name+'=\''+that.options[name]+'\'';
+ }
+
+ return string;
+ };
+
+ return that;
+};
+
+IPA.batch_command = function (spec) {
+
+ spec = spec || {};
+
+ spec.method = 'batch';
+
+ var that = IPA.command(spec);
+
+ that.commands = [];
+ that.errors = IPA.error_list();
+ that.show_error = typeof spec.show_error == 'undefined' ?
+ true : spec.show_error;
+
+ that.add_command = function(command) {
+ that.commands.push(command);
+ that.add_arg(command.to_json());
+ };
+
+ that.add_commands = function(commands) {
+ for (var i=0; i<commands.length; i++) {
+ that.add_command(commands[i]);
+ }
+ };
+
+ that.execute = function() {
+ that.errors.clear();
+
+ var command = IPA.command({
+ name: that.name,
+ entity: that.entity,
+ method: that.method,
+ args: that.args,
+ options: that.options,
+ retry: that.retry
+ });
+
+ command.on_success = that.batch_command_on_success;
+ command.on_error = that.batch_command_on_error;
+
+ command.execute();
+ };
+
+ that.batch_command_on_success = function(data, text_status, xhr) {
+
+ for (var i=0; i<that.commands.length; i++) {
+ var command = that.commands[i];
+ var result = data.result.results[i];
+
+ var name = '';
+ var message = '';
+
+ if (!result) {
+ name = IPA.get_message('errors.internal_error', 'Internal Error')+' '+xhr.status;
+ message = result ? xhr.statusText : IPA.get_message('errors.internal_error', 'Internal Error');
+
+ that.errors.add(command, name, message, text_status);
+
+ if (command.on_error) command.on_error.call(
+ this,
+ xhr,
+ text_status,
+ {
+ name: name,
+ message: message
+ }
+ );
+
+ } else if (result.error) {
+ var code = result.error.code || result.error_code;
+ name = IPA.get_message('errors.ipa_error', 'IPA Error')+(code ? ' '+code : '');
+ message = result.error.message || result.error;
+
+ if (command.retry) that.errors.add(command, name, message, text_status);
+
+ if (command.on_error) command.on_error.call(
+ this,
+ xhr,
+ text_status,
+ {
+ name: name,
+ code: code,
+ message: message,
+ data: result
+ }
+ );
+
+ } else {
+ var failed = that.get_failed(command, result, text_status, xhr);
+ that.errors.add_range(failed);
+
+ if (command.on_success) command.on_success.call(this, result, text_status, xhr);
+ }
+ }
+
+ //check for partial errors and show error dialog
+ if (that.show_error && that.errors.errors.length > 0) {
+ var ajax = this;
+ var dialog = IPA.error_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: {
+ name: IPA.get_message('dialogs.batch_error_title', 'Operations Error'),
+ message: that.error_message
+ },
+ command: that,
+ errors: that.errors.errors,
+ visible_buttons: [ 'ok' ]
+ });
+
+ dialog.on_ok = function() {
+ dialog.close();
+ if (that.on_success) that.on_success.call(ajax, data, text_status, xhr);
+ };
+
+ dialog.open();
+
+ } else {
+ if (that.on_success) that.on_success.call(this, data, text_status, xhr);
+ }
+ };
+
+ that.batch_command_on_error = function(xhr, text_status, error_thrown) {
+ // TODO: undefined behavior
+ if (that.on_error) {
+ that.on_error.call(this, xhr, text_status, error_thrown);
+ }
+ };
+
+ return that;
+};
+
+
+IPA.concurrent_command = function(spec) {
+
+ spec = spec || {};
+ var that = {};
+
+ that.commands = [];
+ that.on_success = spec.on_success;
+ that.on_error = spec.on_error;
+
+ that.add_commands = function(commands) {
+
+ if(commands && commands.length) {
+ for(var i=0; i < commands.length; i++) {
+ that.commands.push({
+ command: commands[i]
+ });
+ }
+ }
+ };
+
+ that.execute = function() {
+
+ var command_info, command, i;
+
+ //prepare for execute
+ for(i=0; i < that.commands.length; i++) {
+ command_info = that.commands[i];
+ command = command_info.command;
+ if(!command) {
+ var dialog = IPA.message_dialog({
+ name: 'internal_error',
+ title: IPA.get_message('errors.error', 'Error'),
+ message: IPA.get_message('errors.internal_error', 'Internal error.')
+ });
+ break;
+ }
+ command_info.completed = false;
+ command_info.success = false;
+ command_info.on_success = command_info.on_success || command.on_success;
+ command_info.on_error = command_info.on_error || command.on_error;
+ command.on_success = function(command_info) {
+ return function(data, text_status, xhr) {
+ that.success_handler.call(this, command_info, data, text_status, xhr);
+ };
+ }(command_info);
+ command.on_error = function(command_info) {
+ return function(xhr, text_status, error_thrown) {
+ that.error_handler.call(this, command_info, xhr, text_status, error_thrown);
+ };
+ }(command_info);
+ }
+
+ //execute
+ for(i=0; i < that.commands.length; i++) {
+ command = that.commands[i].command;
+ command.execute();
+ }
+ };
+
+ that.error_handler = function(command_info, xhr, text_status, error_thrown) {
+
+ command_info.completed = true;
+ command_info.success = false;
+ command_info.xhr = xhr;
+ command_info.text_status = text_status;
+ command_info.error_thrown = error_thrown;
+ command_info.context = this;
+ that.command_completed();
+ };
+
+ that.success_handler = function(command_info, data, text_status, xhr) {
+
+ command_info.completed = true;
+ command_info.success = true;
+ command_info.data = data;
+ command_info.text_status = text_status;
+ command_info.xhr = xhr;
+ command_info.context = this;
+ that.command_completed();
+ };
+
+ that.command_completed = function() {
+
+ var all_completed = true;
+ var all_success = true;
+
+ for(var i=0; i < that.commands.length; i++) {
+ var command_info = that.commands[i];
+ all_completed = all_completed && command_info.completed;
+ all_success = all_success && command_info.success;
+ }
+
+ if(all_completed) {
+ if(all_success) {
+ that.on_success_all();
+ } else {
+ that.on_error_all();
+ }
+ }
+ };
+
+ that.on_success_all = function() {
+
+ for(var i=0; i < that.commands.length; i++) {
+ var command_info = that.commands[i];
+ if(command_info.on_success) {
+ command_info.on_success.call(
+ command_info.context,
+ command_info.data,
+ command_info.text_status,
+ command_info.xhr);
+ }
+ }
+
+ if(that.on_success) {
+ that.on_success();
+ }
+ };
+
+ that.on_error_all = function() {
+
+ if(that.on_error) {
+ that.on_error();
+
+ } else {
+ var dialog = IPA.message_dialog({
+ name: 'operation_error',
+ title: IPA.get_message('dialogs.batch_error_title', 'Operations Error'),
+ message: IPA.get_message('dialogs.batch_error_message', 'Some operations failed.')
+ });
+
+ dialog.open();
+ }
+ };
+
+ that.add_commands(spec.commands);
+
+ return that;
+};
+
+IPA.builder = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.factory = spec.factory || IPA.default_factory;
+
+ that.build = function(spec) {
+
+ var factory = spec.factory || that.factory;
+
+ //when spec is a factory function
+ if (!spec.factory && typeof spec === 'function') {
+ factory = spec;
+ spec = {};
+ }
+
+ var obj = factory(spec);
+ return obj;
+ };
+
+ that.build_objects = function(specs) {
+
+ var objects = [];
+
+ for (var i=0; i<specs.length; i++) {
+ var spec = specs[i];
+ var obj = that.build(spec);
+ objects.push(obj);
+ }
+
+ return objects;
+ };
+
+ return that;
+};
+
+IPA.build = function(spec, builder_fac) {
+
+ if (!spec) return null;
+
+ if (!builder_fac) builder_fac = IPA.builder;
+
+ var builder = builder_fac();
+ var product;
+
+ if ($.isArray(spec)) {
+ product = builder.build_objects(spec);
+ } else {
+ product = builder.build(spec);
+ }
+
+ return product;
+};
+
+IPA.build_default = function(spec, def_spec) {
+
+ var builder, factory, default_object;
+
+ if (!spec && !def_spec) return null;
+
+ if (typeof def_spec === 'function') { //factory function
+ factory = def_spec;
+ } else if (typeof def_spec === 'object') {
+ default_object = def_spec;
+ }
+
+ builder = IPA.builder({
+ factory: factory
+ });
+
+ var product;
+ spec = spec || default_object || {};
+
+ if ($.isArray(spec)) {
+ product = builder.build_objects(spec);
+ } else {
+ product = builder.build(spec);
+ }
+
+ return product;
+};
+
+IPA.default_factory = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ $.extend(that, spec);
+
+ return that;
+};
+
+/* helper function used to retrieve information about an attribute */
+IPA.get_entity_param = function(entity_name, name) {
+
+ var metadata = IPA.metadata.objects[entity_name];
+ if (!metadata) {
+ return null;
+ }
+
+ var params = metadata.takes_params;
+ if (!params) {
+ return null;
+ }
+
+ for (var i=0; i<params.length; i++) {
+ if (params[i].name === name) {
+ return params[i];
+ }
+ }
+
+ return null;
+};
+
+IPA.get_command_arg = function(command_name, arg_name) {
+
+ var metadata = IPA.metadata.commands[command_name];
+ if (!metadata) {
+ return null;
+ }
+
+ var args = metadata.takes_args;
+ if (!args) {
+ return null;
+ }
+
+ for (var i=0; i<args.length; i++) {
+ if (args[i].name === arg_name) {
+ return args[i];
+ }
+ }
+
+ return null;
+};
+
+IPA.get_command_option = function(command_name, option_name) {
+
+ var metadata = IPA.metadata.commands[command_name];
+ if (!metadata) {
+ return null;
+ }
+
+ var options = metadata.takes_options;
+ if (!options) {
+ return null;
+ }
+
+ for (var i=0; i<options.length; i++) {
+ if (options[i].name === option_name) {
+ return options[i];
+ }
+ }
+
+ return null;
+};
+
+/* helper function used to retrieve attr name with members of type `member` */
+IPA.get_member_attribute = function(obj_name, member) {
+
+ var obj = IPA.metadata.objects[obj_name];
+ if (!obj) {
+ return null;
+ }
+
+ var attribute_members = obj.attribute_members;
+ for (var a in attribute_members) {
+ var objs = attribute_members[a];
+ for (var i = 0; i < objs.length; i += 1) {
+ if (objs[i] === member){
+ return a;
+ }
+ }
+ }
+
+ return null;
+};
+
+IPA.create_network_spinner = function(){
+ var span = $('<span/>', {
+ 'class': 'network-activity-indicator'
+ });
+ $('<img/>', {
+ src: 'images/spinner-small.gif'
+ }).appendTo(span);
+ return span;
+};
+
+IPA.dirty_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.title = spec.title || IPA.messages.dialogs.dirty_title;
+ spec.width = spec.width || '25em';
+
+ var that = IPA.dialog(spec);
+ that.facet = spec.facet;
+ that.message = spec.message || IPA.messages.dialogs.dirty_message;
+
+ that.create = function() {
+ that.container.append(that.message);
+ };
+
+ that.create_button({
+ name: 'update',
+ label: IPA.messages.buttons.update,
+ click: function() {
+ that.facet.update(function() {
+ that.close();
+ that.callback();
+ });
+ }
+ });
+
+ that.create_button({
+ name: 'reset',
+ label: IPA.messages.buttons.reset,
+ click: function() {
+ that.facet.reset();
+ that.close();
+ that.callback();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+
+ that.callback = function() {
+ };
+
+ return that;
+};
+
+IPA.error_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.id = spec.id || 'error_dialog';
+ spec.title = spec.error_thrown.name;
+
+ var that = IPA.dialog(spec);
+
+ IPA.confirm_mixin().apply(that);
+
+ that.xhr = spec.xhr || {};
+ that.text_status = spec.text_status || '';
+ that.error_thrown = spec.error_thrown || {};
+ that.command = spec.command;
+ that.errors = spec.errors;
+ that.visible_buttons = spec.visible_buttons || ['retry', 'cancel'];
+
+
+ that.beautify_message = function(container, message) {
+ var lines = message.split(/\n/g);
+ var line_span;
+ for(var i=0; i<lines.length; i++) {
+ // multi-lined text may contain TAB character as first char of the line
+ // to hint at marking the whole line differently
+ if (lines[i].charAt(0) == '\t') {
+ line_span = $('<p />', {
+ 'class': 'error-message-hinted',
+ text: lines[i].substr(1)
+ }).appendTo(container);
+ } else {
+ line_span = $('<p />', {
+ text: lines[i]
+ }).appendTo(container);
+ }
+ }
+ };
+
+ that.create = function() {
+ if (that.error_thrown.url) {
+ $('<p/>', {
+ text: IPA.get_message('errors.url', 'URL')+': '+that.error_thrown.url
+ }).appendTo(that.container);
+ }
+
+ var error_message = $('<div />', {});
+ that.beautify_message(error_message, that.error_thrown.message);
+ error_message.appendTo(that.container);
+
+ if(that.errors && that.errors.length > 0) {
+ //render errors
+ var errors_title_div = $('<div />', {
+ 'class': 'errors_title'
+ }).appendTo(that.container);
+
+ var show_details = $('<a />', {
+ href: '#',
+ title: IPA.messages.dialogs.show_details,
+ text: IPA.messages.dialogs.show_details
+ }).appendTo(errors_title_div);
+
+ var hide_details = $('<a />', {
+ href: '#',
+ title: IPA.messages.dialogs.hide_details,
+ text: IPA.messages.dialogs.hide_details,
+ style : 'display: none'
+ }).appendTo(errors_title_div);
+
+ var errors_container = $('<ul />', {
+ 'class' : 'error-container',
+ style : 'display: none'
+ }).appendTo(that.container);
+
+ for(var i=0; i < that.errors.length; i++) {
+ var error = that.errors[i];
+ if(error.message) {
+ var error_div = $('<li />', {});
+ that.beautify_message(error_div, error.message);
+ error_div.appendTo(errors_container);
+ }
+ }
+
+ show_details.click(function() {
+ errors_container.show();
+ show_details.hide();
+ hide_details.show();
+ return false;
+ });
+
+ hide_details.click(function() {
+ errors_container.hide();
+ hide_details.hide();
+ show_details.show();
+ return false;
+ });
+ }
+ };
+
+ that.create_buttons = function() {
+ /**
+ * When a user initially opens the Web UI without a Kerberos
+ * ticket, the messages including the button labels have not
+ * been loaded yet, so the button labels need default values.
+ */
+
+ var visible = that.visible_buttons.indexOf('retry') > -1;
+ var label = IPA.get_message('buttons.retry', 'Retry');
+ that.create_button({
+ name: 'retry',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_retry();
+ }
+ });
+
+ visible = that.visible_buttons.indexOf('ok') > -1;
+ label = IPA.get_message('buttons.ok', 'OK');
+ that.create_button({
+ name: 'ok',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_ok();
+ }
+ });
+
+ visible = that.visible_buttons.indexOf('cancel') > -1;
+ label = IPA.get_message('buttons.cancel', 'Cancel');
+ that.create_button({
+ name: 'cancel',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_cancel();
+ }
+ });
+ };
+
+ that.on_retry = function() {
+ that.close();
+ that.command.execute();
+ };
+
+ that.on_ok = function() {
+ that.close();
+ };
+
+ that.on_cancel = function() {
+ that.close();
+ };
+
+ that.on_confirm = function() {
+ if (that.visible_buttons.indexOf('retry') > -1) that.on_retry();
+ else that.on_ok();
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.error_list = function() {
+ var that = {};
+
+ that.clear = function() {
+ that.errors = [];
+ };
+
+ that.add = function(command, name, message, status) {
+ that.errors.push({
+ command: command,
+ name: name,
+ message: message,
+ status: status
+ });
+ };
+
+ that.add_range = function(error_list) {
+ that.errors = that.errors.concat(error_list.errors);
+ };
+
+ that.is_empty = function () {
+ return that.errors.length === 0;
+ };
+
+ that.clear();
+ return that;
+};
+
+IPA.create_4304_error_handler = function(adder_dialog) {
+
+ var set_pkey = function(result) {
+
+ var pkey_name = adder_dialog.entity.metadata.primary_key;
+ var args = adder_dialog.command.args;
+ var pkey = args[args.length-1];
+ result[pkey_name] = pkey;
+ };
+
+ return function (xhr, text_status, error_thrown) {
+
+ var ajax = this;
+ var command = adder_dialog.command;
+ var data = error_thrown.data;
+ var dialog = null;
+
+ if (data && data.error && data.error.code === 4304) {
+ dialog = IPA.message_dialog({
+ name: 'error_4304_info',
+ message: data.error.message,
+ title: adder_dialog.title,
+ on_ok: function() {
+ data.result = { result: {} };
+ set_pkey(data.result.result);
+ command.on_success.call(ajax, data, text_status, xhr);
+ }
+ });
+ } else {
+ dialog = IPA.error_dialog({
+ xhr: xhr,
+ text_status: text_status,
+ error_thrown: error_thrown,
+ command: command
+ });
+ }
+
+ dialog.open(adder_dialog.container);
+ };
+};
+
+IPA.unauthorized_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.sections = [
+ {
+ name: 'login',
+ label: 'Login',
+ fields: [
+ {
+ name: 'username',
+ label: IPA.get_message('login.username', "Username")
+ },
+ {
+ name: 'password',
+ type: 'password',
+ label: IPA.get_message('login.password', "Password")
+ }
+ ]
+ },
+ {
+ name: 'reset',
+ label: 'Reset',
+ fields: [
+ {
+ name: 'username_r',
+ read_only: true,
+ label: IPA.get_message('login.username', "Username")
+ },
+ {
+ name: 'new_password',
+ type: 'password',
+ required: true,
+ label: IPA.get_message('password.new_password)', "New Password")
+ },
+ {
+ name: 'verify_password',
+ type: 'password',
+ required: true,
+ label: IPA.get_message('password.verify_password', "Verify Password"),
+ validators: [IPA.same_password_validator({
+ other_field: 'new_password'
+ })]
+ }
+ ]
+ }
+ ];
+
+ spec.visible_buttons = spec.visible_buttons || ['retry'];
+ spec.name = spec.name || 'unauthorized_dialog';
+ spec.id = spec.id || spec.name;
+
+ var that = IPA.error_dialog(spec);
+
+ that.title = spec.title || IPA.get_message('login.login', "Login");
+
+ that.message = spec.message || IPA.get_message('ajax.401.message',
+ "Your session has expired. Please re-login.");
+
+ that.form_auth_msg = spec.form_auth_msg || IPA.get_message('login.form_auth',
+ "To login with username and password, enter them in the fields below then click Login.");
+
+ that.krb_auth_msg = spec.krb_auth_msg || IPA.get_message('login.krb_auth_msg',
+ " To login with Kerberos, please make sure you" +
+ " have valid tickets (obtainable via kinit) and " +
+ "<a href='http://${host}/ipa/config/unauthorized.html'>configured</a>" +
+ " the browser correctly, then click Login. ");
+
+ that.krb_auth_msg = that.krb_auth_msg.replace('${host}', window.location.hostname);
+
+ that.form_auth_failed = "<p><strong>Please re-enter your username or password</strong></p>" +
+ "<p>The password or username you entered is incorrect. " +
+ "Please try again (make sure your caps lock is off).</p>" +
+ "<p>If the problem persists, contact your administrator.</p>";
+
+ that.password_expired = "Your password has expired. Please enter a new password.";
+
+ that.denied = "Sorry you are not allowed to access this service.";
+
+ that.create = function() {
+
+ that.session_expired_form();
+ that.create_reset_form();
+ };
+
+ that.session_expired_form = function() {
+ that.session_form = $('<div\>').appendTo(that.container);
+
+ that.login_error_box = $('<div/>', {
+ 'class': 'error-box',
+ style: 'display:none',
+ html: that.form_auth_failed
+ }).appendTo(that.session_form);
+
+ $('<p/>', {
+ html: that.message
+ }).appendTo(that.session_form);
+
+ $('<p/>', {
+ html: that.krb_auth_msg
+ }).appendTo(that.session_form);
+
+ $('<p/>', {
+ html: that.form_auth_msg
+ }).appendTo(that.session_form);
+
+ $('<div>', {
+ 'class': 'auth-dialog'
+ }).appendTo(that.session_form);
+
+
+ var section = that.widgets.get_widget('login');
+ var div = $('<div/>', {
+ name: 'login',
+ 'class': 'dialog-section'
+ }).appendTo(that.session_form);
+ section.create(div);
+
+ that.username_widget = that.widgets.get_widget('login.username');
+ that.password_widget = that.widgets.get_widget('login.password');
+
+ that.username_widget.value_changed.attach(that.on_username_change);
+ };
+
+ that.create_reset_form = function() {
+
+ that.reset_form = $('<div\>', {
+ style: 'display:none'
+ }).appendTo(that.container);
+
+ that.reset_error_box = $('<div/>', {
+ 'class': 'error-box'
+ }).appendTo(that.reset_form);
+
+ $('<p/>', {
+ html: that.password_expired
+ }).appendTo(that.reset_form);
+
+ var section = that.widgets.get_widget('reset');
+ var div = $('<div/>', {
+ name: 'reset',
+ 'class': 'dialog-section'
+ }).appendTo(that.reset_form);
+ section.create(div);
+
+ that.username_r_widget = that.widgets.get_widget('reset.username_r');
+ that.new_password_widget = that.widgets.get_widget('reset.new_password');
+ that.verify_password_widget = that.widgets.get_widget('reset.verify_password');
+ };
+
+ that.create_buttons = function() {
+
+ that.buttons.empty();
+
+ var visible = that.visible_buttons.indexOf('login') > -1;
+ var label = IPA.get_message('login.login', "Login");
+ that.create_button({
+ name: 'login',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_login();
+ }
+ });
+
+ visible = that.visible_buttons.indexOf('reset') > -1;
+ label = IPA.get_message('buttons.reset_password_and_login', "Reset Password and Login");
+ that.create_button({
+ name: 'reset',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_reset();
+ }
+ });
+
+ visible = that.visible_buttons.indexOf('cancel') > -1;
+ label = IPA.get_message('buttons.cancel', "Cancel");
+ that.create_button({
+ name: 'cancel',
+ label: label,
+ visible: visible,
+ click: function() {
+ that.on_cancel();
+ }
+ });
+ };
+
+ that.open = function() {
+ that.dialog_open();
+ that.show_session_form();
+ that.check_error_reason();
+ };
+
+ that.check_error_reason = function() {
+ if (this.xhr) {
+ var reason = this.xhr.getResponseHeader("X-IPA-Rejection-Reason");
+ if (reason) {
+ that.show_login_error_message(reason);
+ }
+ }
+ };
+
+ that.on_username_change = function() {
+
+ var password_field = that.fields.get_field('password');
+ var user_specified = !IPA.is_empty(that.username_widget.save());
+ password_field.set_required(user_specified);
+ if (!user_specified) that.password_widget.clear();
+ };
+
+ that.enable_fields = function(field_names) {
+
+ var field, fields, i, enable;
+ fields = that.fields.get_fields();
+ for (i=0; i<fields.length; i++) {
+ field = fields[i];
+ enable = field_names.indexOf(field.name) > -1;
+ field.set_enabled(enable);
+ }
+ };
+
+ that.show_session_form = function() {
+
+ that.current_view = 'session';
+ that.enable_fields(['username', 'password']);
+ that.session_form.css('display', 'block');
+ that.reset_form.css('display', 'none');
+ that.display_buttons(['login']);
+ that.username_widget.focus_input();
+ };
+
+ that.show_reset_form = function() {
+
+ that.current_view = 'reset';
+ that.enable_fields(['new_password', 'verify_password']);
+ that.session_form.css('display', 'none');
+ that.reset_form.css('display', 'block');
+ that.display_buttons(['reset', 'cancel']);
+
+ var username = that.username_widget.save();
+ that.username_r_widget.update(username);
+ that.new_password_widget.focus_input();
+ };
+
+ that.show_login_error_message = function(reason) {
+ var errors = {
+ 'invalid': that.form_auth_failed,
+ 'denied': that.denied
+ };
+
+ var message = errors[reason];
+
+ if (message) {
+ that.login_error_box.html(message);
+ that.login_error_box.css('display', 'block');
+ }
+ };
+
+ that.on_cancel = function() {
+
+ that.username_widget.clear();
+ that.password_widget.clear();
+ that.username_r_widget.clear();
+ that.new_password_widget.clear();
+ that.verify_password_widget.clear();
+
+ that.show_session_form();
+ };
+
+ that.on_login = function() {
+
+ var username = that.username_widget.save();
+ var password = that.password_widget.save();
+
+ //if user doesn't specify username and password try kerberos auth
+ if (IPA.is_empty(username) && IPA.is_empty(password)) {
+ that.on_retry();
+ return;
+ }
+
+ if (!that.validate()) return;
+
+ IPA.display_activity_icon();
+
+ var result = IPA.login_password(username[0], password[0]);
+
+ IPA.hide_activity_icon();
+
+ if (result === 'success') {
+ that.on_login_success();
+ } else if (result === 'password-expired') {
+ that.reset_error_box.css('display', 'none');
+ that.show_reset_form();
+ } else {
+ that.show_login_error_message(result);
+ }
+ };
+
+ that.on_login_success = function() {
+ that.login_error_box.css('display', 'none');
+
+ that.username_widget.clear();
+ that.password_widget.clear();
+
+ that.on_retry();
+ };
+
+ that.on_reset = function() {
+ if (!that.validate()) return;
+
+ var username = that.username_widget.save();
+ var password = that.password_widget.save();
+ var new_password = that.new_password_widget.save();
+ var verify_password = that.verify_password_widget.save();
+
+ that.reset_error_box.css('display', 'none');
+
+ var result = IPA.reset_password(username[0],
+ password[0],
+ new_password[0]);
+
+ if (result.status === 'ok') {
+ that.on_reset_success();
+ } else {
+ that.reset_error_box.html(result.message);
+ that.reset_error_box.css('display', 'block');
+ }
+ };
+
+ that.on_reset_success = function() {
+
+ that.login_error_box.css('display', 'none');
+ that.reset_error_box.css('display', 'none');
+
+ that.password_widget.update(that.new_password_widget.save());
+
+ that.new_password_widget.clear();
+ that.verify_password_widget.clear();
+
+ that.show_session_form();
+
+ //re-login
+ that.on_login();
+ };
+
+ //replaces confirm_mixin method
+ that.on_key_up = function(event) {
+
+ if (that.switching) {
+ that.switching = false;
+ return;
+ }
+
+ if (that.current_view === 'session') {
+ if (event.keyCode === $.ui.keyCode.ENTER && !this.test_ignore(event)) {
+ that.on_login();
+ event.preventDefault();
+ }
+ } else {
+ if (event.keyCode === $.ui.keyCode.ENTER && !this.test_ignore(event)) {
+ that.on_reset();
+ event.preventDefault();
+ } else if (event.keyCode === $.ui.ESCAPE) {
+ that.on_cancel();
+ event.preventDefault();
+ }
+ }
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.limit_text = function(value, max_length) {
+
+ if (!value) return '';
+
+ var limited_text = value;
+
+ if (value.length && value.length > max_length) {
+ limited_text = value.substring(0, max_length - 3)+'...';
+ }
+
+ return limited_text;
+};
+
+IPA.create_options = function(values) {
+
+ var options = [];
+
+ for (var i=0; i<values.length; i++) {
+ var val = values[i];
+ var option = val;
+
+ if (typeof val === 'string') {
+ option = {
+ value: val,
+ label: val
+ };
+ }
+
+ options.push(option);
+ }
+
+ return options;
+};
+
+IPA.is_empty = function(value) {
+
+ var empty = false;
+
+ if (!value) empty = true;
+
+ if (value instanceof Array) {
+ empty = empty || value.length === 0 ||
+ (value.length === 1) && (value[0] === '');
+ }
+
+ if (value === '') empty = true;
+
+ return empty;
+};
+
+IPA.defined = function(value, check_empty_str) {
+ return value !== null && value !== undefined &&
+ ((check_empty_str && value !== '') || !check_empty_str);
+};
+
+IPA.array_diff = function(a, b) {
+
+ if (a === b || (!a && !b)) return false;
+
+ if (!a || !b) return true;
+
+ if (a.length !== b.length) return true;
+
+ for (var i=0; i<a.length; i++) {
+ if (a[i] !== b[i]) return true;
+ }
+
+ return false;
+};
+
+IPA.confirm = function(msg) {
+ return window.confirm(msg);
+};
+
+IPA.notify_success = function(message, timeout) {
+
+ if (!message) return; // don't show undefined, null and such
+
+ function destroy_timeout() {
+ if (IPA.notify_success.timeout) window.clearTimeout(IPA.notify_success.timeout);
+ }
+
+ var notification_area = $('.notification-area');
+
+ if (notification_area.length === 0) {
+ notification_area = $('<div/>', {
+ 'class': 'notification-area ui-corner-all ui-state-highlight',
+ click: function() {
+ destroy_timeout();
+ notification_area.fadeOut(100);
+ }
+ });
+
+ notification_area.appendTo('#container');
+ }
+
+ notification_area.text(message);
+
+ destroy_timeout();
+ notification_area.fadeIn(IPA.config.message_fadein_time);
+
+ IPA.notify_success.timeout = window.setTimeout(function() {
+ notification_area.fadeOut(IPA.config.message_fadeout_time);
+ }, timeout || IPA.config.message_timeout);
+};
+
+IPA.config = {
+ default_priority: 500,
+ message_timeout: 3000, // [ms]
+ message_fadeout_time: 800, // [ms]
+ message_fadein_time: 400 // [ms]
+};
diff --git a/install/ui/src/freeipa/navigation.js b/install/ui/src/freeipa/navigation.js
new file mode 100644
index 000000000..deef37dd8
--- /dev/null
+++ b/install/ui/src/freeipa/navigation.js
@@ -0,0 +1,455 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+IPA.navigation = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+
+ that.container = spec.container;
+ that.root = that.container.attr('id');
+
+ that.content = spec.content;
+ that.tab_class = spec.tab_class || 'tabs';
+ that.max_depth = spec.max_depth || 3;
+
+ that.tabs = [];
+ that.tabs_by_name = {};
+
+ that.path = {};
+
+ that.set_tabs = function(tabs) {
+ that.tabs = tabs;
+ that.tabs_by_name = {};
+
+ for (var i=0; i<tabs.length; i++) {
+ that.add_tab(tabs[i]);
+ }
+ };
+
+ that.add_tab = function(tab, parent) {
+ if (!tab.name) {
+ tab.name = tab.entity;
+ }
+ tab.parent = parent;
+
+ that.tabs_by_name[tab.name] = tab;
+
+ for (var i=0; tab.children && i<tab.children.length; i++) {
+ that.add_tab(tab.children[i], tab);
+ }
+ };
+
+ that.get_tab = function(name) {
+ return that.tabs_by_name[name];
+ };
+
+ that.get_active_tab = function(state) {
+ var name = null;
+ var next = state[that.root];
+
+ while (next) {
+ name = next;
+ next = state[name];
+ }
+
+ return that.get_tab(name);
+ };
+
+ that.is_ancestor = function(tab, ancestor) {
+ var parent = tab.parent;
+ while (parent) {
+ if (parent == ancestor) return true;
+ parent = parent.parent;
+ }
+ return false;
+ };
+
+ that.get_path_state = function(name) {
+
+ var path_state = {};
+
+ var tab = that.get_tab(name);
+ var parent = tab.parent;
+
+ while (parent) {
+ path_state[parent.name] = tab.name;
+
+ tab = parent;
+ parent = tab.parent;
+ }
+
+ path_state[that.root] = tab.name;
+
+ return path_state;
+ };
+
+ that.push_state = function(params) {
+
+ var param_path = {};
+ var param_state = {};
+
+ for (var key in params) {
+ var value = params[key];
+ if (key.indexOf('-') < 0) {
+ param_path[key] = value;
+ } else {
+ param_state[key] = value;
+ }
+ }
+
+ var state = {};
+
+ var prev_entity = IPA.current_entity;
+ var prev_facet = prev_entity ? prev_entity.facet : null;
+
+ if (prev_facet) {
+
+ if (prev_facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ facet: prev_facet
+ });
+
+ dialog.callback = function() {
+
+ // Some facet's might not call reset before this call but after
+ // so they are still dirty. Calling reset prevent's opening of
+ // dirty dialog again.
+ if (prev_facet.is_dirty()) prev_facet.reset();
+ $.bbq.pushState(params);
+ };
+
+ dialog.open(that.container);
+
+ return false;
+ }
+
+ // get prev facet state
+ $.extend(state, prev_facet.state);
+ }
+
+ // merge existing path with new path
+ $.extend(that.path, param_path);
+
+ // find the tab pointed by the path
+ var tab = that.get_active_tab(that.path);
+
+ // find the active tab at the lowest level
+ while (!tab.entity) {
+ var index = tab.container.tabs('option', 'selected');
+ tab = tab.children[index];
+ }
+
+ var facet_name;
+ if (tab.entity == prev_entity) {
+ // merge prev facet state with new state to find new facet name
+ $.extend(state, param_state);
+ facet_name = state[tab.entity.name+'-facet'];
+
+ } else {
+ // find new facet name in the new state
+ facet_name = param_state[tab.entity.name+'-facet'];
+ }
+
+ var facet = tab.entity.get_facet(facet_name);
+
+ // update new facet state with new state
+ $.extend(facet.state, param_state);
+
+ var entity = tab.entity.get_containing_entity();
+ while (entity) {
+ var facet2 = entity.get_facet();
+
+ var key_names = entity.get_key_names();
+ for (var i=0; i<key_names.length; i++) {
+ var key_name = key_names[i];
+ var key_value = param_state[key_name];
+ if (!key_value) key_value = facet2.state[key_name];
+ if (key_value) facet.state[key_name] = key_value;
+ }
+
+ entity = entity.get_containing_entity();
+ }
+
+ // push entity path and facet state
+ state = {};
+ $.extend(state, that.get_path_state(tab.name));
+ $.extend(state, facet.state);
+ $.bbq.pushState(state, 2);
+
+ return true;
+ };
+
+ that.get_state = function(key) {
+ return $.bbq.getState(key);
+ };
+
+ that.remove_state = function(key) {
+ $.bbq.removeState(key);
+ };
+
+ that.show_tab = function(tab_name, pkey) {
+
+ var tab = that.get_tab(tab_name);
+
+ var state = that.get_path_state(tab.name);
+
+ if (tab.entity) {
+
+ if (tab.facet) {
+ state[tab.entity.name + '-facet'] = tab.facet;
+ }
+
+ if (pkey) {
+ state[tab.entity.name + '-pkey'] = pkey;
+ }
+ }
+
+ return that.push_state(state);
+ };
+
+ that.show_page = function(entity_name, facet_name, pkey) {
+ var state = that.get_path_state(entity_name);
+
+ if (facet_name) {
+ state[entity_name + '-facet'] = facet_name;
+ }
+
+ if (pkey) {
+ state[entity_name + '-pkey'] = pkey;
+ }
+
+ return that.push_state(state);
+ };
+
+ /*like show page, but works for nested entities */
+ that.show_entity_page = function(entity, facet_name, pkeys) {
+ var state = that.get_path_state(entity.name);
+
+ if (facet_name) {
+ state[entity.name + '-facet'] = facet_name;
+ }
+
+ if (pkeys) {
+ if (pkeys instanceof Array){
+ var current_entity = entity;
+ while (current_entity){
+ state[current_entity.name + '-pkey'] = pkeys.pop();
+ current_entity = current_entity.get_containing_entity();
+ }
+ }else{
+ state[entity.name + '-pkey'] = pkeys;
+ }
+ }
+
+ return that.push_state(state);
+ };
+
+ that.show_top_level_page = function() {
+ jQuery.bbq.pushState({}, 2);
+ };
+
+ that.get_tab_facet = function(tab_name) {
+
+ var facet = null;
+ var tab = that.get_tab(tab_name);
+
+ if (tab.entity) {
+ if (tab.facet) {
+ facet = tab.entity.get_facet(tab.facet);
+ } else {
+ facet = tab.entity.get_facet(tab.entity.redirect_facet);
+ }
+ }
+
+ return facet;
+ };
+
+
+ that.create = function() {
+
+ var container = $('<div/>', {
+ name: that.root
+ }).appendTo(that.container);
+
+ that._create(that.tabs, container, 1);
+
+ var tabs = $('.' + that.tab_class, that.container);
+ tabs.tabs({
+ select: function(event, ui) {
+
+ // get the selected tab
+ var panel = $(ui.panel);
+ var name = panel.attr('name');
+ var selected_tab = that.get_tab(name);
+
+ // get the tab specified in the URL state
+ var state = that.get_state();
+ var url_tab = that.get_active_tab(state);
+
+ if (url_tab) {
+ // if they are the same, the selection is triggered by hash change
+ if (url_tab == selected_tab) {
+ // use the URL state to update internal state
+ return that.push_state(state);
+
+ // if the selection is for the ancestor
+ } else if (that.is_ancestor(url_tab, selected_tab)) {
+ // let the tab be updated and don't change the state
+ return true;
+ }
+ }
+
+ // selection is triggered by mouse click, update the URL state
+ return that.show_tab(name);
+ }
+ });
+ };
+
+ that._create = function(tabs, container, depth) {
+
+ var parent_name = container.attr('name');
+ that.path[parent_name] = tabs[0].name;
+
+ container.addClass(that.tab_class);
+ container.addClass('tabs'+depth);
+
+ var ul = $('<ul/>').appendTo(container);
+ var created_count = 0;
+
+ for (var i=0; i<tabs.length; i++) {
+ var tab = tabs[i];
+ tab.container = container;
+
+ var tab_id = that.root+'-'+tab.name;
+
+ if (tab.entity) {
+ var entity = IPA.get_entity(tab.entity);
+ if (!entity){
+ tabs.splice(i, 1);
+ i--;
+ continue;
+ }
+ tab.entity = entity;
+
+ if (!tab.label) {
+ tab.label = entity.label;
+ }
+ }
+
+ var tab_li = $('<li/>').append($('<a/>', {
+ href: '#'+tab_id,
+ title: tab.label,
+ html: tab.label
+ }));
+
+ if (tab.hidden) {
+ tab_li.css('display', 'none');
+ }
+
+ tab.children_container = $('<div/>', {
+ id: tab_id,
+ name: tab.name
+ });
+
+ if (tab.children && tab.children.length) {
+ var kids =
+ that._create(tab.children, tab.children_container, depth+1);
+ /*If there are no child tabs, remove the container */
+ if (kids === 0) {
+ tabs.splice(i, 1);
+ i -= 1;
+ continue;
+ }
+ }
+ created_count += 1;
+ tab_li.appendTo(ul);
+ tab.children_container.appendTo(container);
+ }
+ return created_count;
+ };
+
+ that.update = function() {
+ for (var i=1; i<=that.max_depth; i++) {
+ that.container.removeClass(that.tab_class+'-'+i);
+ that.content.removeClass(that.tab_class+'-'+i);
+ }
+ $('.entity', that.content).css('display', 'none');
+
+ var container = $('div[name='+that.root+']', that.container);
+ that._update(that.tabs, container, 1);
+ };
+
+ that._update = function(tabs, container, depth) {
+
+ var parent_name = container.attr('name');
+ var tab_name = that.get_state(parent_name);
+ if (!tab_name) tab_name = that.path[parent_name];
+ that.path[parent_name] = tab_name;
+
+ var index = 0;
+ while (index < tabs.length && tabs[index].name != tab_name) index++;
+ if (index >= tabs.length) index = 0;
+
+ container.tabs('select', index);
+
+ var tab = tabs[index];
+ if (tab.depth !== undefined) {
+ depth += tab.depth;
+ }
+
+ if (tab.children && tab.children.length) {
+ var next_depth = depth + 1;
+ that._update(tab.children, tab.children_container, next_depth);
+
+ } else if (tab.entity) {
+
+ that.container.addClass(that.tab_class+'-'+depth);
+ that.content.addClass(that.tab_class+'-'+depth);
+
+ var entity_container = $('.entity[name="'+tab.entity.name+'"]',
+ that.content);
+ if (!entity_container.length) {
+ tab.content = $('<div/>', {
+ name: tab.entity.name,
+ title: tab.entity.label,
+ 'class': 'entity'
+ }).appendTo(that.content);
+ tab.entity.create(tab.content);
+ }
+
+ entity_container.css('display', 'block');
+ tab.entity.display(tab.content);
+ }
+ };
+
+ // methods that should be invoked by subclasses
+ that.navigation_update = that.update;
+
+ that.set_tabs(spec.tabs);
+
+ return that;
+};
diff --git a/install/ui/src/freeipa/net.js b/install/ui/src/freeipa/net.js
new file mode 100644
index 000000000..b8674919f
--- /dev/null
+++ b/install/ui/src/freeipa/net.js
@@ -0,0 +1,394 @@
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var NET = {};
+
+NET.ip_address = function(spec) {
+
+ spec = spec || {};
+
+ if (typeof spec === 'string') {
+ spec = {
+ address: spec
+ };
+ }
+
+ var that = {};
+
+ that.input = spec.address;
+
+ that.type = spec.type;
+ that.parts = spec.parts;
+ that.reverse_address = '';
+ that.only_decimal = spec.only_decimal !== undefined? spec.only_decimal :
+ false; //for parsing IPv4 address
+
+ that.parse = function() {
+
+ if (!that.input && !that.parts) {
+ that.set_error('no input');
+ return false;
+ }
+
+ if (!that.type) {
+ that.type = that.detect_type();
+ }
+
+ if (that.type === 'v4-quads') {
+ return that.parse_v4_quads();
+ } else if (that.type === 'v4-int') {
+ return that.parse_v4_int();
+ } else if (that.type === 'v6') {
+ return that.parse_v6();
+ }
+
+ that.set_error('not an ip address');
+ return false;
+ };
+
+ that.detect_type = function() {
+
+ var type;
+
+ if (!that.input) return null;
+
+ if (that.input.indexOf(':') > -1) type = 'v6';
+ else if (that.input.indexOf('.') > -1) type = 'v4-quads';
+ else type = 'v4-int';
+
+ return type;
+ };
+
+ that.parse_v4_int = function() {
+
+ var part = { value: that.input };
+ if(!that.is_part_valid_v4(part, 32, that.only_decimal)) return false;
+
+ that.parts = [];
+ that.make_quads(part.decimal_value, that.parts);
+
+ that.valid = true;
+ return true;
+ };
+
+ that.parse_v4_quads = function() {
+
+ if (!that.parts) {
+ that.parts = that.input.split('.');
+ }
+
+ if (that.parts.length !== 4) {
+ return that.set_error('invalid number of parts');
+ }
+
+ for (var i=0; i<4; i++) {
+
+ var part = { value: that.parts[i] };
+
+ if (!that.is_part_valid_v4(part, 8, that.only_decimal)) {
+ return false;
+ }
+ that.parts[i] = part.decimal_value.toString(10);
+ }
+
+ that.valid = true;
+ return true;
+ };
+
+ that.parse_v6 = function() {
+
+ if (!that.parts) {
+ that.parts = that.input.split(':');
+ }
+
+ var total_parts = that.parts.length;
+ var ipv4_present = false;
+ var double_colon = false;
+ var double_colon_position;
+
+ var i;
+
+ //usecases like ':'
+ if (that.parts.length <= 2) {
+ return that.set_error('invalid format');
+ }
+
+ for (i=0; i<that.parts.length; i++) {
+ var part = that.parts[i];
+
+ if (i === that.parts.length -1 && part.indexOf('.') > -1) {
+ ipv4_present = true;
+ total_parts++; //ipv4 part consists of 4 octects (two parts)
+ }
+
+ //checking for ::
+ if (part.length === 0) {
+
+ if (!double_colon || //first occurance
+ (double_colon && i === 1) || //still at the beginning
+ (double_colon && i === that.parts.length - 1 &&
+ double_colon_position === i -1)) { //still at the end
+
+ part = '0000';
+ that.parts[i] = part;
+ double_colon = true;
+ double_colon_position = i;
+ } else { //second occurance of ::
+ return that.set_error('invalid format: mupltiple ::');
+ }
+ }
+
+ //add missing zeros for not empty parts
+ if (part.length !== 0 && part.length < 4) {
+ part = add_leading_zeros(part, 4 - part.length);
+ that.parts[i] = part;
+ }
+ }
+
+ //add missing empty parts
+ if (double_colon) {
+ var parts_to_add = 8 - total_parts;
+
+ for (i=0; i<parts_to_add; i++) {
+ that.parts.splice(double_colon_position, 0, '0000');
+ }
+ }
+
+ //change ipv4 part
+ if (ipv4_present) {
+ var ipv4_address = NET.ip_address();
+ ipv4_address.input = that.parts[that.parts.length -1];
+ ipv4_address.only_decimal = true;
+ if (ipv4_address.parse() && ipv4_address.type === 'v4-quads') {
+ var v4_parts = ipv4_address.parts;
+ var oct1 = dec_2_hex(v4_parts[0]);
+ var oct2 = dec_2_hex(v4_parts[1]);
+ var oct3 = dec_2_hex(v4_parts[2]);
+ var oct4 = dec_2_hex(v4_parts[3]);
+
+ //replace IPv4 part with two IPv6 parts (4 octets)
+ that.parts[that.parts.length -1] = oct1+oct2;
+ that.parts.push(oct3+oct4);
+ } else {
+ return that.set_error('invalid IPv4 part');
+ }
+ }
+
+ //validate length after modifications
+ if (that.parts.length !== 8) {
+ return that.set_error('invalid number of parts');
+ }
+
+ //validate each part
+ for (i=0; i<8; i++) {
+
+ if (!that.is_part_valid_v6(that.parts[i])) {
+ return false;
+ }
+ }
+
+ that.valid = true;
+ return true;
+ };
+
+ function dec_2_hex(val) {
+ var dec = parseInt(val, 10);
+ var hex = dec.toString(16);
+ hex = add_leading_zeros(hex, 2 - hex.length);
+ return hex;
+ }
+
+ function add_leading_zeros(val, num) {
+ for (var i=0; i<num; i++) {
+ val='0'+val;
+ }
+ return val;
+ }
+
+ that.get_reverse = function() {
+
+ if (!that.valid) return 'invalid input address';
+
+ if (that.type === 'v4-quads' || that.type === 'v4-int') {
+ return that.get_v4_reverse();
+ } else if (that.type === 'v6') {
+ return that.get_v6_reverse();
+ }
+
+ return '';
+ };
+
+ that.get_v4_reverse = function() {
+
+ that.reverse_parts = [];
+
+ for (var i=3; i>=0; i--) {
+ that.reverse_parts.push(that.parts[i]);
+ }
+
+ that.reverse_parts.push('in-addr');
+ that.reverse_parts.push('arpa');
+
+ return that.reverse_parts.join('.');
+ };
+
+ that.get_v6_reverse = function() {
+
+ that.reverse_parts = [];
+
+ var address = that.parts.join('');
+
+ for (var i=31; i>=0; i--) {
+ that.reverse_parts.push(address[i]);
+ }
+
+ that.reverse_parts.push('ip6');
+ that.reverse_parts.push('arpa');
+
+ return that.reverse_parts.join('.');
+ };
+
+ that.set_error = function(msg) {
+ that.valid = false;
+ that.error = msg;
+ return false;
+ };
+
+ that.is_part_valid_v6 = function(str) {
+
+ if (str.length === 0) {
+ return that.set_error('not a number');
+ }
+
+ if (str.length > 4) {
+ return that.set_error('wrong format - too long');
+ }
+
+ for (var i=0; i<str.length; i++) {
+
+ var digit = parseInt(str[i], 16);
+
+ //check if character is digit
+ if (isNaN(digit)) {
+ return that.set_error('invalid format: \''+digit+'\'');
+ }
+ }
+
+ return true;
+ };
+
+ /*
+ * Checks if part.value is valid IPv4 integer of given size (in bits).
+ * Validation can be limited only to decimal values by only_decimal argument.
+ * Sets its decimal representation to part.decimal_value.
+ */
+ that.is_part_valid_v4 = function(part, bits, only_decimal) {
+
+ if (!part.value || part.value.length === 0) {
+ return that.set_error('not a number');
+ }
+
+ var radix = that.get_radix(part.value);
+
+ var number = part.value;
+
+ if (radix === 16) number = part.value.substring(2);
+ else if (radix === 8) number = part.value.substring(1);
+
+ if (radix !== 10 && only_decimal) {
+ return that.set_error('not a decimal number');
+ }
+
+ for (var i=0; i<number.length; i++) {
+
+ var digit = parseInt(number[i], radix);
+
+ //check if character is digit in its radix
+ if (isNaN(digit)) {
+ return that.set_error('invalid format: \''+digit+'\'');
+ }
+
+ //check for leading zeros
+ if (i === 0 && digit === 0 && number.length > 1) {
+ return that.set_error('invalid format: leading zeros');
+ }
+ }
+
+ var max_value = Math.pow(2, bits) - 1;
+
+ part.decimal_value = parseInt(part.value, radix);
+
+ if (part.decimal_value > max_value) {
+ return that.set_error('value out of range');
+ }
+
+ return true;
+ };
+
+ that.get_radix = function(str) {
+
+ var normalized = str.toLowerCase();
+
+ if (normalized.length > 2 &&
+ normalized[0] === '0' &&
+ normalized[1] === 'x') {
+ return 16;
+
+ } else if (normalized.length > 1 && normalized[0] === '0') {
+ return 8;
+ }
+
+ return 10;
+ };
+
+ that.make_quads = function(integer, quads) {
+
+ var hex_str = integer.toString(16);
+ if (hex_str.length < 8) {
+ hex_str = add_leading_zeros(hex_str, 8 - hex_str.length);
+ }
+
+ for (var i=0; i<hex_str.length; i+=2) {
+ var quad_hex = hex_str.substring(i,i+2);
+ var quad = parseInt(quad_hex, 16);
+ quads.push(quad.toString(10));
+ }
+ };
+
+ that.get_radix = function(str) {
+
+ var normalized = str.toLowerCase();
+
+ if (normalized.length > 2 &&
+ normalized[0] === '0' &&
+ normalized[1] === 'x') {
+ return 16;
+
+ } else if (normalized.length > 1 && normalized[0] === '0') {
+ return 8;
+ }
+
+ return 10;
+ };
+
+ that.parse();
+
+ return that;
+}; \ No newline at end of file
diff --git a/install/ui/src/freeipa/netgroup.js b/install/ui/src/freeipa/netgroup.js
new file mode 100644
index 000000000..73deec100
--- /dev/null
+++ b/install/ui/src/freeipa/netgroup.js
@@ -0,0 +1,306 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.netgroup = {
+ remove_method_priority: IPA.config.default_priority - 1,
+ enable_priority: IPA.config.default_priority + 1
+};
+
+IPA.netgroup.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.facet_groups(['settings', 'member', 'memberof']).
+ search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ factory: IPA.netgroup.details_facet,
+ entity: that,
+ command_mode: 'info'
+ }).
+ association_facet({
+ name: 'memberof_netgroup',
+ associator: IPA.serial_associator
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.netgroup.details_facet = function(spec) {
+
+ var entity_name = spec.entity.name;
+
+ //
+ // Identity
+ //
+
+ spec.fields = [
+ {
+ name: 'cn',
+ widget: 'identity.cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description',
+ widget: 'identity.description'
+ },
+ {
+ name: 'nisdomainname',
+ widget: 'identity.nisdomainname'
+ }
+ ];
+
+ spec.widgets = [
+ {
+ type: 'details_table_section',
+ name: 'identity',
+ label: IPA.messages.details.general,
+ widgets: [
+ {
+ name: 'cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description'
+ },
+ {
+ name: 'nisdomainname',
+ widget: 'general.nisdomainname'
+ }
+ ]
+ }
+ ];
+
+ //
+ // Users
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'usercategory',
+ widget: 'user.rule.usercategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_user',
+ widget: 'user.rule.memberuser_user',
+ priority: IPA.netgroup.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_group',
+ widget: 'user.rule.memberuser_group',
+ priority: IPA.netgroup.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'user',
+ label: IPA.messages.objects.netgroup.user,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'usercategory',
+ options: [
+ { value: 'all',
+ label: IPA.messages.objects.netgroup.anyone },
+ { value: '',
+ label: IPA.messages.objects.netgroup.specified_users }
+ ],
+ tables: [
+ { name: 'memberuser_user' },
+ { name: 'memberuser_group' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberuser_user',
+ add_method: 'add_member',
+ remove_method: 'remove_member',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member,
+ columns: [
+ {
+ name: 'memberuser_user',
+ label: IPA.messages.objects.netgroup.users,
+ link: true
+ }
+ ]
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberuser_group',
+ add_method: 'add_member',
+ remove_method: 'remove_member',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member,
+ columns: [
+ {
+ name: 'memberuser_group',
+ label: IPA.messages.objects.netgroup.usergroups,
+ link: true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Hosts
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'hostcategory',
+ widget: 'host.rule.hostcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_host',
+ widget: 'host.rule.memberhost_host',
+ priority: IPA.netgroup.remove_method_priority,
+ external: 'externalhost'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_hostgroup',
+ widget: 'host.rule.memberhost_hostgroup',
+ priority: IPA.netgroup.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'host',
+ label: IPA.messages.objects.netgroup.host,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'hostcategory',
+ options: [
+ {
+ 'value': 'all',
+ 'label': IPA.messages.objects.netgroup.any_host
+ },
+ {
+ 'value': '',
+ 'label': IPA.messages.objects.netgroup.specified_hosts
+ }
+ ],
+ tables: [
+ { 'name': 'memberhost_host' },
+ { 'name': 'memberhost_hostgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberhost_host',
+ name: 'memberhost_host',
+ add_method: 'add_member',
+ remove_method: 'remove_member',
+ external: 'externalhost',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member,
+ columns: [
+ {
+ name: 'memberhost_host',
+ label: IPA.messages.objects.netgroup.hosts,
+ link: true
+ },
+ {
+ name: 'externalhost',
+ label: IPA.messages.objects.netgroup.external,
+ formatter: IPA.boolean_formatter(),
+ width: '200px'
+ }
+ ]
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberhost_hostgroup',
+ name: 'memberhost_hostgroup',
+ add_method: 'add_member',
+ remove_method: 'remove_member',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member,
+ columns: [
+ {
+ name: 'memberhost_hostgroup',
+ label: IPA.messages.objects.netgroup.hostgroups,
+ link: true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ var that = IPA.details_facet(spec);
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.refresh();
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ that.refresh();
+ };
+
+ return that;
+};
+
+IPA.register('netgroup', IPA.netgroup.entity);
diff --git a/install/ui/src/freeipa/policy.js b/install/ui/src/freeipa/policy.js
new file mode 100644
index 000000000..c109163e4
--- /dev/null
+++ b/install/ui/src/freeipa/policy.js
@@ -0,0 +1,122 @@
+/*jsl:import ipa.js */
+/*jsl:import search.js */
+
+/* Authors:
+ * Adam Young <ayoung@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.pwpolicy = {};
+
+IPA.pwpolicy.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ sort_enabled: false,
+ columns:['cn','cospriority']
+ }).
+ details_facet({
+ sections:[
+ {
+ name : 'identity',
+ fields:[
+ {
+ type: 'link',
+ name: 'cn',
+ other_entity: 'group'
+ },
+ 'krbmaxpwdlife',
+ 'krbminpwdlife',
+ {
+ name: 'krbpwdhistorylength',
+ measurement_unit: 'number_of_passwords'
+ },
+ 'krbpwdmindiffchars',
+ 'krbpwdminlength',
+ 'krbpwdmaxfailure',
+ {
+ name: 'krbpwdfailurecountinterval',
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbpwdlockoutduration',
+ measurement_unit: 'seconds'
+ },
+ 'cospriority'
+ ]
+ }]}).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ {
+ type: 'entity_select',
+ name: 'cn',
+ other_entity: 'group',
+ other_field: 'cn',
+ required: true
+ },
+ 'cospriority'
+ ],
+ height: 300
+ });
+ };
+
+ return that;
+};
+
+IPA.krbtpolicy = {};
+
+IPA.krbtpolicy.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.details_facet({
+ title: IPA.metadata.objects.krbtpolicy.label,
+ sections: [
+ {
+ name: 'identity',
+ fields: [
+ {
+ name: 'krbmaxrenewableage',
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbmaxticketlife',
+ measurement_unit: 'seconds'
+ }
+ ]
+ }
+ ],
+ needs_update: true
+ });
+ };
+
+ return that;
+};
+
+IPA.register('pwpolicy', IPA.pwpolicy.entity);
+IPA.register('krbtpolicy', IPA.krbtpolicy.entity);
diff --git a/install/ui/src/freeipa/rule.js b/install/ui/src/freeipa/rule.js
new file mode 100644
index 000000000..dfe710b91
--- /dev/null
+++ b/install/ui/src/freeipa/rule.js
@@ -0,0 +1,254 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.rule_details_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.composite_widget(spec);
+
+ that.radio_name = spec.radio_name;
+ that.options = spec.options || [];
+ that.tables = spec.tables || [];
+ that.columns = spec.columns;
+
+ that.init = function() {
+
+ that.enable_radio = IPA.radio_widget({
+ name: that.radio_name,
+ options: that.options
+ });
+
+ that.widgets.add_widget(that.enable_radio);
+ that.enable_radio.value_changed.attach(that.on_enable_radio_changed);
+ };
+
+ that.on_enable_radio_changed = function(value) {
+ if(value.length > 0) {
+ var enabled = ('' === value[0]);
+ for (var i=0; i<that.tables.length; i++) {
+ var table = that.tables[i];
+
+ var table_widget = that.widgets.get_widget(table.name);
+ table_widget.set_enabled(enabled);
+ }
+ }
+ };
+
+ that.create = function(container) {
+
+ that.container = container;
+
+ //enable radios
+ var param_info = IPA.get_entity_param(that.entity.name, that.radio_name);
+ var title = param_info ? param_info.doc : that.radio_name;
+ var enable_radio_container = $('<div/>', {
+ name: that.radio_name,
+ title: title,
+ 'class': 'field'
+ }).appendTo(container);
+
+ enable_radio_container.append(title+': ');
+ that.enable_radio.create(enable_radio_container);
+
+ //tables
+ for (var j=0; j<that.tables.length; j++) {
+ var table = that.tables[j];
+
+ var metadata = IPA.get_entity_param(that.entity.name, table.name);
+
+ var table_container = $('<div/>', {
+ name: table.name,
+ title: metadata ? metadata.doc : table.name,
+ 'class': 'field'
+ }).appendTo(container);
+
+ var widget = that.widgets.get_widget(table.name);
+ widget.create(table_container);
+ }
+ };
+
+ that.init();
+
+ return that;
+};
+
+
+IPA.rule_association_table_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.association_table_widget(spec);
+
+ that.external = spec.external;
+
+ that.enabled = spec.enabled !== undefined ? spec.enabled : true;
+
+ that.setup_column = function(column, div, record) {
+ var suppress_link = false;
+ if (that.external) {
+ suppress_link = record[that.external] === 'true';
+ }
+ column.setup(div, record, suppress_link);
+ };
+
+ that.create_columns = function() {
+
+ if (!that.columns.length) {
+ that.association_table_widget_create_columns();
+ if (that.external) {
+ that.create_column({
+ name: that.external,
+ label: IPA.messages.objects.sudorule.external,
+ entity: that.other_entity,
+ formatter: IPA.boolean_formatter(),
+ width: '200px'
+ });
+ }
+ }
+ };
+
+ that.create_add_dialog = function() {
+
+ var entity_label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ var other_entity_label = that.other_entity.metadata.label;
+
+ var title = that.add_title;
+ title = title.replace('${entity}', entity_label);
+ title = title.replace('${primary_key}', pkey);
+ title = title.replace('${other_entity}', other_entity_label);
+
+ return IPA.rule_association_adder_dialog({
+ title: title,
+ pkey: pkey,
+ other_entity: that.other_entity,
+ attribute_member: that.attribute_member,
+ entity: that.entity,
+ external: that.external,
+ exclude: that.values
+ });
+ };
+
+ return that;
+};
+
+IPA.rule_association_table_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.association_table_field(spec);
+
+ that.external = spec.external;
+
+ that.set_values_external = function(values, external) {
+
+ for (var i=0; i<values.length; i++) {
+
+ var record = values[i];
+
+ if (typeof record !== 'object') {
+ record = {};
+ record[that.param] = values[i];
+ }
+
+ record[that.external] = external;
+
+ values[i] = record;
+ }
+ };
+
+ that.load = function(result) {
+ that.values = result[that.param] || [];
+
+ if (that.external) {
+ that.set_values_external(that.values, '');
+ var external_values = result[that.external] || [];
+ that.set_values_external(external_values, 'true');
+ $.merge(that.values, external_values);
+ }
+
+ that.widget.update(that.values);
+ that.widget.unselect_all();
+ };
+
+ that.get_update_info = function() {
+
+ var update_info = IPA.update_info_builder.new_update_info();
+
+ //association_table_widget performs basic add and remove operation
+ //immediately. Rule association field test if its enabled and if not it
+ //performs delete operation.
+
+ if (!that.widget.enabled) {
+ var values = that.save();
+
+ if (values.length > 0) { //no need to delete if has no values
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.widget.remove_method,
+ args: that.entity.get_primary_key()
+ });
+
+ command.set_option(that.widget.other_entity.name, values);
+ update_info.append_command(command, that.priority);
+ }
+ }
+
+ return update_info;
+ };
+
+ return that;
+};
+
+IPA.widget_factories['rule_association_table'] = IPA.rule_association_table_widget;
+IPA.field_factories['rule_association_table'] = IPA.rule_association_table_field;
+
+IPA.rule_association_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.association_adder_dialog(spec);
+
+ that.external = spec.external;
+
+ that.add = function() {
+ var rows = that.available_table.remove_selected_rows();
+ that.selected_table.add_rows(rows);
+
+ if (that.external) {
+ var pkey_name = that.other_entity.metadata.primary_key;
+ var value = that.external_field.val();
+ if (!value) return;
+
+ var record = {};
+ record[pkey_name] = value;
+ that.selected_table.add_record(record);
+ that.external_field.val('');
+ }
+ };
+
+ return that;
+};
diff --git a/install/ui/src/freeipa/search.js b/install/ui/src/freeipa/search.js
new file mode 100644
index 000000000..b54c375f7
--- /dev/null
+++ b/install/ui/src/freeipa/search.js
@@ -0,0 +1,491 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js */
+
+IPA.search_facet = function(spec, no_init) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'search';
+ spec.managed_entity = spec.managed_entity ? IPA.get_entity(spec.managed_entity) : spec.entity;
+
+ spec.disable_breadcrumb =
+ spec.disable_breadcrumb === undefined ? true : spec.disable_breadcrumb;
+ spec.disable_facet_tabs =
+ spec.disable_facet_tabs === undefined ? true : spec.disable_facet_tabs;
+
+ spec.actions = spec.actions || [];
+ spec.actions.unshift(
+ IPA.refresh_action,
+ IPA.batch_remove_action,
+ IPA.add_action);
+
+ spec.control_buttons = spec.control_buttons || [];
+ spec.control_buttons.unshift(
+ {
+ name: 'refresh',
+ label: IPA.messages.buttons.refresh,
+ icon: 'reset-icon'
+ },
+ {
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon'
+ },
+ {
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon'
+ });
+
+ spec.state = spec.state || {};
+ spec.state.evaluators = spec.state.evaluators || [];
+ spec.state.evaluators.push(
+ IPA.selected_state_evaluator,
+ IPA.self_service_state_evaluator);
+
+ var that = IPA.table_facet(spec, true);
+
+ that.deleter_dialog = spec.deleter_dialog || IPA.search_deleter_dialog;
+
+ that.create_header = function(container) {
+
+ that.facet_create_header(container);
+
+ var div = $('<div/>', {
+ 'class': 'right-aligned-facet-controls'
+ }).appendTo(that.controls);
+
+ div.append(IPA.create_network_spinner());
+
+ var filter_container = $('<div/>', {
+ 'class': 'search-filter'
+ }).appendTo(div);
+
+ that.filter = $('<input/>', {
+ type: 'text',
+ name: 'filter'
+ }).appendTo(filter_container);
+
+ that.filter.keypress(function(e) {
+ /* if the key pressed is the enter key */
+ if (e.which == 13) {
+ that.find();
+ }
+ });
+
+ that.find_button = IPA.action_button({
+ name: 'find',
+ icon: 'search-icon',
+ click: function() {
+ that.find();
+ return false;
+ }
+ }).appendTo(filter_container);
+
+ that.create_control_buttons(that.controls);
+ };
+
+ that.show = function() {
+ that.facet_show();
+
+ var filter = IPA.nav.get_state(that.entity.name+'-filter');
+ that.old_filter = filter || '';
+ that.old_pkeys = that.managed_entity.get_primary_key_prefix();
+
+ if (that.filter) {
+ that.filter.val(filter);
+ }
+ };
+
+ that.needs_update = function() {
+ if (that._needs_update !== undefined) return that._needs_update;
+
+ var needs_update = that.facet_needs_update();
+
+ //check if state changed
+ var pkeys = that.managed_entity.get_primary_key_prefix();
+ needs_update = needs_update || IPA.array_diff(pkeys, that.old_pkeys);
+
+ return needs_update;
+ };
+
+ that.show_add_dialog = function() {
+ var dialog = that.managed_entity.get_dialog('add');
+ dialog.open(that.container);
+ };
+
+ that.show_remove_dialog = function() {
+
+ var values = that.get_selected_values();
+
+ var title;
+ if (!values.length) {
+ title = IPA.messages.dialogs.remove_empty;
+ alert(title);
+ return;
+ }
+
+ var dialog = that.managed_entity.get_dialog('remove');
+
+ if (!dialog) {
+ dialog = that.deleter_dialog();
+ }
+
+ dialog.entity_name = that.managed_entity.name;
+ dialog.entity = that.managed_entity;
+ dialog.facet = that;
+
+ title = IPA.messages.dialogs.remove_title;
+ var label = that.managed_entity.metadata.label;
+ dialog.title = title.replace('${entity}', label);
+
+ dialog.set_values(values);
+
+ dialog.open(that.container);
+ };
+
+ that.find = function() {
+ var filter = that.filter.val();
+ var old_filter = IPA.nav.get_state(that.managed_entity.name+'-filter');
+ var state = {};
+ state[that.managed_entity.name + '-filter'] = filter;
+
+ if (filter !== old_filter) that.set_expired_flag();
+
+ IPA.nav.push_state(state);
+ };
+
+ that.get_search_command_name = function() {
+ var name = that.managed_entity.name + '_find';
+ if (that.pagination && !that.search_all_entries) {
+ name += '_pkeys';
+ }
+ return name;
+ };
+
+ that.create_refresh_command = function() {
+
+ var filter = that.managed_entity.get_primary_key_prefix();
+ filter.push(IPA.nav.get_state(that.managed_entity.name+'-filter'));
+
+ var command = IPA.command({
+ name: that.get_search_command_name(),
+ entity: that.managed_entity.name,
+ method: 'find',
+ args: filter,
+ options: {
+ all: that.search_all_attributes
+ }
+ });
+
+ if (that.pagination) {
+ if (!that.search_all_entries) command.set_option('pkey_only', true);
+ command.set_option('sizelimit', 0);
+ }
+
+ return command;
+ };
+
+ that.refresh = function() {
+
+ var command = that.create_refresh_command();
+
+ command.on_success = function(data, text_status, xhr) {
+ if (!IPA.opened_dialogs.dialogs.length) that.filter.focus();
+ that.load(data);
+ that.show_content();
+ };
+
+ command.on_error = function(xhr, text_status, error_thrown) {
+ that.report_error(error_thrown);
+ };
+
+ command.execute();
+ };
+
+ that.clear = function() {
+ if (that.needs_clear()) {
+ that.table.clear();
+ }
+ };
+
+ that.needs_clear = function() {
+ var clear = false;
+ var filter = IPA.nav.get_state(that.entity.name+'-filter') || '';
+ clear = that.old_filter !== '' || that.old_filter !== filter;
+
+ var pkeys = that.managed_entity.get_primary_key_prefix();
+ clear = clear || IPA.array_diff(pkeys, that.old_pkeys);
+
+ return clear;
+ };
+
+ that.init_search_facet = function() {
+
+ that.init_facet();
+ that.init_table_columns();
+ that.init_table(that.managed_entity);
+ };
+
+ if (!no_init) that.init_search_facet();
+
+ // methods that should be invoked by subclasses
+ that.search_facet_refresh = that.refresh;
+ that.search_facet_create_refresh_command = that.create_refresh_command;
+
+ return that;
+};
+
+IPA.search_deleter_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.deleter_dialog(spec);
+
+ that.create_command = function() {
+ var batch = IPA.batch_command({
+ error_message: IPA.messages.search.partial_delete
+ });
+
+ var pkeys = that.entity.get_primary_key_prefix();
+
+ for (var i=0; i<that.values.length; i++) {
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: 'del'
+ });
+
+ for (var j=0; j<pkeys.length; j++) {
+ command.add_arg(pkeys[j]);
+ }
+
+ var value = that.values[i];
+ if (value instanceof Object) {
+ for (var key in value) {
+ if (value.hasOwnProperty(key)) {
+ if (key === 'pkey'){
+ command.add_arg(value[key]);
+ } else {
+ command.set_option(key, value[key]);
+ }
+ }
+ }
+ } else {
+ command.add_arg(value);
+ }
+
+ batch.add_command(command);
+ }
+
+ return batch;
+ };
+
+ that.execute = function() {
+
+ var batch = that.create_command();
+
+ batch.on_success = function(data, text_status, xhr) {
+ that.facet.refresh();
+ that.facet.on_update.notify([],that.facet);
+ IPA.notify_success(IPA.messages.search.deleted);
+ };
+
+ batch.on_error = function() {
+ that.facet.refresh();
+ };
+
+ batch.execute();
+ };
+
+ that.search_deleter_dialog_create_command = that.create_command;
+
+ return that;
+};
+
+/*TODO. this has much copied code from above. Refactor the search_facet
+To either be nested or not nested. */
+IPA.nested_search_facet = function(spec) {
+
+ spec = spec || {};
+
+ spec.managed_entity = IPA.get_entity(spec.nested_entity);
+
+ spec.disable_breadcrumb = false;
+ spec.disable_facet_tabs = false;
+
+ var that = IPA.search_facet(spec);
+
+ that.show = function() {
+ that.facet_show();
+
+ that.header.set_pkey(
+ IPA.nav.get_state(IPA.current_entity.name+'-pkey'));
+
+ var filter = IPA.nav.get_state(that.managed_entity.name+'-filter');
+ that.old_filter = filter || '';
+ that.old_pkeys = that.managed_entity.get_primary_key_prefix();
+
+ if (that.filter) {
+ that.filter.val(filter);
+ }
+ };
+
+ that.refresh = function() {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ if ((!pkey) && (that.entity.redirect_facet)) {
+ that.redirect();
+ return;
+ }
+
+ that.search_facet_refresh();
+ };
+
+ return that;
+};
+
+IPA.batch_remove_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'remove';
+ spec.label = spec.label || IPA.messages.buttons.remove;
+ spec.enable_cond = spec.enable_cond || ['item-selected'];
+ spec.hide_cond = spec.hide_cond || ['self-service'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+ facet.show_remove_dialog();
+ };
+
+ return that;
+};
+
+IPA.add_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'add';
+ spec.label = spec.label || IPA.messages.buttons.add;
+ spec.hide_cond = spec.hide_cond || ['self-service'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+ facet.show_add_dialog();
+ };
+
+ return that;
+};
+
+/*
+ * Calls entity's disable command for each selected item in a batch.
+ * Usable in table facets.
+ */
+IPA.batch_items_action = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.action(spec);
+
+ that.method = spec.method || 'disable';
+ that.success_msg = spec.success_msg;
+
+ that.execute_action = function(facet, on_success, on_error) {
+
+ var entity = facet.managed_entity;
+ var pkeys = facet.get_selected_values();
+
+ that.batch = IPA.batch_command({
+ name: entity.name + '_batch_'+ that.method,
+ on_success: that.get_on_success(facet, on_success)
+ });
+
+ for (var i=0; i<pkeys.length; i++) {
+ var pkey = pkeys[i];
+
+ var command = IPA.command({
+ entity: entity.name,
+ method: that.method,
+ args: [pkey]
+ });
+
+ that.batch.add_command(command);
+ }
+
+ that.batch.execute();
+ };
+
+ that.on_success = function(facet, data, text_status, xhr) {
+ facet.on_update.notify();
+ facet.refresh();
+
+ if (that.success_msg) {
+ var succeeded = that.batch.commands.length - that.batch.errors.errors.length;
+ var msg = that.success_msg.replace('${count}', succeeded);
+ IPA.notify_success(msg);
+ }
+ };
+
+ that.get_on_success = function(facet, on_success) {
+ return function(data, text_status, xhr) {
+ that.on_success(facet, data, text_status, xhr);
+ if (on_success) on_success.call(this, data, text_status, xhr);
+ };
+ };
+
+
+ return that;
+};
+
+IPA.batch_disable_action = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'disable';
+ spec.method = spec.method || 'disable';
+ spec.needs_confirm = spec.needs_confirm === undefined ? true : spec.needs_confirm;
+ spec.enable_cond = spec.enable_cond || ['item-selected'];
+ spec.success_msg = spec.success_msg || IPA.messages.search.disabled;
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.search.disable_confirm;
+
+ return IPA.batch_items_action(spec);
+};
+
+IPA.batch_enable_action = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = spec.name || 'enable';
+ spec.method = spec.method || 'enable';
+ spec.needs_confirm = spec.needs_confirm === undefined ? true : spec.needs_confirm;
+ spec.enable_cond = spec.enable_cond || ['item-selected'];
+ spec.success_msg = spec.success_msg || IPA.messages.search.enabled;
+ spec.confirm_msg = spec.confirm_msg || IPA.messages.search.enable_confirm;
+
+ return IPA.batch_items_action(spec);
+}; \ No newline at end of file
diff --git a/install/ui/src/freeipa/selinux.js b/install/ui/src/freeipa/selinux.js
new file mode 100644
index 000000000..ca4700609
--- /dev/null
+++ b/install/ui/src/freeipa/selinux.js
@@ -0,0 +1,315 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2012 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.selinux = {
+ remove_method_priority: IPA.config.default_priority - 1
+};
+
+IPA.selinux.selinuxusermap_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ row_enabled_attribute: 'ipaenabledflag',
+ search_all_attributes: true,
+ columns: [
+ 'cn',
+ 'ipaselinuxuser',
+ {
+ name: 'ipaenabledflag',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ },
+ 'description'
+ ],
+ actions: [
+ IPA.batch_disable_action,
+ IPA.batch_enable_action
+ ],
+ control_buttons: [
+ {
+ name: 'disable',
+ label: IPA.messages.buttons.disable,
+ icon: 'disabled-icon'
+ },
+ {
+ name: 'enable',
+ label: IPA.messages.buttons.enable,
+ icon: 'enabled-icon'
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.selinux_details_facet,
+ entity: that,
+ command_mode: 'info',
+ actions: [
+ IPA.select_action,
+ IPA.enable_action,
+ IPA.disable_action,
+ IPA.delete_action
+ ],
+ header_actions: ['select_action', 'enable', 'disable', 'delete'],
+ state: {
+ evaluators: [
+ {
+ factory: IPA.enable_state_evaluator,
+ field: 'ipaenabledflag'
+ }
+ ],
+ summary_conditions: [
+ IPA.enabled_summary_cond(),
+ IPA.disabled_summary_cond()
+ ]
+ }
+ }).
+ adder_dialog({
+ fields: [
+ 'cn',
+ 'ipaselinuxuser'
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.selinux_details_facet = function(spec) {
+
+ var entity_name = spec.entity.name;
+
+ //
+ // General
+ //
+
+ spec.fields = [
+ {
+ name: 'cn',
+ read_only: true,
+ widget: 'general.cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description',
+ widget: 'general.description'
+ },
+ {
+ name: 'ipaselinuxuser',
+ widget: 'general.ipaselinuxuser'
+ },
+ {
+ type: 'entity_select',
+ name: 'seealso',
+ widget: 'general.seealso'
+ }
+ ];
+
+ spec.widgets = [
+ {
+ type: 'details_table_section',
+ name: 'general',
+ label: IPA.messages.details.general,
+ widgets: [
+ {
+ name: 'cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description'
+ },
+ {
+ name: 'ipaselinuxuser',
+ widget: 'general.ipaselinuxuser'
+ },
+ {
+ type: 'entity_select',
+ name: 'seealso',
+ other_entity: 'hbacrule',
+ other_field: 'cn'
+ }
+ ]
+ }
+ ];
+
+ //
+ // Users
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'usercategory',
+ widget: 'user.rule.usercategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_user',
+ widget: 'user.rule.memberuser_user',
+ priority: IPA.selinux.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_group',
+ widget: 'user.rule.memberuser_group',
+ priority: IPA.selinux.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'user',
+ label: IPA.messages.objects.selinuxusermap.user,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'usercategory',
+ options: [
+ { value: 'all',
+ label: IPA.messages.objects.selinuxusermap.anyone },
+ { value: '',
+ label: IPA.messages.objects.selinuxusermap.specified_users }
+ ],
+ tables: [
+ { name: 'memberuser_user' },
+ { name: 'memberuser_group' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberuser_user',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberuser_group',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Hosts
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'hostcategory',
+ widget: 'host.rule.hostcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_host',
+ widget: 'host.rule.memberhost_host',
+ priority: IPA.selinux.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_hostgroup',
+ widget: 'host.rule.memberhost_hostgroup',
+ priority: IPA.selinux.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'host',
+ label: IPA.messages.objects.selinuxusermap.host,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'hostcategory',
+ options: [
+ {
+ 'value': 'all',
+ 'label': IPA.messages.objects.selinuxusermap.any_host
+ },
+ {
+ 'value': '',
+ 'label': IPA.messages.objects.selinuxusermap.specified_hosts
+ }
+ ],
+ tables: [
+ { 'name': 'memberhost_host' },
+ { 'name': 'memberhost_hostgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberhost_host',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberhost_hostgroup',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ var that = IPA.details_facet(spec);
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.refresh();
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ that.refresh();
+ };
+
+ return that;
+};
+
+IPA.register('selinuxusermap', IPA.selinux.selinuxusermap_entity); \ No newline at end of file
diff --git a/install/ui/src/freeipa/serverconfig.js b/install/ui/src/freeipa/serverconfig.js
new file mode 100644
index 000000000..517aa7800
--- /dev/null
+++ b/install/ui/src/freeipa/serverconfig.js
@@ -0,0 +1,118 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.serverconfig = {};
+
+IPA.serverconfig.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.details_facet({
+ title: IPA.metadata.objects.config.label,
+ sections: [
+ {
+ name: 'search',
+ label: IPA.messages.objects.config.search,
+ fields: [
+ 'ipasearchrecordslimit',
+ 'ipasearchtimelimit'
+ ]
+ },
+ {
+ name: 'user',
+ label: IPA.messages.objects.config.user,
+ fields: [
+ 'ipausersearchfields',
+ 'ipadefaultemaildomain',
+ {
+ type: 'entity_select',
+ name: 'ipadefaultprimarygroup',
+ other_entity: 'group',
+ other_field: 'cn'
+ },
+ 'ipahomesrootdir',
+ 'ipadefaultloginshell',
+ 'ipamaxusernamelength',
+ 'ipapwdexpadvnotify',
+ {
+ name: 'ipaconfigstring',
+ type: 'checkboxes',
+ options: IPA.create_options([
+ 'AllowLMhash', 'AllowNThash',
+ 'KDC:Disable Last Success', 'KDC:Disable Lockout'
+ ])
+ },
+ {
+ type: 'checkbox',
+ name: 'ipamigrationenabled'
+ },
+ {
+ type: 'multivalued',
+ name: 'ipauserobjectclasses'
+ }
+ ]
+ },
+ {
+ name: 'group',
+ label: IPA.messages.objects.config.group,
+ fields: [
+ 'ipagroupsearchfields',
+ {
+ type: 'multivalued',
+ name: 'ipagroupobjectclasses'
+ }
+ ]
+ },
+ {
+ name: 'selinux',
+ label: IPA.messages.objects.config.selinux,
+ fields: [
+ 'ipaselinuxusermaporder',
+ 'ipaselinuxusermapdefault'
+ ]
+ },
+ {
+ name: 'service',
+ label: IPA.messages.objects.config.service,
+ fields: [
+ {
+ name: 'ipakrbauthzdata',
+ type: 'checkboxes',
+ options: IPA.create_options(['MS-PAC', 'PAD'])
+ }
+ ]
+ }
+ ],
+ needs_update: true
+ });
+ };
+
+ return that;
+};
+
+IPA.register('config', IPA.serverconfig.entity);
diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js
new file mode 100644
index 000000000..04e294bf0
--- /dev/null
+++ b/install/ui/src/freeipa/service.js
@@ -0,0 +1,467 @@
+/*jsl:import ipa.js */
+/*jsl:import certificate.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.service = {};
+
+IPA.service.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [ 'krbprincipalname' ]
+ }).
+ details_facet({
+ factory: IPA.service.details_facet,
+ sections: [
+ {
+ name: 'details',
+ fields: [
+ 'krbprincipalname',
+ {
+ type: 'service_name',
+ name: 'service',
+ label: IPA.messages.objects.service.service,
+ read_only: true
+ },
+ {
+ type: 'service_host',
+ name: 'host',
+ label: IPA.messages.objects.service.host,
+ read_only: true
+ },
+ {
+ name: 'ipakrbauthzdata',
+ type: 'checkboxes',
+ options: IPA.create_options(['MS-PAC', 'PAD'])
+ }
+ ]
+ },
+ {
+ name: 'provisioning',
+ action_panel: {
+ factory: IPA.action_panel,
+ name: 'provisioning_actions',
+ actions: ['unprovision']
+ },
+ fields: [
+ {
+ type: 'service_provisioning_status',
+ name: 'has_keytab',
+ label: IPA.messages.objects.service.status
+ }
+ ]
+ },
+ {
+ name: 'certificate',
+ action_panel: {
+ factory: IPA.action_panel,
+ name: 'cert_actions',
+ actions: [
+ 'request_cert', 'view_cert', 'get_cert',
+ 'revoke_cert', 'restore_cert'
+ ]
+ },
+ fields: [
+ {
+ type: 'certificate_status',
+ name: 'certificate_status',
+ label: IPA.messages.objects.service.status
+ }
+ ]
+ }
+ ],
+ actions: [
+ IPA.service.unprovision_action,
+ IPA.cert.view_action,
+ IPA.cert.get_action,
+ IPA.cert.request_action,
+ IPA.cert.revoke_action,
+ IPA.cert.restore_action
+ ],
+ state: {
+ evaluators: [
+ IPA.service.has_keytab_evaluator,
+ IPA.service.krbprincipalkey_acl_evaluator,
+ IPA.cert.certificate_evaluator
+ ]
+ },
+ policies: [
+ IPA.service.certificate_policy()
+ ]
+ }).
+ association_facet({
+ name: 'managedby_host',
+ add_method: 'add_host',
+ remove_method: 'remove_host'
+ }).
+ standard_association_facets().
+ adder_dialog({
+ factory: IPA.service_adder_dialog,
+ height: 350,
+ sections: [
+ {
+ fields: [
+ {
+ type: 'combobox',
+ name: 'service',
+ label: IPA.messages.objects.service.service,
+ options: [
+ 'cifs',
+ 'DNS',
+ 'ftp',
+ 'HTTP',
+ 'imap',
+ 'ldap',
+ 'libvirt',
+ 'nfs',
+ 'smtp',
+ 'qpidd'
+ ],
+ editable: true,
+ size: 10,
+ required: true,
+ z_index: 2
+ },
+ {
+ type: 'entity_select',
+ name: 'host',
+ other_entity: 'host',
+ other_field: 'fqdn',
+ label: IPA.messages.objects.service.host,
+ required: true,
+ z_index: 1
+ },
+ {
+ type: 'checkbox',
+ name: 'force',
+ metadata: IPA.get_command_option('service_add', 'force')
+ }
+ ]
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.service.details_facet = function(spec, no_init) {
+
+ var that = IPA.details_facet(spec, true);
+ that.certificate_loaded = IPA.observer();
+
+ if (!no_init) that.init_details_facet();
+
+ return that;
+};
+
+IPA.service_adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ var init = function() {
+
+ //small hack - krbprincipalname should not be displayed. This way
+ //creation of associated widget is skipped.
+ //In future it would be better split section definion into widget and
+ //fields definition and create custom field with two associated
+ //widgets - 'service' and 'host' with this dialog's save logic.
+ that.builder.build_field({
+ type: 'field',
+ name: 'krbprincipalname',
+ required: false
+ });
+ };
+
+ that.save = function(record) {
+
+ var field = that.fields.get_field('service');
+ var service = field.save()[0];
+
+ field = that.fields.get_field('host');
+ var host = field.save()[0];
+
+ record['krbprincipalname'] = [ service+'/'+host ];
+
+ field = that.fields.get_field('force');
+ record['force'] = field.save();
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.service_name_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.load = function(record) {
+
+ that.field_load(record);
+
+ var krbprincipalname = record.krbprincipalname[0];
+ var value = krbprincipalname.replace(/\/.*$/, '');
+ that.values = [value];
+
+ that.reset();
+ };
+
+ return that;
+};
+
+IPA.field_factories['service_name'] = IPA.service_name_field;
+IPA.widget_factories['service_name'] = IPA.text_widget;
+
+
+IPA.service_host_field = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.field(spec);
+
+ that.load = function(record) {
+
+ that.field_load(record);
+
+ var krbprincipalname = record.krbprincipalname[0];
+ var value = krbprincipalname.replace(/^.*\//, '').replace(/@.*$/, '');
+ that.values = [value];
+
+ that.reset();
+ };
+
+ return that;
+};
+
+IPA.field_factories['service_host'] = IPA.service_host_field;
+IPA.widget_factories['service_host'] = IPA.text_widget;
+
+IPA.service_provisioning_status_widget = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.status_valid = $('<div/>', {
+ name: 'kerberos-key-valid',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/check-icon.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(that.status_valid);
+
+ var content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(that.status_valid);
+
+ content_div.append('<b>'+IPA.messages.objects.service.valid+'</b>');
+
+ that.status_missing = $('<div/>', {
+ name: 'kerberos-key-missing',
+ style: 'display: none;'
+ }).appendTo(container);
+
+ $('<img/>', {
+ src: 'images/caution-icon.png',
+ style: 'float: left;',
+ 'class': 'status-icon'
+ }).appendTo(that.status_missing);
+
+ content_div = $('<div/>', {
+ style: 'float: left;'
+ }).appendTo(that.status_missing);
+
+ content_div.append('<b>'+IPA.messages.objects.service.missing+'</b>');
+ };
+
+ that.update = function(values) {
+ that.status = values && values.length ? values[0] : false;
+ set_status(that.status ? 'valid' : 'missing');
+ };
+
+ that.clear = function() {
+ that.status_valid.css('display', 'none');
+ that.status_missing.css('display', 'none');
+ };
+
+ function set_status(status) {
+ that.status_valid.css('display', status == 'valid' ? 'inline' : 'none');
+ that.status_missing.css('display', status == 'missing' ? 'inline' : 'none');
+ }
+
+ return that;
+};
+
+IPA.field_factories['service_provisioning_status'] = IPA.field;
+IPA.widget_factories['service_provisioning_status'] = IPA.service_provisioning_status_widget;
+
+
+IPA.service.unprovision_dialog = function(spec) {
+
+ spec = spec || {};
+ spec.title = spec.title || IPA.messages.objects.service.unprovision_title;
+
+ var that = IPA.dialog(spec);
+ that.facet = spec.facet;
+
+ var entity_singular = that.entity.metadata.label_singular;
+ that.title = that.title.replace('${entity}', entity_singular);
+
+ that.create = function() {
+ that.container.append(IPA.messages.objects.service.unprovision_confirmation);
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'unprovision',
+ label: IPA.messages.objects.service.unprovision,
+ click: function() {
+ that.unprovision();
+ }
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+ };
+
+ that.unprovision = function() {
+
+ var principal_f = that.facet.fields.get_field('krbprincipalname');
+ var pkey = principal_f.values[0];
+
+ IPA.command({
+ entity: that.entity.name,
+ method: 'disable',
+ args: [pkey],
+ on_success: function(data, text_status, xhr) {
+ that.facet.refresh();
+ that.close();
+ IPA.notify_success(IPA.messages.objects.service.unprovisioned);
+ },
+ on_error: function(xhr, text_status, error_thrown) {
+ that.close();
+ }
+ }).execute();
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.service.unprovision_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'unprovision';
+ spec.label = spec.label || IPA.messages.objects.service.delete_key_unprovision;
+ spec.enable_cond = spec.enable_cond || ['has_keytab', 'krbprincipalkey_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var dialog = IPA.service.unprovision_dialog({
+ entity: facet.entity,
+ facet: facet
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.service.krbprincipalkey_acl_evaluator = function(spec) {
+
+ spec.name = spec.name || 'unprovision_acl_evaluator';
+ spec.attribute = spec.attribute || 'krbprincipalkey';
+
+ var that = IPA.acl_state_evaluator(spec);
+ return that;
+};
+
+IPA.service.has_keytab_evaluator = function(spec) {
+
+ spec.name = spec.name || 'has_keytab_evaluator';
+ spec.attribute = spec.attribute || 'has_keytab';
+ spec.value = spec.value || [true];
+ spec.representation = spec.representation || 'has_keytab';
+
+ var that = IPA.value_state_evaluator(spec);
+ return that;
+};
+
+IPA.service.certificate_policy = function(spec) {
+
+ spec = spec || {};
+
+ function get_pkey(result) {
+ var values = result.krbprincipalname;
+ return values ? values[0] : null;
+ }
+
+ spec.get_pkey = spec.get_pkey || get_pkey;
+
+ spec.get_name = spec.get_name || function(result) {
+ var value = get_pkey(result);
+ return value ? value.replace(/@.*$/, '') : null;
+ };
+
+ spec.get_principal = spec.get_principal || get_pkey;
+
+ spec.get_hostname = spec.get_hostname || function(result) {
+ var value = get_pkey(result);
+ if (value) {
+ value = value.replace(/@.*$/, '').replace(/^.*\//, '');
+ }
+ return value;
+ };
+
+ var that = IPA.cert.load_policy(spec);
+ return that;
+};
+
+IPA.register('service', IPA.service.entity);
diff --git a/install/ui/src/freeipa/sudo.js b/install/ui/src/freeipa/sudo.js
new file mode 100644
index 000000000..fddcda0b5
--- /dev/null
+++ b/install/ui/src/freeipa/sudo.js
@@ -0,0 +1,930 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.sudo = {
+ //priority of commands in details facet
+ remove_method_priority: IPA.config.default_priority - 1
+};
+
+IPA.sudo.rule_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ row_enabled_attribute: 'ipaenabledflag',
+ columns: [
+ 'cn',
+ {
+ name: 'ipaenabledflag',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter()
+ },
+ 'description'
+ ],
+ actions: [
+ IPA.batch_disable_action,
+ IPA.batch_enable_action
+ ],
+ control_buttons: [
+ {
+ name: 'disable',
+ label: IPA.messages.buttons.disable,
+ icon: 'disabled-icon'
+ },
+ {
+ name: 'enable',
+ label: IPA.messages.buttons.enable,
+ icon: 'enabled-icon'
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.sudorule_details_facet,
+ entity: that,
+ command_mode: 'info',
+ actions: [
+ IPA.select_action,
+ IPA.enable_action,
+ IPA.disable_action,
+ IPA.delete_action
+ ],
+ header_actions: ['select_action', 'enable', 'disable', 'delete'],
+ state: {
+ evaluators: [
+ {
+ factory: IPA.enable_state_evaluator,
+ field: 'ipaenabledflag'
+ }
+ ],
+ summary_conditions: [
+ IPA.enabled_summary_cond(),
+ IPA.disabled_summary_cond()
+ ]
+ }
+ }).
+ adder_dialog({
+ fields: [ 'cn' ]
+ });
+ };
+
+ return that;
+};
+
+IPA.sudo.command_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'sudocmd',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'sudocmd',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'memberof_sudocmdgroup',
+ associator: IPA.serial_associator,
+ columns:[
+ 'cn',
+ 'description'
+ ],
+ adder_columns: [
+ {
+ name: 'cn',
+ primary_key: true,
+ width: '100px'
+ },
+ {
+ name: 'description',
+ width: '100px'
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'sudocmd',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.sudo.command_group_entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn',
+ 'description'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'general',
+ label: IPA.messages.details.general,
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ]
+ }).
+ association_facet({
+ name: 'member_sudocmd',
+ columns: [
+ 'sudocmd',
+ 'description'
+ ],
+ adder_columns: [
+ {
+ name: 'sudocmd',
+ primary_key: true,
+ width: '100px'
+ },
+ {
+ name: 'description',
+ width: '100px'
+ }
+ ]
+ }).
+ standard_association_facets().
+ adder_dialog({
+ fields: [
+ 'cn',
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.sudorule_details_facet = function(spec) {
+
+ var entity_name = spec.entity.name;
+
+ //
+ // General
+ //
+
+ spec.fields = [
+ {
+ name: 'cn',
+ read_only: true,
+ widget: 'general.cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description',
+ widget: 'general.description'
+ }
+ ];
+
+ spec.widgets = [
+ {
+ type: 'details_table_section',
+ name: 'general',
+ label: IPA.messages.details.general,
+ widgets: [
+ {
+ name: 'cn'
+ },
+ {
+ type: 'textarea',
+ name: 'description'
+ }
+ ]
+ }
+ ];
+
+ //
+ // Options
+ //
+
+ spec.fields.push(
+ {
+ name: 'ipasudoopt',
+ widget: 'options.ipasudoopt'
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.sudo.options_section,
+ name: 'options',
+ label: IPA.messages.objects.sudorule.options,
+ facet: that
+ }
+ );
+
+ //
+ // Users
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'usercategory',
+ widget: 'user.rule.usercategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_user',
+ widget: 'user.rule.memberuser_user',
+ external: 'externaluser',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberuser_group',
+ widget: 'user.rule.memberuser_group',
+ priority: IPA.sudo.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'user',
+ label: IPA.messages.objects.sudorule.user,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'usercategory',
+ options: [
+ {
+ value: 'all',
+ label: IPA.messages.objects.sudorule.anyone
+ },
+ {
+ value: '',
+ label: IPA.messages.objects.sudorule.specified_users
+ }
+ ],
+ tables: [
+ { name: 'memberuser_user' },
+ { name: 'memberuser_group' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberuser_user',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ external: 'externaluser',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberuser_group',
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Hosts
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'hostcategory',
+ widget: 'host.rule.hostcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_host',
+ widget: 'host.rule.memberhost_host',
+ external: 'externalhost',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberhost_hostgroup',
+ widget: 'host.rule.memberhost_hostgroup',
+ priority: IPA.sudo.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'host',
+ label: IPA.messages.objects.sudorule.host,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'hostcategory',
+ options: [
+ {
+ 'value': 'all',
+ 'label': IPA.messages.objects.sudorule.any_host
+ },
+ {
+ 'value': '',
+ 'label': IPA.messages.objects.sudorule.specified_hosts
+ }
+ ],
+ tables: [
+ { 'name': 'memberhost_host' },
+ { 'name': 'memberhost_hostgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_user',
+ name: 'memberhost_host',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ external: 'externalhost',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberuser_group',
+ name: 'memberhost_hostgroup',
+ add_method: 'add_host',
+ remove_method: 'remove_host',
+ add_title: IPA.messages.association.add.member,
+ remove_title: IPA.messages.association.remove.member
+ }
+ ]
+ }
+ ]
+ }
+ );
+
+ //
+ // Run Commands
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'cmdcategory',
+ widget: 'command.rule.cmdcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberallowcmd_sudocmd',
+ widget: 'command.rule.memberallowcmd_sudocmd',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberallowcmd_sudocmdgroup',
+ widget: 'command.rule.memberallowcmd_sudocmdgroup',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberdenycmd_sudocmd',
+ widget: 'command.memberdenycmd_sudocmd',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'memberdenycmd_sudocmdgroup',
+ widget: 'command.memberdenycmd_sudocmdgroup',
+ priority: IPA.sudo.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'command',
+ label: IPA.messages.objects.sudorule.command,
+ widgets: [
+ {
+ factory: IPA.header_widget,
+ name: 'allow_header',
+ text: IPA.messages.objects.sudorule.allow,
+ description: IPA.messages.objects.sudorule.allow
+ },
+ {
+ factory: IPA.rule_details_widget,
+ name: 'rule',
+ radio_name: 'cmdcategory',
+ options: [
+ {
+ value: 'all',
+ label: IPA.messages.objects.sudorule.any_command
+ },
+ {
+ value: '',
+ label: IPA.messages.objects.sudorule.specified_commands
+ }
+ ],
+ tables: [
+ { name: 'memberallowcmd_sudocmd' },
+ { name: 'memberallowcmd_sudocmdgroup' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberallowcmd_sudocmd',
+ name: 'memberallowcmd_sudocmd',
+ add_method: 'add_allow_command',
+ remove_method: 'remove_allow_command',
+ add_title: IPA.messages.association.add.memberallowcmd,
+ remove_title: IPA.messages.association.remove.memberallowcmd
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberallowcmd_sudocmdgroup',
+ name: 'memberallowcmd_sudocmdgroup',
+ add_method: 'add_allow_command',
+ remove_method: 'remove_allow_command',
+ add_title: IPA.messages.association.add.memberallowcmd,
+ remove_title: IPA.messages.association.remove.memberallowcmd
+ }
+ ]
+ },
+ {
+ factory: IPA.header_widget,
+ name: 'deny_header',
+ text: IPA.messages.objects.sudorule.deny,
+ description: IPA.messages.objects.sudorule.deny
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberdenycmd_sudocmd',
+ name: 'memberdenycmd_sudocmd',
+ add_method: 'add_deny_command',
+ remove_method: 'remove_deny_command',
+ add_title: IPA.messages.association.add.memberdenycmd,
+ remove_title: IPA.messages.association.remove.memberdenycmd
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-memberdenycmd_sudocmdgroup',
+ name: 'memberdenycmd_sudocmdgroup',
+ add_method: 'add_deny_command',
+ remove_method: 'remove_deny_command',
+ add_title: IPA.messages.association.add.memberdenycmd,
+ remove_title: IPA.messages.association.remove.memberdenycmd
+ }
+ ]
+ }
+ );
+
+ //
+ // As whom
+ //
+
+ spec.fields.push(
+ {
+ type: 'radio',
+ name: 'ipasudorunasusercategory',
+ widget: 'runas.runas_users.ipasudorunasusercategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'ipasudorunas_user',
+ widget: 'runas.runas_users.ipasudorunas_user',
+ external: 'ipasudorunasextuser',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'rule_association_table',
+ name: 'ipasudorunas_group',
+ widget: 'runas.runas_users.ipasudorunas_group',
+ priority: IPA.sudo.remove_method_priority
+ },
+ {
+ type: 'radio',
+ name: 'ipasudorunasgroupcategory',
+ widget: 'runas.runas_groups.ipasudorunasgroupcategory'
+ },
+ {
+ type: 'rule_association_table',
+ name: 'ipasudorunasgroup_group',
+ widget: 'runas.runas_groups.ipasudorunasgroup_group',
+ external: 'ipasudorunasextgroup',
+ priority: IPA.sudo.remove_method_priority
+ }
+ );
+
+ spec.widgets.push(
+ {
+ factory: IPA.collapsible_section,
+ name: 'runas',
+ label: IPA.messages.objects.sudorule.runas,
+ widgets: [
+ {
+ factory: IPA.rule_details_widget,
+ name: 'runas_users',
+ radio_name: 'ipasudorunasusercategory',
+ options: [
+ { value: 'all', label: IPA.messages.objects.sudorule.anyone },
+ { value: '', label: IPA.messages.objects.sudorule.specified_users }
+ ],
+ tables: [
+ { name: 'ipasudorunas_user' },
+ { name: 'ipasudorunas_group' }
+ ],
+ widgets: [
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-runasruser_user',
+ name: 'ipasudorunas_user',
+ external: 'ipasudorunasextuser',
+ add_method: 'add_runasuser',
+ remove_method: 'remove_runasuser',
+ add_title: IPA.messages.association.add.ipasudorunas,
+ remove_title: IPA.messages.association.remove.ipasudorunas
+ },
+ {
+ type: 'rule_association_table',
+ id: entity_name+'-runasuser_group',
+ name: 'ipasudorunas_group',
+ add_method: 'add_runasuser',
+ remove_method: 'remove_runasuser',
+ add_title: IPA.messages.association.add.ipasudorunas,
+ remove_title: IPA.messages.association.remove.ipasudorunas
+ }
+ ]
+ },
+ {
+ factory: IPA.rule_details_widget,
+ name: 'runas_groups',
+ radio_name: 'ipasudorunasgroupcategory',
+ options: [
+ { value: 'all', label: IPA.messages.objects.sudorule.any_group },
+ { value: '', label: IPA.messages.objects.sudorule.specified_groups }
+ ],
+ tables: [
+ { name: 'ipasudorunasgroup_group' }
+ ],
+ widgets: [{
+ type: 'rule_association_table',
+ id: entity_name+'-runasgroup_group',
+ name: 'ipasudorunasgroup_group',
+ external: 'ipasudorunasextgroup',
+ add_method: 'add_runasgroup',
+ remove_method: 'remove_runasgroup',
+ add_title: IPA.messages.association.add.ipasudorunasgroup,
+ remove_title: IPA.messages.association.remove.ipasudorunasgroup
+ }]
+ }
+ ]
+ }
+ );
+
+ var that = IPA.details_facet(spec);
+
+ var init = function() {
+ var options = that.widgets.get_widget('options');
+ options.facet = that;
+ };
+
+ that.update_on_success = function(data, text_status, xhr) {
+ that.refresh();
+ that.on_update.notify();
+ that.nofify_update_success();
+ };
+
+ that.update_on_error = function(xhr, text_status, error_thrown) {
+ that.refresh();
+ };
+
+ init();
+
+ return that;
+};
+
+IPA.sudo.options_section = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.collapsible_section(spec);
+
+ function setup_table(){
+ that.table = IPA.table_widget({
+ name: 'ipasudoopt',
+ show_buttons: true
+ });
+
+ that.widgets.add_widget(that.table);
+
+ that.table.create_column({
+ name: 'ipasudoopt',
+ label: IPA.get_command_option('sudorule_add_option', 'ipasudoopt').label,
+ entity: that.entity,
+ primary_key: true
+ });
+
+ that.table.create = function(container) {
+
+ that.table.table_create(container);
+
+ that.remove_button = IPA.action_button({
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon',
+ 'class': 'action-button-disabled',
+ click: function() {
+ if (!that.remove_button.hasClass('action-button-disabled')) {
+ that.remove_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.table.buttons);
+
+ that.add_button = IPA.action_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon',
+ click: function() {
+ if (!that.add_button.hasClass('action-button-disabled')) {
+ that.add_handler();
+ }
+ return false;
+ }
+ }).appendTo(that.table.buttons);
+ };
+
+ that.table.select_changed = function() {
+
+ var values = that.table.get_selected_values();
+
+ if (that.remove_button) {
+ if (values.length === 0) {
+ that.remove_button.addClass('action-button-disabled');
+ } else {
+ that.remove_button.removeClass('action-button-disabled');
+ }
+ }
+ };
+
+ that.table.update = function(values) {
+
+ that.table.empty();
+
+ for (var i=0; i<values.length; i++) {
+ var value = values[i];
+ if(!value || value === '') continue;
+
+ var record = {
+ ipasudoopt: values[i]
+ };
+ that.table.add_record(record);
+ }
+
+ that.table.unselect_all();
+ };
+ }
+
+ that.add_handler = function() {
+ if (that.facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ facet: that.facet
+ });
+
+ dialog.callback = function() {
+ that.show_add_dialog();
+ };
+ dialog.open(that.container);
+
+ } else {
+ that.show_add_dialog();
+ }
+ };
+
+ that.remove_handler = function() {
+ if (that.facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ facet: that.facet
+ });
+
+ dialog.callback = function() {
+ that.show_remove_dialog();
+ };
+ dialog.open(that.container);
+
+ } else {
+ that.show_remove_dialog();
+ }
+ };
+
+ that.show_add_dialog = function() {
+
+ var label = IPA.get_command_option('sudorule_add_option', 'ipasudoopt').label;
+
+ var title = IPA.messages.dialogs.add_title;
+ title = title.replace('${entity}', label);
+
+ var dialog = IPA.dialog({
+ name: 'option-adder-dialog',
+ title: title,
+ sections: [
+ {
+ fields: [
+ {
+ name: 'ipasudoopt',
+ label: label
+ }
+ ]
+ }
+ ]
+ });
+
+ dialog.create_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ click: function() {
+ var ipasudoopt = dialog.fields.get_field('ipasudoopt');
+ var value = ipasudoopt.save()[0];
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var command = IPA.command({
+ entity: 'sudorule',
+ method: 'add_option',
+ args: [pkey],
+ options: {
+ ipasudoopt: value
+ },
+ on_success: function(data) {
+ that.table.load(data.result.result);
+ dialog.close();
+ IPA.notify_success(IPA.messages.objects.sudorule.option_added);
+ },
+ on_error: function(data) {
+ that.reload();
+ dialog.close();
+ }
+ });
+
+ command.execute();
+ }
+ });
+
+ dialog.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ dialog.close();
+ }
+ });
+
+ dialog.open(that.container);
+ };
+
+ that.show_remove_dialog = function() {
+
+ var label = IPA.get_command_option('sudorule_add_option', 'ipasudoopt').label;
+ var values = that.table.get_selected_values();
+
+ if (!values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return;
+ }
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var title = IPA.messages.dialogs.remove_title;
+ title = title.replace('${entity}', label);
+
+ var dialog = IPA.deleter_dialog({
+ title: title,
+ values: values
+ });
+
+ dialog.execute = function() {
+
+ var batch = IPA.batch_command({
+ on_success: function(data) {
+ //last successful result of batch results contains valid data
+ var result;
+ for(var i = data.result.results.length - 1; i > -1; i--) {
+ result = data.result.results[i].result;
+ if(result) break;
+ }
+
+ if(result) {
+ that.table.load(result);
+ } else {
+ that.reload();
+ }
+
+ IPA.notify_success(IPA.messages.objects.sudorule.option_removed);
+ },
+ on_error: function(data) {
+ that.reload();
+ }
+ });
+
+ for (var i=0; i<values.length; i++) {
+ var command = IPA.command({
+ entity: 'sudorule',
+ method: 'remove_option',
+ args: [pkey]
+ });
+
+ command.set_option('ipasudoopt', values[i]);
+
+ batch.add_command(command);
+ }
+
+ batch.execute();
+ };
+
+ dialog.open(that.container);
+ };
+
+ that.reload = function() {
+ var command = IPA.command({
+ entity: that.facet.entity.name,
+ method: 'show',
+ args: that.facet.get_primary_key(true),
+ on_success: function(data) {
+ that.table.load(data.result.result);
+ }
+ });
+
+ command.execute();
+ };
+
+ /*initialization*/
+ setup_table();
+
+ return that;
+};
+
+IPA.register('sudorule', IPA.sudo.rule_entity);
+IPA.register('sudocmd', IPA.sudo.command_entity);
+IPA.register('sudocmdgroup', IPA.sudo.command_group_entity);
diff --git a/install/ui/src/freeipa/trust.js b/install/ui/src/freeipa/trust.js
new file mode 100644
index 000000000..939bb59a3
--- /dev/null
+++ b/install/ui/src/freeipa/trust.js
@@ -0,0 +1,183 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.trust = {};
+
+IPA.trust.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ that.builder.search_facet({
+ columns: [
+ 'cn'
+ ]
+ }).
+ details_facet({
+ sections: [
+ {
+ name: 'details',
+ label: IPA.messages.objects.trust.details,
+ fields: [
+ 'cn',
+ {
+ name: 'ipantflatname',
+ label: IPA.messages.objects.trust.ipantflatname,
+ read_only: true
+ },
+ {
+ name: 'ipanttrusteddomainsid',
+ label: IPA.messages.objects.trust.ipanttrusteddomainsid,
+ read_only: true
+ },
+ {
+ name: 'trustdirection',
+ label: IPA.messages.objects.trust.trustdirection
+ },
+ {
+ name: 'trusttype',
+ label: IPA.messages.objects.trust.trusttype
+ }
+// trust status not supported by show command at the moment
+// {
+// name: 'truststatus',
+// label: IPA.messages.objects.trust.truststatus
+// }
+ ]
+ }
+ ]
+ }).
+ adder_dialog({
+ factory: IPA.trust.adder_dialog,
+ fields: [
+ {
+ name: 'cn',
+ label: IPA.messages.objects.trust.domain,
+ widget: 'realm.realm_server'
+ },
+ {
+ name: 'realm_admin',
+ label: IPA.messages.objects.trust.account,
+ widget: 'method.realm_admin'
+ },
+ {
+ type: 'password',
+ name: 'realm_passwd',
+ label: IPA.messages.password.password,
+ widget: 'method.realm_passwd'
+ },
+ {
+ type: 'password',
+ name: 'trust_secret',
+ label: IPA.messages.password.password,
+ widget: 'method.trust_secret'
+ },
+ {
+ type: 'password',
+ name: 'trust_secret_verify',
+ label: IPA.messages.password.verify_password,
+ widget: 'method.trust_secret_verify',
+ flags: ['no_command'],
+ validators: [IPA.same_password_validator({
+ other_field: 'trust_secret'
+ })]
+ }
+ ],
+ widgets: [
+ {
+ type: 'details_table_section_nc',
+ name: 'realm',
+ widgets: [
+ 'realm_server'
+ ]
+ },
+ {
+ type: 'multiple_choice_section',
+ name: 'method',
+ label: IPA.messages.objects.trust.establish_using,
+ choices: [
+ {
+ name: 'admin-account',
+ label: IPA.messages.objects.trust.admin_account,
+ fields: ['realm_admin', 'realm_passwd'],
+ required: ['realm_admin', 'realm_passwd'],
+ enabled: true
+ },
+ {
+ name: 'preshared_password',
+ label: IPA.messages.objects.trust.preshared_password,
+ fields: ['trust_secret', 'trust_secret_verify'],
+ required: ['trust_secret', 'trust_secret_verify']
+ }
+ ],
+ widgets: [
+ {
+ name: 'realm_admin'
+ },
+ {
+ type: 'password',
+ name: 'realm_passwd'
+ },
+ {
+ type: 'password',
+ name: 'trust_secret'
+ },
+ {
+ type: 'password',
+ name: 'trust_secret_verify'
+ }
+ ]
+ }
+ ],
+ policies: [
+ IPA.multiple_choice_section_policy({
+ widget: 'method'
+ })
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.trust.adder_dialog = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.get_success_message = function(data) {
+ return that.entity_adder_dialog_get_success_message(data) + '. ' + data.result.result.truststatus[0];
+ };
+
+ that.notify_success = function(data) {
+ IPA.notify_success(that.get_success_message(data), 5000);
+ };
+
+ return that;
+};
+
+IPA.register('trust', IPA.trust.entity);
diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js
new file mode 100644
index 000000000..ac51db2ba
--- /dev/null
+++ b/install/ui/src/freeipa/user.js
@@ -0,0 +1,663 @@
+/*jsl:import ipa.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js, details.js, search.js, add.js, facet.js, entity.js */
+
+IPA.user = {};
+
+IPA.user.entity = function(spec) {
+
+ var that = IPA.entity(spec);
+
+ that.init = function() {
+ that.entity_init();
+
+ var self_service = IPA.nav.name === 'self-service';
+ var link = self_service ? false : undefined;
+
+ that.builder.search_facet({
+ row_disabled_attribute: 'nsaccountlock',
+ columns: [
+ 'uid',
+ 'givenname',
+ 'sn',
+ {
+ name: 'nsaccountlock',
+ label: IPA.messages.status.label,
+ formatter: IPA.boolean_status_formatter({
+ invert_value: true
+ })
+ },
+ 'uidnumber',
+ 'mail',
+ 'telephonenumber',
+ 'title'
+ ],
+ actions: [
+ {
+ factory: IPA.batch_disable_action,
+ hide_cond: ['self-service']
+ },
+ {
+ factory: IPA.batch_enable_action,
+ hide_cond: ['self-service']
+ }
+ ],
+ control_buttons: [
+ {
+ name: 'disable',
+ label: IPA.messages.buttons.disable,
+ icon: 'disabled-icon'
+ },
+ {
+ name: 'enable',
+ label: IPA.messages.buttons.enable,
+ icon: 'enabled-icon'
+ }
+ ]
+ }).
+ details_facet({
+ factory: IPA.user.details_facet,
+ sections: [
+ {
+ name: 'identity',
+ label: IPA.messages.details.identity,
+ fields: [
+ 'title',
+ 'givenname',
+ 'sn',
+ 'cn',
+ 'displayname',
+ 'initials'
+ ]
+ },
+ {
+ name: 'account',
+ action_panel: {
+ factory: IPA.action_panel,
+ name: 'account_actions',
+ actions: ['reset_password']
+ },
+ fields: [
+ 'uid',
+ {
+ factory: IPA.user_password_widget,
+ name: 'has_password',
+ metadata: IPA.get_entity_param('user', 'userpassword')
+ },
+ {
+ name: 'krbpasswordexpiration',
+ label: IPA.messages.objects.user.krbpasswordexpiration,
+ read_only: true,
+ formatter: IPA.utc_date_formatter()
+ },
+ 'uidnumber',
+ 'gidnumber',
+ 'loginshell',
+ 'homedirectory',
+ {
+ type: 'sshkeys',
+ name: 'ipasshpubkey',
+ label: IPA.messages.objects.sshkeystore.keys
+ }
+ ]
+ },
+ {
+ name: 'pwpolicy',
+ label: IPA.messages.objects.pwpolicy.identity,
+ fields: [
+ {
+ name: 'krbmaxpwdlife',
+ label: IPA.get_entity_param('pwpolicy', 'krbmaxpwdlife').label,
+ read_only: true
+ },
+ {
+ name: 'krbminpwdlife',
+ label: IPA.get_entity_param('pwpolicy', 'krbminpwdlife').label,
+ read_only: true
+ },
+ {
+ name: 'krbpwdhistorylength',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdhistorylength').label,
+ read_only: true,
+ measurement_unit: 'number_of_passwords'
+ },
+ {
+ name: 'krbpwdmindiffchars',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdmindiffchars').label,
+ read_only: true
+ },
+ {
+ name: 'krbpwdminlength',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdminlength').label,
+ read_only: true
+ },
+ {
+ name: 'krbpwdmaxfailure',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdmaxfailure').label,
+ read_only: true
+ },
+ {
+ name: 'krbpwdfailurecountinterval',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdfailurecountinterval').label,
+ read_only: true,
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbpwdlockoutduration',
+ label: IPA.get_entity_param('pwpolicy', 'krbpwdlockoutduration').label,
+ read_only: true,
+ measurement_unit: 'seconds'
+ }
+ ]
+ },
+ {
+ name: 'krbtpolicy',
+ label: IPA.messages.objects.krbtpolicy.identity,
+ fields: [
+ {
+ name: 'krbmaxrenewableage',
+ label: IPA.get_entity_param('krbtpolicy', 'krbmaxrenewableage').label,
+ read_only: true,
+ measurement_unit: 'seconds'
+ },
+ {
+ name: 'krbmaxticketlife',
+ label: IPA.get_entity_param('krbtpolicy', 'krbmaxticketlife').label,
+ read_only: true,
+ measurement_unit: 'seconds'
+ }
+ ]
+ },
+ {
+ name: 'contact',
+ fields: [
+ { type: 'multivalued', name: 'mail' },
+ { type: 'multivalued', name: 'telephonenumber' },
+ { type: 'multivalued', name: 'pager' },
+ { type: 'multivalued', name: 'mobile' },
+ { type: 'multivalued', name: 'facsimiletelephonenumber' }
+ ]
+ },
+ {
+ name: 'mailing',
+ fields: ['street', 'l', 'st', 'postalcode']
+ },
+ {
+ name: 'employee',
+ fields: [
+ 'ou',
+ {
+ type: 'entity_select',
+ name: 'manager',
+ other_entity: 'user',
+ other_field: 'uid'
+ }
+ ]
+ },
+ {
+ name: 'misc',
+ fields: [ 'carlicense' ]
+ }
+ ],
+ actions: [
+ IPA.select_action,
+ IPA.enable_action,
+ IPA.disable_action,
+ IPA.delete_action,
+ IPA.user.reset_password_action
+ ],
+ header_actions: ['select_action', 'enable', 'disable', 'delete'],
+ state: {
+ evaluators: [
+ {
+ factory: IPA.enable_state_evaluator,
+ field: 'nsaccountlock',
+ invert_value: true
+ },
+ IPA.user.reset_password_acl_evaluator
+ ],
+ summary_conditions: [
+ IPA.enabled_summary_cond(),
+ IPA.disabled_summary_cond()
+ ]
+ }
+ }).
+ association_facet({
+ name: 'memberof_group',
+ associator: IPA.serial_associator,
+ link: link,
+ read_only: self_service
+ }).
+ association_facet({
+ name: 'memberof_netgroup',
+ associator: IPA.serial_associator,
+ link: link,
+ read_only: self_service
+ }).
+ association_facet({
+ name: 'memberof_role',
+ associator: IPA.serial_associator,
+ link: link,
+ read_only: self_service
+ }).
+ association_facet({
+ name: 'memberof_hbacrule',
+ associator: IPA.serial_associator,
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ link: link,
+ read_only: self_service
+ }).
+ association_facet({
+ name: 'memberof_sudorule',
+ associator: IPA.serial_associator,
+ add_method: 'add_user',
+ remove_method: 'remove_user',
+ link: link,
+ read_only: self_service
+ }).
+ standard_association_facets({
+ link: link
+ }).
+ adder_dialog({
+ factory: IPA.user_adder_dialog,
+ sections: [
+ {
+ fields: [
+ {
+ name: 'uid',
+ required: false
+ },
+ 'givenname',
+ 'sn'
+ ]
+ },
+ {
+ fields: [
+ {
+ name: 'userpassword',
+ label: IPA.messages.password.new_password,
+ type: 'password'
+ },
+ {
+ name: 'userpassword2',
+ label: IPA.messages.password.verify_password,
+ type: 'password'
+ }
+ ]
+ }
+ ]
+ });
+ };
+
+ return that;
+};
+
+IPA.user.details_facet = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.details_facet(spec);
+
+ that.refresh_on_success = function(data, text_status, xhr) {
+ // do not load data from batch
+
+ that.show_content();
+ };
+
+ that.create_refresh_command = function() {
+
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+
+ var batch = IPA.batch_command({
+ name: 'user_details_refresh'
+ });
+
+ var user_command = that.details_facet_create_refresh_command();
+
+ user_command.on_success = function(data, text_status, xhr) {
+ // create data that mimics user-show output
+ var user_data = {};
+ user_data.result = data;
+ that.load(user_data);
+ };
+
+ batch.add_command(user_command);
+
+ var pwpolicy_command = IPA.command({
+ entity: 'pwpolicy',
+ method: 'show',
+ options: {
+ user: pkey,
+ all: true,
+ rights: true
+ }
+ });
+
+ pwpolicy_command.on_success = function(data, text_status, xhr) {
+ // TODO: Use nested fields: that.fields.get_field('pwpolicy').get_fields();
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+
+ // load result into pwpolicy fields
+ if (field.widget_name.match(/^pwpolicy\./)) {
+ field.load(data.result);
+ }
+ }
+ };
+
+ batch.add_command(pwpolicy_command);
+
+ var krbtpolicy_command = IPA.command({
+ entity: 'krbtpolicy',
+ method: 'show',
+ args: [ pkey ],
+ options: {
+ all: true,
+ rights: true
+ }
+ });
+
+ krbtpolicy_command.on_success = function(data, text_status, xhr) {
+ // TODO: Use nested fields: that.fields.get_field('krbtpolicy').get_fields();
+ var fields = that.fields.get_fields();
+ for (var i=0; i<fields.length; i++) {
+ var field = fields[i];
+
+ // load result into krbtpolicy fields
+ if (field.widget_name.match(/^krbtpolicy\./)) {
+ field.load(data.result);
+ }
+ }
+ };
+
+ batch.add_command(krbtpolicy_command);
+
+ return batch;
+ };
+
+ return that;
+};
+
+IPA.user_adder_dialog = function(spec) {
+
+ var that = IPA.entity_adder_dialog(spec);
+
+ that.validate = function() {
+ var valid = that.dialog_validate();
+
+ var field1 = that.fields.get_field('userpassword');
+ var field2 = that.fields.get_field('userpassword2');
+
+ var password1 = field1.save()[0];
+ var password2 = field2.save()[0];
+
+ if (password1 !== password2) {
+ field2.show_error(IPA.messages.password.password_must_match);
+ valid = false;
+ }
+
+ return valid;
+ };
+
+ that.save = function(record) {
+ that.dialog_save(record);
+ delete record.userpassword2;
+ };
+
+ return that;
+};
+
+IPA.user_password_widget = function(spec) {
+
+ spec = spec || {};
+ spec.read_only = true;
+
+ var that = IPA.input_widget(spec);
+ that.set_value = spec.set_value || '******';
+ that.unset_value = spec.unset_value || '';
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.display_control = $('<label/>', {
+ name: that.name
+ }).appendTo(container);
+ };
+
+ that.update = function(values) {
+
+ if (values && values[0]) {
+ that.display_control.text(that.set_value);
+ } else {
+ that.display_control.text(that.unset_value);
+ }
+ };
+
+ that.clear = function() {
+ that.display_control.text('');
+ };
+
+ return that;
+};
+
+IPA.user_password_dialog = function(spec) {
+
+ spec = spec || {};
+
+ spec.width = spec.width || 400;
+ spec.title = spec.title || IPA.messages.password.reset_password;
+ spec.sections = spec.sections || [];
+
+ spec.sections.push(
+ {
+ name: 'input',
+ fields: [
+ {
+ name: 'current_password',
+ label: IPA.messages.password.current_password,
+ type: 'password',
+ required: true
+ },
+ {
+ name: 'password1',
+ label: IPA.messages.password.new_password,
+ type: 'password',
+ required: true
+ },
+ {
+ name: 'password2',
+ label: IPA.messages.password.verify_password,
+ type: 'password',
+ validators: [IPA.same_password_validator({
+ other_field: 'password1'
+ })],
+ required: true
+ }
+ ]
+ });
+
+ var that = IPA.dialog(spec);
+
+ IPA.confirm_mixin().apply(that);
+
+ that.success_handler = spec.on_success;
+ that.error_handler = spec.on_error;
+ that.self_service = spec.self_service; //option to force self-service
+
+ that.get_pkey = function() {
+ var pkey;
+ if (that.self_service) {
+ pkey = IPA.whoami.uid[0];
+ } else {
+ pkey = IPA.nav.get_state('user-pkey');
+ }
+ return pkey;
+ };
+
+ that.is_self_service = function() {
+ var pkey = that.get_pkey();
+ var self_service = pkey === IPA.whoami.uid[0];
+ return self_service;
+ };
+
+ that.open = function() {
+
+ var self_service = that.is_self_service();
+ var section = that.widgets.get_widget('input');
+ var current_password_f = that.fields.get_field('current_password');
+
+ that.dialog_open();
+ section.set_row_visible('current_password', self_service);
+ current_password_f.set_required(self_service);
+ that.focus_first_element();
+ };
+
+ that.create_buttons = function() {
+
+ that.create_button({
+ name: 'reset_password',
+ label: IPA.messages.password.reset_password,
+ click: that.on_reset_click
+ });
+
+ that.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ that.close();
+ }
+ });
+ };
+
+ that.on_confirm = function() {
+ that.on_reset_click();
+ };
+
+ that.on_reset_click = function() {
+
+ if (!that.validate()) return;
+
+ var pkey = that.get_pkey();
+ var self_service = that.is_self_service();
+
+ var record = {};
+ that.save(record);
+
+ var current_password = self_service ? record.current_password[0] : undefined;
+ var new_password = record.password1[0];
+ var repeat_password = record.password2[0];
+
+ that.set_password(
+ pkey,
+ current_password,
+ new_password,
+ that.on_reset_success,
+ that.on_reset_error);
+ };
+
+ that.set_password = function(pkey, current_password, password, on_success, on_error) {
+
+ var command = IPA.command({
+ method: 'passwd',
+ args: [ pkey ],
+ options: {
+ current_password: current_password,
+ password: password
+ },
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.execute();
+ };
+
+ that.on_reset_success = function(data, text_status, xhr) {
+
+ if (that.success_handler) {
+ that.success_handler.call(this, data, text_status, xhr);
+ } else {
+ IPA.notify_success(IPA.messages.password.password_change_complete);
+ that.close();
+
+ // refresh password expiration field
+ var facet = IPA.current_entity.get_facet();
+ facet.refresh();
+
+ if (that.is_self_service()) {
+ var command = IPA.get_whoami_command();
+ command.execute();
+ }
+ }
+ };
+
+ that.on_reset_error = function(xhr, text_status, error_thrown) {
+
+ if (that.error_handler) {
+ that.error_handler.call(this, xhr, text_status, error_thrown);
+ } else {
+ that.close();
+ }
+ };
+
+ that.create_buttons();
+
+ return that;
+};
+
+IPA.user.reset_password_action = function(spec) {
+
+ spec = spec || {};
+ spec.name = spec.name || 'reset_password';
+ spec.label = spec.label || IPA.messages.password.reset_password;
+ spec.enable_cond = spec.enable_cond || ['userpassword_w'];
+
+ var that = IPA.action(spec);
+
+ that.execute_action = function(facet) {
+
+ var dialog = IPA.user_password_dialog({
+ entity: facet.entity
+ });
+
+ dialog.open();
+ };
+
+ return that;
+};
+
+IPA.user.reset_password_acl_evaluator = function(spec) {
+
+ spec.name = spec.name || 'reset_password_acl_evaluator';
+ spec.attribute = spec.attribute || 'userpassword';
+
+ var that = IPA.acl_state_evaluator(spec);
+ return that;
+};
+
+IPA.register('user', IPA.user.entity); \ No newline at end of file
diff --git a/install/ui/src/freeipa/webui.js b/install/ui/src/freeipa/webui.js
new file mode 100644
index 000000000..f381ab0be
--- /dev/null
+++ b/install/ui/src/freeipa/webui.js
@@ -0,0 +1,204 @@
+/*jsl:import ipa.js */
+/*jsl:import navigation.js */
+
+/* Authors:
+ * Pavel Zuna <pzuna@redhat.com>
+ * Endi S. Dewata <edewata@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: everything, this file puts it all togheter */
+
+/* tabs definition for IPA webUI */
+
+IPA.admin_navigation = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = 'admin';
+
+ spec.tabs = [
+ {name: 'identity', label: IPA.messages.tabs.identity, children: [
+ {entity: 'user'},
+ {entity: 'group'},
+ {entity: 'host'},
+ {entity: 'hostgroup'},
+ {entity: 'netgroup'},
+ {entity: 'service'},
+ {name:'dns', label: IPA.messages.tabs.dns, children:[
+ {entity: 'dnszone'},
+ {entity: 'dnsconfig'},
+ {entity: 'dnsrecord', hidden:true}
+ ]
+ }
+ ]},
+ {name: 'policy', label: IPA.messages.tabs.policy, children: [
+ {name: 'hbac', label: IPA.messages.tabs.hbac, children: [
+ {entity: 'hbacrule'},
+ {entity: 'hbacsvc'},
+ {entity: 'hbacsvcgroup'},
+ {entity: 'hbactest'}
+ ]},
+ {name: 'sudo', label: IPA.messages.tabs.sudo, children: [
+ {entity: 'sudorule'},
+ {entity: 'sudocmd'},
+ {entity: 'sudocmdgroup'}
+ ]},
+ {name:'automount',
+ label: IPA.messages.tabs.automount,
+ children:[
+ {entity: 'automountlocation', hidden:true, depth: -1},
+ {entity: 'automountmap', hidden: true, depth: -1},
+ {entity: 'automountkey', hidden: true, depth: -1}]},
+ {entity: 'pwpolicy'},
+ {entity: 'krbtpolicy'},
+ {entity: 'selinuxusermap'},
+ {name: 'automember', label: IPA.messages.tabs.automember,
+ children: [
+ { name: 'amgroup', entity: 'automember',
+ facet: 'searchgroup', label: IPA.messages.objects.automember.usergrouprules},
+ { name: 'amhostgroup', entity: 'automember',
+ facet: 'searchhostgroup', label: IPA.messages.objects.automember.hostgrouprules}
+ ]}
+ ]},
+ {name: 'ipaserver', label: IPA.messages.tabs.ipaserver, children: [
+ {name: 'rolebased', label: IPA.messages.tabs.role, children: [
+ {entity: 'role'},
+ {entity: 'privilege'},
+ {entity: 'permission'}
+ ]},
+ {entity: 'selfservice'},
+ {entity: 'delegation'},
+ {entity: 'idrange'},
+ {entity: 'trust'},
+ {entity: 'config'}
+ ]}];
+
+ var that = IPA.navigation(spec);
+
+ return that;
+};
+
+IPA.self_serv_navigation = function(spec) {
+
+ spec = spec || {};
+
+ spec.name = 'self-service';
+
+ spec.tabs = [
+ {name: 'identity', label: IPA.messages.tabs.identity, children: [
+ {entity: 'user'}
+ ]}];
+
+ var that = IPA.navigation(spec);
+
+ that.update = function() {
+ var pkey = that.get_state('user-pkey');
+ var facet = that.get_state('user-facet');
+
+ if (pkey && facet) {
+ that.navigation_update();
+
+ } else {
+ var state = {
+ 'navigation': 'identity',
+ 'identity': 'user',
+ 'user-pkey': pkey || IPA.whoami_pkey,
+ 'user-facet': facet || 'details'
+ };
+ that.push_state(state);
+ }
+ };
+
+ return that;
+};
+
+/* main (document onready event handler) */
+$(function() {
+
+
+
+ /* main loop (hashchange event handler) */
+ function window_hashchange(evt){
+ IPA.nav.update();
+ }
+
+ function create_navigation() {
+ var whoami = IPA.whoami;
+ var factory;
+
+
+ if (whoami.hasOwnProperty('memberof_group') &&
+ whoami.memberof_group.indexOf('admins') !== -1) {
+ factory = IPA.admin_navigation;
+ } else if (whoami.hasOwnProperty('memberofindirect_group')&&
+ whoami.memberofindirect_group.indexOf('admins') !== -1) {
+ factory = IPA.admin_navigation;
+ } else if (whoami.hasOwnProperty('memberof_role') &&
+ whoami.memberof_role.length > 0) {
+ factory = IPA.admin_navigation;
+ } else if (whoami.hasOwnProperty('memberofindirect_role') &&
+ whoami.memberofindirect_role.length > 0) {
+ factory = IPA.admin_navigation;
+ } else {
+ factory = IPA.self_serv_navigation;
+ }
+
+ return factory({
+ container: $('#navigation'),
+ content: $('#content')
+ });
+ }
+
+
+ function init_on_success(data, text_status, xhr) {
+ $(window).bind('hashchange', window_hashchange);
+
+ var whoami = IPA.whoami;
+ IPA.whoami_pkey = whoami.uid[0];
+ $('#loggedinas .login').text(whoami.cn[0]);
+ $('#loggedinas a').fragment(
+ {'user-facet': 'details', 'user-pkey': IPA.whoami_pkey}, 2);
+
+ $('#logout').click(function() {
+ IPA.logout();
+ return false;
+ }).text(IPA.messages.login.logout);
+
+ $('.header-loggedinas').css('visibility','visible');
+ IPA.update_password_expiration();
+
+ IPA.nav = create_navigation();
+ IPA.nav.create();
+ IPA.nav.update();
+
+ $('#login_header').html(IPA.messages.login.header);
+ }
+
+
+ function init_on_error(xhr, text_status, error_thrown) {
+ var container = $('#content').empty();
+ container.append('<p>Error: '+error_thrown.name+'</p>');
+ container.append('<p>'+error_thrown.message+'</p>');
+ }
+
+ IPA.init({
+ on_success: init_on_success,
+ on_error: init_on_error
+ });
+});
diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js
new file mode 100644
index 000000000..8d2239d89
--- /dev/null
+++ b/install/ui/src/freeipa/widget.js
@@ -0,0 +1,3559 @@
+/*jsl:import ipa.js */
+/* Authors:
+ * Endi Sukma Dewata <edewata@redhat.com>
+ * Adam Young <ayoung@redhat.com>
+ * Pavel Zuna <pzuna@redhat.com>
+ *
+ * Copyright (C) 2010 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* REQUIRES: ipa.js */
+
+IPA.checkbox_column_width = 22;
+IPA.required_indicator = '*';
+
+IPA.widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.name = spec.name;
+ that.id = spec.id;
+ that.label = spec.label;
+ that.tooltip = spec.tooltip;
+ that.measurement_unit = spec.measurement_unit;
+ that.entity = IPA.get_entity(spec.entity); //some old widgets still need it
+ that.facet = spec.facet;
+
+ that.create = function(container) {
+ container.addClass('widget');
+ that.container = container;
+ };
+
+ that.clear = function() {
+ };
+
+ that.set_visible = function(visible) {
+
+ if (visible) {
+ that.container.show();
+ } else {
+ that.container.hide();
+ }
+ };
+
+ that.build_child = function(spec, factory) {
+
+ if (typeof spec === 'function') {
+ spec = {
+ factory: spec
+ };
+ }
+
+ $.extend(spec, {
+ parent: that,
+ entity: that.entity,
+ facet: that.facet
+ });
+
+ var child = IPA.build(spec, factory);
+ return child;
+ };
+
+ that.widget_create = that.create;
+
+ return that;
+};
+
+IPA.input_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.width = spec.width;
+ that.height = spec.height;
+
+ that.undo = spec.undo === undefined ? true : spec.undo;
+ that.writable = spec.writable === undefined ? true : spec.writable;
+ that.read_only = spec.read_only;
+ that.hidden = spec.hidden;
+
+ //events
+ //each widget can contain several events
+ that.value_changed = IPA.observer();
+ that.undo_clicked = IPA.observer();
+
+
+ that.create_error_link = function(container) {
+ container.append(' ');
+
+ $('<span/>', {
+ name: 'error_link',
+ 'class': 'ui-state-error ui-corner-all',
+ style: 'display:none'
+ }).appendTo(container);
+ };
+
+ that.create_required = function(container) {
+ that.required_indicator = $('<span/>', {
+ 'class': 'required-indicator',
+ text: IPA.required_indicator,
+ style: 'display: none;'
+ }).appendTo(container);
+ };
+
+ that.update = function() {
+ };
+
+ /**
+ * This function saves the values entered in the UI.
+ * It returns the values in an array, or null if
+ * the field should not be saved.
+ */
+ that.save = function() {
+ return [];
+ };
+
+ /**
+ * This function creates an undo link in the container.
+ * On_undo is a link click callback. It can be specified to custom
+ * callback. If a callback isn't set, default callback is used. If
+ * spefified to value other than a function, no callback is registered.
+ */
+ that.create_undo = function(container, on_undo) {
+ container.append(' ');
+
+ that.undo_span =
+ $('<span/>', {
+ name: 'undo',
+ style: 'display: none;',
+ 'class': 'ui-state-highlight ui-corner-all undo',
+ html: IPA.messages.widget.undo
+ }).appendTo(container);
+
+ if(on_undo === undefined) {
+ on_undo = function() {
+ that.undo_clicked.notify([], that);
+ };
+ }
+
+ if(typeof on_undo === 'function') {
+ that.undo_span.click(on_undo);
+ }
+ };
+
+ that.get_undo = function() {
+ return $(that.undo_span);
+ };
+
+ that.show_undo = function() {
+ that.get_undo().css('display', 'inline');
+ };
+
+ that.hide_undo = function() {
+ $(that.undo_span).css('display', 'none');
+ };
+
+ that.get_error_link = function() {
+ return $('span[name="error_link"]', that.container);
+ };
+
+ that.show_error = function(message) {
+ var error_link = that.get_error_link();
+ error_link.html(message);
+ error_link.css('display', 'block');
+ };
+
+ that.hide_error = function() {
+ var error_link = that.get_error_link();
+ error_link.css('display', 'none');
+ };
+
+ that.set_required = function(required) {
+
+ that.required = required;
+
+ if (that.required_indicator) {
+ that.required_indicator.css('display', that.required ? 'inline' : 'none');
+ }
+ };
+
+ that.on_value_changed = function() {
+ var value = that.save();
+ that.value_changed.notify([value], that);
+ };
+
+ that.focus_input = function() {};
+ that.set_deleted = function() {};
+
+ // methods that should be invoked by subclasses
+ that.widget_hide_error = that.hide_error;
+ that.widget_show_error = that.show_error;
+
+ return that;
+};
+
+/*uses a browser specific technique to select a range.*/
+IPA.select_range = function(input,start, end) {
+ input.focus();
+ if (input[0].setSelectionRange) {
+ input[0].setSelectionRange(start, end);
+ } else if (input[0].createTextRange) {
+ var range = input[0].createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+};
+
+
+IPA.text_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.size = spec.size || 30;
+ that.input_type = spec.input_type || 'text';
+
+ that.select_range = function(start, end){
+ IPA.select_range(that.input, start, end);
+ };
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('text-widget');
+
+ that.display_control = $('<label/>', {
+ name: that.name,
+ style: 'display: none;'
+ }).appendTo(container);
+
+ that.input = $('<input/>', {
+ type: that.input_type,
+ name: that.name,
+ disabled: that.disabled,
+ size: that.size,
+ title: that.tooltip,
+ keyup: function() {
+ that.on_value_changed();
+ }
+ }).appendTo(container);
+
+ that.input.bind('input', function() {
+ that.on_value_changed();
+ });
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.update = function(values) {
+ var value = values && values.length ? values[0] : '';
+
+ if (that.read_only || !that.writable) {
+ that.display_control.text(value);
+ that.display_control.css('display', 'inline');
+ that.input.css('display', 'none');
+
+ } else {
+ that.input.val(value);
+ that.display_control.css('display', 'none');
+ that.input.css('display', 'inline');
+ }
+ };
+
+ that.save = function() {
+ if (that.read_only || !that.writable) {
+ return null;
+
+ } else {
+ var value = that.input.val();
+ return value === '' ? [] : [value];
+ }
+ };
+
+ that.set_enabled = function(value) {
+
+ that.input.prop('disabled', !value);
+ };
+
+ that.clear = function() {
+ that.input.val('');
+ that.display_control.text('');
+ };
+
+ that.focus_input = function() {
+ that.input.focus();
+ };
+
+ that.set_deleted = function(deleted) {
+ if(deleted) {
+ that.input.addClass('strikethrough');
+ } else {
+ that.input.removeClass('strikethrough');
+ }
+ };
+
+ // methods that should be invoked by subclasses
+ that.text_load = that.load;
+
+ return that;
+};
+
+IPA.password_widget = function(spec) {
+
+ spec = spec || {};
+ spec.input_type = 'password';
+
+ var that = IPA.text_widget(spec);
+ return that;
+};
+
+IPA.multivalued_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.widget_factory = spec.widget_factory || IPA.text_widget;
+ that.size = spec.size || 30;
+ that.undo_control;
+ that.initialized = false;
+
+ that.rows = [];
+
+ that.on_child_value_changed = function(row) {
+ if (that.test_dirty_row(row)) {
+ row.widget.show_undo();
+ row.remove_link.hide();
+ } else {
+ row.widget.hide_undo();
+ row.remove_link.show();
+ }
+
+ that.value_changed.notify([], that);
+ };
+
+ that.on_child_undo_clicked = function(row) {
+ if (row.is_new) {
+ that.remove_row(row);
+ } else {
+ //reset
+ row.widget.update(row.original_values);
+ row.widget.set_deleted(false);
+ row.deleted = false;
+ row.remove_link.show();
+ }
+
+ row.widget.hide_undo();
+ that.value_changed.notify([], that);
+ };
+
+ that.hide_undo = function() {
+
+ $(that.undo_span).css('display', 'none');
+ for(var i=0; i<that.rows.length; i++) {
+ var row = that.rows[i];
+ row.widget.hide_undo();
+ row.remove_link.show();
+ }
+ };
+
+
+ that.update_child = function(values, index) {
+ that.rows[index].widget.update(values);
+ };
+
+ that.show_child_undo = function(index) {
+ that.rows[index].widget.show_undo();
+ that.show_undo();
+ };
+
+ that.hide_error = function() {
+
+ that.widget_hide_error();
+
+ for (var i=0; i<that.rows.length; i++) {
+ that.rows[i].widget.hide_error();
+ }
+ };
+
+ that.show_child_error = function(index, error) {
+
+ that.rows[index].widget.show_error(error);
+ };
+
+ that.get_saved_value_row_index = function(index) {
+
+ for (var i=0; i<that.rows.length;i++) {
+
+ if(that.rows[i].deleted) index++;
+ if(i === index) return i;
+ }
+
+ return -1; //error state
+ };
+
+ that.save = function() {
+
+ var values = [];
+
+ for (var i=0; i<that.rows.length;i++) {
+
+ if(that.rows[i].deleted) continue;
+
+ values.push(that.extract_child_value(that.rows[i].widget.save()));
+ }
+
+ return values;
+ };
+
+ that.extract_child_value = function(value) {
+
+ if (value instanceof Array) {
+ if (value.length > 0) {
+ return value[0];
+ }
+ return '';
+ }
+
+ if (value) return value;
+
+ return '';
+ };
+
+ that.focus_last = function() {
+ var last_row = that.rows[that.rows.length-1];
+ last_row.widget.focus_input();
+ };
+
+ that.add_row = function(values) {
+ var row = {};
+ that.rows.push(row);
+ var row_index = that.rows.length - 1;
+ row.is_new = that.initialized;
+
+ row.container = $('<div/>', { name: 'value'});
+
+ row.widget = that.widget_factory({
+ name: that.name+'-'+row_index,
+ undo: that.undo || row.is_new,
+ read_only: that.read_only,
+ writable: that.writable
+ });
+
+ row.widget.create(row.container);
+
+ row.original_values = values;
+ row.widget.update(values);
+
+ row.widget.value_changed.attach(function() {
+ that.on_child_value_changed(row);
+ });
+ row.widget.undo_clicked.attach(function() {
+ that.on_child_undo_clicked(row);
+ });
+
+ row.remove_link = $('<a/>', {
+ name: 'remove',
+ href: 'jslink',
+ title: IPA.messages.buttons.remove,
+ html: IPA.messages.buttons.remove,
+ click: function () {
+ that.remove_row(row);
+ that.value_changed.notify([], that);
+ return false;
+ }
+ }).appendTo(row.container);
+
+ if(row.is_new) {
+ row.remove_link.hide();
+ row.widget.show_undo();
+ that.value_changed.notify([], that);
+ }
+
+ row.container.insertBefore(that.add_link);
+ };
+
+ that.create = function(container) {
+
+ container.addClass('multivalued-widget');
+
+ that.widget_create(container);
+
+ that.create_error_link(container);
+
+ that.add_link = $('<a/>', {
+ name: 'add',
+ href: 'jslink',
+ title: IPA.messages.buttons.add,
+ html: IPA.messages.buttons.add,
+ click: function() {
+ that.add_row('');
+ that.focus_last();
+ return false;
+ }
+ }).appendTo(container);
+
+
+ container.append(' ');
+
+ that.undo_span = $('<span/>', {
+ name: 'undo_all',
+ style: 'display: none;',
+ 'class': 'ui-state-highlight ui-corner-all undo',
+ html: IPA.messages.widget.undo_all,
+ click: function() {
+ that.undo_clicked.notify([], that);
+ }
+ }).appendTo(container);
+ };
+
+ that.remove_row = function(row) {
+ if (row.is_new) {
+ row.container.remove();
+ that.rows.splice(that.rows.indexOf(row), 1); //not supported by IE<9
+ } else {
+ row.deleted = true;
+ row.widget.set_deleted(true);
+ row.remove_link.hide();
+ row.widget.show_undo();
+ }
+ };
+
+ that.remove_rows = function() {
+ for(var i=0; i < that.rows.length; i++) {
+ that.rows[i].container.remove();
+ }
+ that.rows = [];
+ };
+
+ that.clear = function() {
+ that.remove_rows();
+ };
+
+ that.test_dirty_row = function(row) {
+
+ if (row.deleted || row.is_new) return true;
+
+ var values = row.widget.save();
+
+ if (row.original_values.length !== values.length) return true;
+
+ for (var i=0; i<values.length; i++) {
+ if (values[i] !== row.original_values[i]) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ that.test_dirty = function() {
+ var dirty = false;
+
+ for(var i=0; i < that.rows.length; i++) {
+ dirty = dirty || that.test_dirty_row(that.rows[i]);
+ }
+
+ return dirty;
+ };
+
+ that.update = function(values, index) {
+
+ var value;
+
+ if (index === undefined) {
+
+ that.initialized = false;
+ that.remove_rows();
+
+ for (var i=0; i<values.length; i++) {
+ value = [values[i]];
+ if(value[0]) {
+ that.add_row(value);
+ }
+ }
+
+ that.initialized = true;
+
+ if (that.read_only || !that.writable) {
+ that.add_link.css('display', 'none');
+ } else {
+ that.add_link.css('display', 'inline');
+ }
+
+ } else {
+ value = values[index];
+ var row = that.rows[index];
+ row.widget.update(values);
+ }
+ };
+
+ return that;
+};
+
+IPA.checkbox_widget = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ // default value
+ that.checked = spec.checked || false;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('checkbox-widget');
+
+ that.input = $('<input/>', {
+ type: 'checkbox',
+ name: that.name,
+ checked: that.checked,
+ title: that.tooltip,
+ change: function() {
+ that.value_changed.notify([that.save()], that);
+ }
+ }).appendTo(container);
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.save = function() {
+ var value = that.input.is(':checked');
+ return [value];
+ };
+
+ that.update = function(values) {
+ var value;
+
+ if (values && values.length) {
+ value = values[0];
+ }
+
+ if (typeof value !== 'boolean') {
+ // use default value
+ value = that.checked;
+ }
+
+ that.input.prop('checked', value);
+ };
+
+ that.clear = function() {
+ that.input.prop('checked', false);
+ };
+
+ that.checkbox_save = that.save;
+
+ return that;
+};
+
+IPA.checkboxes_widget = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.options = spec.options || [];
+ that.direction = spec.direction || 'vertical';
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('checkboxes-widget');
+
+ var vertical = that.direction === 'vertical';
+
+ for (var i=0; i<that.options.length; i++) {
+ var option = that.options[i];
+ $('<input/>', {
+ type: 'checkbox',
+ name: that.name,
+ value: option.value,
+ title: that.tooltip
+ }).appendTo(container);
+
+ $('<label/>', {
+ text: option.label,
+ title: that.tooltip
+ }).appendTo(container);
+
+ if (vertical) {
+ $('<br/>').appendTo(container);
+ }
+ }
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ var input = $('input[name="'+that.name+'"]', that.container);
+ input.change(function() {
+ that.value_changed.notify([that.save()], that);
+ });
+
+ that.create_error_link(container);
+ };
+
+ that.save = function() {
+ var values = [];
+
+ $('input[name="'+that.name+'"]:checked', that.container).each(function() {
+ values.push($(this).val());
+ });
+
+ return values;
+ };
+
+ that.update = function(values) {
+ var inputs = $('input[name="'+that.name+'"]', that.container);
+ inputs.prop('checked', false);
+
+ for (var j=0; values && j<values.length; j++) {
+ var value = values[j];
+ var input = $('input[name="'+that.name+'"][value="'+value+'"]', that.container);
+ if (!input.length) continue;
+ input.prop('checked', true);
+ }
+ };
+
+ that.clear = function() {
+ $('input[name="'+that.name+'"]').prop('checked', false);
+ };
+
+ that.add_option = function(option) {
+ that.options.push(option);
+ };
+
+ // methods that should be invoked by subclasses
+ that.checkboxes_update = that.update;
+
+ return that;
+};
+
+IPA.radio_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.default_value = spec.default_value;
+ that.options = spec.options;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('radio-widget');
+
+ var name = IPA.html_util.get_next_id(that.name+'-');
+ that.selector = 'input[name="'+name+'"]';
+
+ for (var i=0; i<that.options.length; i++) {
+ var option = that.options[i];
+
+ var id = name+'-'+i;
+
+ $('<input/>', {
+ id: id,
+ type: 'radio',
+ name: name,
+ value: option.value
+ }).appendTo(container);
+
+ $('<label/>', {
+ text: option.label,
+ 'for': id
+ }).appendTo(container);
+ }
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ var input = $(that.selector, that.container);
+ input.change(function() {
+ that.value_changed.notify([that.save()], that);
+ });
+
+ that.create_error_link(container);
+ };
+
+ that.save = function() {
+ var input = $(that.selector+':checked', that.container);
+ if (!input.length) return [];
+ return [input.val()];
+ };
+
+ that.update = function(values) {
+
+ $(that.selector, that.container).each(function() {
+ var input = this;
+ input.checked = false;
+ });
+
+ var value = values && values.length ? values[0] : '';
+ var input = $(that.selector+'[value="'+value+'"]', that.container);
+ if (input.length) {
+ input.prop('checked', true);
+ } else if (that.default_value) {
+ input = $(that.selector+'[value="'+that.default_value+'"]', that.container);
+ input.prop('checked', true);
+ }
+
+ that.value_changed.notify([that.save()], that);
+ };
+
+ that.clear = function() {
+ $(that.selector, that.container).prop('checked', false);
+
+ if (that.default_value) {
+ var input = $(that.selector+'[value="'+that.default_value+'"]', that.container);
+ input.prop('checked', true);
+ }
+ };
+
+ // methods that should be invoked by subclasses
+ that.radio_create = that.create;
+ that.radio_save = that.save;
+
+ return that;
+};
+
+IPA.select_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.options = spec.options || [];
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('select-widget');
+
+ that.select = $('<select/>', {
+ name: that.name,
+ change: function() {
+ that.value_changed.notify([], that);
+ return false;
+ }
+ }).appendTo(container);
+
+ that.create_options();
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.create_options = function() {
+
+ that.select.empty();
+
+ for (var i=0; i<that.options.length; i++) {
+ var option = that.options[i];
+
+ $('<option/>', {
+ text: option.label,
+ value: option.value
+ }).appendTo(that.select);
+ }
+ };
+
+ that.save = function() {
+ var value;
+
+ if (that.select) {
+ value = that.select.val() || '';
+ } else if (that.options.length > 0) {
+ value = that.options[0].value; //will be default value
+ }
+
+ return [value];
+ };
+
+ that.update = function(values) {
+ var value = values[0];
+ var option = $('option[value="'+value+'"]', that.select);
+ if (!option.length) return;
+ option.prop('selected', true);
+ };
+
+ that.empty = function() {
+ $('option', that.select).remove();
+ };
+
+ that.clear = function() {
+ $('option', that.select).prop('selected', false);
+ };
+
+ that.set_options_enabled = function(enabled, options) {
+
+ if (!options) {
+ $('option', that.select).prop('disabled', !enabled);
+ } else {
+ for (var i=0; i<options.length;i++) {
+ var value = options[i];
+ var option = $('option[value="'+value+'"]', that.select);
+ option.prop('disabled', !enabled);
+ }
+ }
+ };
+
+ that.enable_options = function(options) {
+
+ that.set_options_enabled(true, options);
+ };
+
+ that.disable_options = function(options) {
+
+ that.set_options_enabled(false, options);
+ };
+
+ // methods that should be invoked by subclasses
+ that.select_save = that.save;
+ that.select_update = that.update;
+
+ return that;
+};
+
+IPA.textarea_widget = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.rows = spec.rows || 5;
+ that.cols = spec.cols || 40;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('textarea-widget');
+
+ that.input = $('<textarea/>', {
+ name: that.name,
+ rows: that.rows,
+ cols: that.cols,
+ disabled: that.disabled,
+ title: that.tooltip,
+ keyup: function() {
+ that.on_value_changed();
+ }
+ }).appendTo(container);
+
+ that.input.bind('input', function() {
+ that.on_value_changed();
+ });
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.save = function() {
+ var value = that.input.val();
+ return [value];
+ };
+
+ that.update = function(values) {
+ var value = values && values.length ? values[0] : '';
+ that.input.val(value);
+ };
+
+ that.clear = function() {
+ that.input.val('');
+ };
+
+ return that;
+};
+
+IPA.formatter = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.type = spec.type; // default is text
+
+ // parse attribute value into a normalized value
+ that.parse = function(value) {
+ return value;
+ };
+
+ // format normalized value
+ that.format = function(value) {
+ return value;
+ };
+
+ return that;
+};
+
+IPA.boolean_formatter = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.formatter(spec);
+
+ that.true_value = spec.true_value || IPA.messages['true'];
+ that.false_value = spec.false_value || IPA.messages['false'];
+ that.show_false = spec.show_false;
+ that.invert_value = spec.invert_value;
+
+ // convert string boolean value into real boolean value, or keep the original value
+ that.parse = function(value) {
+
+ if (value === undefined || value === null) return '';
+
+ if (value instanceof Array) {
+ value = value[0];
+ }
+
+ if (typeof value === 'string') {
+ value = value.toLowerCase();
+
+ if (value === 'true') {
+ value = true;
+ } else if (value === 'false') {
+ value = false;
+ } // leave other values unchanged
+ }
+
+ if (typeof value === 'boolean') {
+ if (that.invert_value) value = !value;
+ }
+
+ return value;
+ };
+
+ // convert boolean value into formatted string, or keep the original value
+ that.format = function(value) {
+
+ if (typeof value === 'boolean') {
+ if (value) {
+ value = that.true_value;
+
+ } else {
+ if (that.show_false) {
+ value = that.false_value;
+ } else {
+ value = '';
+ }
+ }
+ }
+
+ return value;
+ };
+
+ that.boolean_formatter_parse = that.parse;
+ that.boolean_formatter_format = that.format;
+
+ return that;
+};
+
+IPA.boolean_status_formatter = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.boolean_formatter(spec);
+
+ that.true_value = spec.true_value || IPA.messages.status.enabled;
+ that.false_value = spec.false_value || IPA.messages.status.disabled;
+ that.show_false = true;
+ that.type = 'html';
+
+ that.format = function(value) {
+ var status = value ? 'enabled' : 'disabled';
+ var formatted_value = that.boolean_formatter_format(value);
+ formatted_value = '<span class=\"icon '+status+'-icon\"/> '+formatted_value;
+ return formatted_value;
+ };
+
+ return that;
+};
+
+/* Take an LDAP format date in UTC and format it */
+IPA.utc_date_formatter = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.formatter(spec);
+
+ that.format = function(value) {
+
+ if (!value) return '';
+ var date = IPA.parse_utc_date(value);
+ if (!date) return value;
+ return date.toString();
+ };
+
+ return that;
+};
+
+/*
+ The entity name must be set in the spec either directly or via entity.name
+*/
+IPA.column = function (spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.entity = IPA.get_entity(spec.entity);
+ that.name = spec.name;
+
+ that.label = spec.label;
+ that.width = spec.width;
+ that.primary_key = spec.primary_key;
+ that.link = spec.link;
+ that.formatter = spec.formatter;
+
+ if (!that.entity) {
+ throw {
+ expected: false,
+ message: 'Column created without an entity.'
+ };
+ }
+
+ that.setup = function(container, record, suppress_link) {
+
+ container.empty();
+
+ var value = record[that.name];
+ var type;
+ if (that.formatter) {
+ value = that.formatter.parse(value);
+ value = that.formatter.format(value);
+ type = that.formatter.type;
+ }
+ value = value ? value.toString() : '';
+
+ var c;
+ if (that.link && !suppress_link) {
+ c = $('<a/>', {
+ href: '#'+value,
+ click: function() {
+ return that.link_handler(value);
+ }
+ }).appendTo(container);
+
+ } else {
+ c = container;
+ }
+
+ if (type === 'html') {
+ c.html(value);
+ } else {
+ c.text(value);
+ }
+ };
+
+ that.link_handler = function(value) {
+ return false;
+ };
+
+
+ /*column initialization*/
+ if (that.entity && !that.label) {
+ var metadata = IPA.get_entity_param(that.entity.name, that.name);
+ if (metadata) {
+ that.label = metadata.label;
+ }
+ }
+
+
+ return that;
+};
+
+IPA.table_widget = function (spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.scrollable = spec.scrollable;
+ that.selectable = spec.selectable === undefined ? true : spec.selectable;
+ that.save_values = spec.save_values === undefined ? true : spec.save_values;
+ that['class'] = spec['class'];
+
+ that.pagination = spec.pagination;
+ that.current_page = 1;
+ that.total_pages = 1;
+ that.page_length = spec.page_length || 20;
+
+ that.multivalued = spec.multivalued === undefined ? true : spec.multivalued;
+
+ that.columns = $.ordered_map();
+ that.value_attr_name = spec.value_attribute || that.name;
+
+ that.get_columns = function() {
+ return that.columns.values;
+ };
+
+ that.get_column = function(name) {
+ return that.columns.get(name);
+ };
+
+ that.add_column = function(column) {
+ column.entity = that.entity;
+ that.columns.put(column.name, column);
+ };
+
+ that.set_columns = function(columns) {
+ that.clear_columns();
+ for (var i=0; i<columns.length; i++) {
+ that.add_column(columns[i]);
+ }
+ };
+
+ that.clear_columns = function() {
+ that.columns.empty();
+ };
+
+ that.create_column = function(spec) {
+ var column = IPA.column(spec);
+ that.add_column(column);
+ return column;
+ };
+
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('table-widget');
+
+ that.table = $('<table/>', {
+ 'class': 'search-table'
+ }).appendTo(container);
+
+ if (that['class']) that.table.addClass(that['class']);
+
+ if (that.scrollable) {
+ that.table.addClass('scrollable');
+ }
+
+ that.thead = $('<thead/>').appendTo(that.table);
+
+ var tr = $('<tr/>').appendTo(that.thead);
+
+ var th;
+
+ if (that.selectable) {
+ th = $('<th/>', {
+ 'style': 'width: '+IPA.checkbox_column_width+'px;'
+ }).appendTo(tr);
+
+ if (that.multivalued) {
+ var select_all_checkbox = $('<input/>', {
+ type: 'checkbox',
+ name: that.name,
+ title: IPA.messages.search.select_all
+ }).appendTo(th);
+
+ select_all_checkbox.change(function() {
+ if(select_all_checkbox.is(':checked')) {
+ that.select_all();
+ } else {
+ that.unselect_all();
+ }
+ return false;
+ });
+ }
+ }
+ var columns = that.columns.values;
+ var column;
+
+ var columns_without_width = 0;
+ var per_column_space = 16; //cell padding(2x6px), border (2x1px), spacing (2px)
+ var available_width = that.thead.width();
+ available_width -= 2; //first cell spacing
+
+ //subtract checkbox column
+ if(that.selectable) {
+ available_width -= IPA.checkbox_column_width;
+ available_width -= per_column_space;
+ }
+
+ //subtract width of columns with their width set
+ for (i=0; i<columns.length; i++) {
+ column = columns[i];
+ if (column.width) {
+ available_width -= parseInt(
+ column.width.substring(0, column.width.length-2),10);
+ available_width -= per_column_space;
+ } else {
+ columns_without_width++;
+ }
+ }
+
+ //width for columns without width set
+ var new_column_width = (available_width -
+ per_column_space * columns_without_width) /
+ columns_without_width;
+
+
+ //set the new width, now all columns should have width set
+ for (i=0; i<columns.length; i++) {
+ column = columns[i];
+ if (!column.width) {
+ column.width = new_column_width+"px";
+ }
+ }
+
+ for (i=0; i<columns.length; i++) {
+ column = columns[i];
+
+ th = $('<th/>').appendTo(tr);
+
+ th.css('width', column.width);
+ th.css('max-width', column.width);
+
+ var label = column.label;
+
+ $('<div/>', {
+ 'style': 'float: left;',
+ 'html': label
+ }).appendTo(th);
+
+ if (i == columns.length-1) {
+ that.buttons = $('<div/>', {
+ 'name': 'buttons',
+ 'style': 'float: right;'
+ }).appendTo(th);
+ }
+
+ }
+
+ that.tbody = $('<tbody/>').appendTo(that.table);
+
+ // workaround for #2835
+ if ($.browser.msie) {
+ that.tbody.mousedown(function(event) {
+ that.scroll_top = that.tbody.scrollTop();
+ window.setTimeout(function() {
+ if (that.tbody.scrollTop() === 0) {
+ that.tbody.scrollTop(that.scroll_top);
+ }
+ }, 0);
+ });
+ }
+
+ if (that.height) {
+ that.tbody.css('height', that.height);
+ }
+
+ that.row = $('<tr/>');
+
+ var td;
+
+ if (that.selectable) {
+ td = $('<td/>', {
+ 'style': 'width: '+ (IPA.checkbox_column_width + 7) +'px;'
+ }).appendTo(that.row);
+
+ if (that.multivalued) {
+ $('<input/>', {
+ type: 'checkbox',
+ name: that.name,
+ value: ''
+ }).appendTo(td);
+ } else {
+ $('<input/>', {
+ type: 'radio',
+ name: that.name,
+ value: ''
+ }).appendTo(td);
+ }
+ }
+
+ var width;
+
+ for (/* var */ i=0; i<columns.length; i++) {
+ /* var */ column = columns[i];
+
+ td = $('<td/>').appendTo(that.row);
+ if (column.width) {
+ width = parseInt(
+ column.width.substring(0, column.width.length-2),10);
+ width += 7; //data cells lack right padding
+ width += 'px';
+ td.css('width', width);
+ td.css('max-width', width);
+ }
+
+ $('<div/>', {
+ 'name': column.name
+ }).appendTo(td);
+ }
+
+ that.tfoot = $('<tfoot/>').appendTo(that.table);
+
+ tr = $('<tr/>').appendTo(that.tfoot);
+
+ td = $('<td/>', {
+ colspan: columns.length + (that.selectable ? 1 : 0)
+ }).appendTo(tr);
+
+ that.create_error_link(td);
+
+ that.summary = $('<span/>', {
+ 'name': 'summary'
+ }).appendTo(td);
+
+ that.pagination_control = $('<span/>', {
+ 'class': 'pagination-control'
+ }).appendTo(td);
+
+ if (that.pagination) {
+
+ $('<a/>', {
+ text: IPA.messages.widget.prev,
+ name: 'prev_page',
+ click: function() {
+ that.prev_page();
+ return false;
+ }
+ }).appendTo(that.pagination_control);
+
+ that.pagination_control.append(' ');
+
+ $('<a/>', {
+ text: IPA.messages.widget.next,
+ name: 'next_page',
+ click: function() {
+ that.next_page();
+ return false;
+ }
+ }).appendTo(that.pagination_control);
+
+ that.pagination_control.append(' ');
+ that.pagination_control.append(IPA.messages.widget.page);
+ that.pagination_control.append(': ');
+
+ that.current_page_input = $('<input/>', {
+ type: 'text',
+ name: 'current_page',
+ keypress: function(e) {
+ if (e.which == 13) {
+ var page = parseInt(that.current_page_input.val(), 10) || 1;
+ that.set_page(page);
+ }
+ }
+ }).appendTo(that.pagination_control);
+
+ that.pagination_control.append(' / ');
+
+ that.total_pages_span = $('<span/>', {
+ name: 'total_pages'
+ }).appendTo(that.pagination_control);
+ }
+ };
+
+ that.prev_page = function() {
+ if (that.current_page > 1) {
+ that.current_page--;
+ that.refresh();
+ }
+ };
+
+ that.next_page = function() {
+ if (that.current_page < that.total_pages) {
+ that.current_page++;
+ that.refresh();
+ }
+ };
+
+ that.set_page = function(page) {
+ if (page < 1) {
+ page = 1;
+ } else if (page > that.total_pages) {
+ page = that.total_pages;
+ }
+ that.current_page = page;
+ that.current_page_input.val(page);
+ that.refresh();
+ };
+
+ that.select_changed = function() {
+ };
+
+ that.select_all = function() {
+ $('input[name="'+that.name+'"]', that.thead).prop('checked', true).
+ attr('title', IPA.messages.search.unselect_all);
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', true);
+ that.select_changed();
+ };
+
+ that.unselect_all = function() {
+ $('input[name="'+that.name+'"]', that.thead).prop('checked', false).
+ attr('title', IPA.messages.search.select_all);
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', false);
+ that.select_changed();
+ };
+
+ that.set_values = function(values) {
+ $('input[name="'+that.name+'"]', that.tbody).prop('checked', false);
+ for (var i=0; values && i<values.length; i++) {
+ var value = values[i];
+ $('input[name="'+that.name+'"][value="'+value+'"]', that.tbody).prop('checked', true);
+ }
+ that.select_changed();
+ };
+
+ that.empty = function() {
+ that.tbody.empty();
+ };
+
+ that.load = function(result) {
+
+ that.empty();
+
+ that.values = result[that.value_attr_name] || [];
+ for (var i=0; i<that.values.length; i++) {
+ var record = that.get_record(result, i);
+ that.add_record(record);
+ }
+ };
+
+ that.update = function(records) {
+
+ that.empty();
+
+ that.values = [];
+ that.records = records;
+
+ for (var i=0; i<records.length; i++) {
+ var record = records[i];
+ that.values.push(record[that.value_attr_name]);
+ that.add_record(record);
+ }
+ };
+
+ that.save = function() {
+ if (that.save_values) {
+ var values = [];
+
+ $('input[name="'+that.name+'"]', that.tbody).each(function() {
+ values.push($(this).val());
+ });
+
+ return values;
+
+ } else {
+ return null;
+ }
+ };
+
+ that.get_selected_values = function() {
+ var values = [];
+
+ $('input[name="'+that.name+'"]:checked', that.tbody).each(function() {
+ values.push($(this).val());
+ });
+
+ return values;
+ };
+
+ that.get_selected_rows = function() {
+ return $('input[name="'+that.name+'"]:checked', that.tbody).closest('tr');
+ };
+
+ that.get_record = function(result, index) {
+
+ var record = {};
+
+ var columns = that.columns.values;
+ for (var i=0; i<columns.length; i++){
+ var name = columns[i].name;
+ var values = result[name];
+ if (!values) continue;
+
+ if (values instanceof Array){
+ record[name] = values[index];
+ } else {
+ record[name] = values;
+ }
+ }
+
+ return record;
+ };
+
+ that.add_record = function(record) {
+
+ var tr = that.row.clone();
+ tr.appendTo(that.tbody);
+
+ $('input[name="'+that.name+'"]', tr).click(function(){
+ that.select_changed();
+ });
+
+ var select_set = false;
+ var value;
+ var columns = that.columns.values;
+
+ for (var i=0; i<columns.length; i++){
+ var column = columns[i];
+
+ value = record[column.name];
+ value = value ? value.toString() : '';
+
+ if (column.primary_key) {
+ $('input[name="'+that.name+'"]', tr).val(value);
+ select_set = true;
+ }
+
+ var div = $('div[name="'+column.name+'"]', tr);
+
+ that.setup_column(column, div, record);
+ }
+
+ if (!select_set) {
+ value = record[that.value_attr_name];
+ value = value ? value.toString() : '';
+ $('input[name="'+that.name+'"]', tr).val(value);
+ }
+
+ return tr;
+ };
+
+ that.set_row_enabled = function(tr, enabled) {
+ if (enabled) {
+ tr.removeClass('disabled');
+ } else {
+ tr.addClass('disabled');
+ }
+ };
+
+ that.setup_column = function(column, div, record) {
+ column.setup(div, record);
+ };
+
+ that.add_rows = function(rows) {
+ for (var i=0; i<rows.length; i++) {
+ var tr = rows[i];
+ $('input', tr).attr('name', that.name);
+ that.tbody.append(tr);
+ }
+ };
+
+ that.remove_selected_rows = function() {
+ var rows = [];
+ that.tbody.children().each(function() {
+ var tr = $(this);
+ if (!$('input[name="'+that.name+'"]', tr).get(0).checked) return;
+ tr.detach();
+ rows.push(tr);
+ });
+ return rows;
+ };
+
+ that.show_error = function(message) {
+ var error_link = that.get_error_link();
+ error_link.html(message);
+ error_link.css('display', 'inline');
+ };
+
+ that.set_enabled = function(enabled) {
+ $('input[name="'+that.name+'"]', that.table).prop('disabled', !enabled);
+ };
+
+ that.clear = function() {
+ that.empty();
+ that.summary.text('');
+ };
+
+ //column initialization
+ if (spec.columns) {
+ for (var i=0; i<spec.columns; i++) {
+ that.create_column(spec.columns[i]);
+ }
+ }
+
+ // methods that should be invoked by subclasses
+ that.table_create = that.create;
+ that.table_load = that.load;
+ that.table_next_page = that.next_page;
+ that.table_prev_page = that.prev_page;
+ that.table_set_enabled = that.set_enabled;
+ that.table_set_page = that.set_page;
+ that.table_show_error = that.show_error;
+ that.table_set_values = that.set_values;
+ that.table_update = that.update;
+
+ return that;
+};
+
+
+IPA.attribute_table_widget = function(spec) {
+
+
+ spec = spec || {};
+ spec.columns = spec.columns || [];
+
+ var that = IPA.table_widget(spec);
+
+ that.attribute_name = spec.attribute_name || that.name;
+ that.adder_dialog_spec = spec.adder_dialog;
+ that.css_class = spec.css_class;
+
+ that.add_command = spec.add_command;
+ that.remove_command = spec.remove_command;
+
+ that.on_add = spec.on_add;
+ that.on_add_error = spec.on_add_error;
+ that.on_remove = spec.on_remove;
+ that.on_remove_error = spec.on_remove_error;
+
+ that.create_column = function(spec) {
+
+ if (typeof spec === 'string') {
+ spec = {
+ name: spec
+ };
+ }
+
+ spec.entity = that.entity;
+
+ var factory = spec.factory || IPA.column;
+
+ var column = factory(spec);
+ that.add_column(column);
+ return column;
+ };
+
+ that.create_columns = function() {
+ that.clear_columns();
+ if (spec.columns) {
+ for (var i=0; i<spec.columns.length; i++) {
+ that.create_column(spec.columns[i]);
+ }
+ }
+
+ that.post_create_columns();
+ };
+
+ that.post_create_columns = function() {
+ };
+
+ that.create_buttons = function(container) {
+
+ that.remove_button = IPA.action_button({
+ name: 'remove',
+ label: IPA.messages.buttons.remove,
+ icon: 'remove-icon',
+ 'class': 'action-button-disabled',
+ click: function() {
+ if (!that.remove_button.hasClass('action-button-disabled')) {
+ that.remove_handler();
+ }
+ return false;
+ }
+ }).appendTo(container);
+
+ that.add_button = IPA.action_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ icon: 'add-icon',
+ click: function() {
+ if (!that.add_button.hasClass('action-button-disabled')) {
+ that.add_handler();
+ }
+ return false;
+ }
+ }).appendTo(container);
+ };
+
+ that.create = function(container) {
+
+ that.create_columns();
+ that.table_create(container);
+ if (that.css_class)
+ container.addClass(that.css_class);
+ that.create_buttons(that.buttons);
+ };
+
+ that.set_enabled = function(enabled) {
+ that.table_set_enabled(enabled);
+ if (enabled) {
+ if(that.add_button) {
+ that.add_button.removeClass('action-button-disabled');
+ }
+ } else {
+ $('.action-button', that.table).addClass('action-button-disabled');
+ that.unselect_all();
+ }
+ that.enabled = enabled;
+ };
+
+ that.select_changed = function() {
+
+ var values = that.get_selected_values();
+
+ if (that.remove_button) {
+ if (values.length === 0) {
+ that.remove_button.addClass('action-button-disabled');
+ } else {
+ that.remove_button.removeClass('action-button-disabled');
+ }
+ }
+ };
+
+ that.add_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_add_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_add_dialog();
+ }
+ };
+
+ that.remove_handler = function() {
+ var facet = that.entity.get_facet();
+
+ if (facet.is_dirty()) {
+ var dialog = IPA.dirty_dialog({
+ entity:that.entity,
+ facet: facet
+ });
+
+ dialog.callback = function() {
+ that.show_remove_dialog();
+ };
+
+ dialog.open(that.container);
+
+ } else {
+ that.show_remove_dialog();
+ }
+ };
+
+ that.show_remove_dialog = function() {
+
+ var dialog = that.create_remove_dialog();
+ if (dialog) dialog.open(that.container);
+ };
+
+ that.create_remove_dialog = function() {
+ var selected_values = that.get_selected_values();
+
+ if (!selected_values.length) {
+ var message = IPA.messages.dialogs.remove_empty;
+ alert(message);
+ return null;
+ }
+
+ var dialog = IPA.deleter_dialog({
+ entity: that.entity,
+ values: selected_values
+ });
+
+ dialog.execute = function() {
+ var command = that.create_remove_command(
+ selected_values,
+ function(data, text_status, xhr) {
+ var handler = that.on_remove || that.on_command_success;
+ handler.call(this, data, text_status, xhr);
+ },
+ function(xhr, text_status, error_thrown) {
+ var handler = that.on_remove_error || that.on_command_error;
+ handler.call(this, xhr, text_status, error_thrown);
+ }
+ );
+ command.execute();
+ };
+
+ return dialog;
+ };
+
+ that.on_command_success = function(data) {
+ that.reload_facet(data);
+ };
+
+ that.on_command_error = function() {
+ that.refresh_facet();
+ };
+
+ that.get_pkeys = function() {
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ return [pkey];
+ };
+
+ that.get_additional_options = function() {
+ return [];
+ };
+
+ that.create_remove_command = function(values, on_success, on_error) {
+
+ var pkeys = that.get_pkeys();
+
+ var command = IPA.command({
+ entity: that.entity.name,
+ method: that.remove_command || 'del',
+ args: pkeys,
+ on_success: on_success,
+ on_error: on_error
+ });
+
+ command.set_option(that.attribute_name, values);
+
+ var additional_options = that.get_additional_options();
+ for (var i=0; i<additional_options.length; i++) {
+ var option = additional_options[i];
+ command.set_option(option.name, option.value);
+ }
+
+ return command;
+ };
+
+ that.create_add_dialog = function() {
+
+ var dialog_spec = {
+ entity: that.entity,
+ method: that.add_command
+ };
+
+ if (that.adder_dialog_spec) {
+ $.extend(dialog_spec, that.adder_dialog_spec);
+ }
+
+ var label = that.entity.metadata.label_singular;
+ var pkey = IPA.nav.get_state(that.entity.name+'-pkey');
+ dialog_spec.title = dialog_spec.title || IPA.messages.dialogs.add_title;
+ dialog_spec.title = dialog_spec.title.replace('${entity}', label);
+ dialog_spec.title = dialog_spec.title.replace('${pkey}', pkey);
+
+
+ var factory = dialog_spec.factory || IPA.entity_adder_dialog;
+ var dialog = factory(dialog_spec);
+
+ var cancel_button = dialog.buttons.get('cancel');
+ dialog.buttons.empty();
+
+ dialog.create_button({
+ name: 'add',
+ label: IPA.messages.buttons.add,
+ click: function() {
+ dialog.hide_message();
+ dialog.add(
+ function(data, text_status, xhr) {
+ var handler = that.on_add || that.on_command_success;
+ handler.call(this, data, text_status, xhr);
+ dialog.close();
+ },
+ dialog.on_error);
+ }
+ });
+
+ dialog.create_button({
+ name: 'add_and_add_another',
+ label: IPA.messages.buttons.add_and_add_another,
+ click: function() {
+ dialog.hide_message();
+ dialog.add(
+ function(data, text_status, xhr) {
+ var label = that.entity.metadata.label_singular;
+ var message = IPA.messages.dialogs.add_confirmation;
+ message = message.replace('${entity}', label);
+ dialog.show_message(message);
+
+ var handler = that.on_add || that.on_command_success;
+ handler.call(this, data, text_status, xhr);
+
+ dialog.reset();
+ },
+ dialog.on_error);
+ }
+ });
+
+ dialog.buttons.put('cancel', cancel_button);
+
+ dialog.create_add_command = function(record) {
+ return that.adder_dialog_create_command(dialog, record);
+ };
+
+ return dialog;
+ };
+
+ that.adder_dialog_create_command = function(dialog, record) {
+ var command = dialog.entity_adder_dialog_create_add_command(record);
+ command.args = that.get_pkeys();
+
+ var additional_options = that.get_additional_options();
+ for (var i=0; i<additional_options.length; i++) {
+ var option = additional_options[i];
+ command.set_option(option.name, option.value);
+ }
+
+ return command;
+ };
+
+ that.show_add_dialog = function() {
+
+ var dialog = that.create_add_dialog();
+ dialog.open(that.container);
+ };
+
+ that.update = function(values) {
+ that.table_update(values);
+ that.unselect_all();
+ };
+
+ that.reload_facet = function(data) {
+
+ //FIXME: bad approach - widget is directly manipulating with facet
+ var facet = IPA.current_entity.get_facet();
+ facet.load(data);
+ };
+
+ that.refresh_facet = function() {
+
+ //FIXME: bad approach
+ var facet = IPA.current_entity.get_facet();
+ facet.refresh();
+ };
+
+ that.attribute_table_adder_dialog_create_command = that.adder_dialog_create_command;
+ that.attribute_table_create_remove_command = that.create_remove_command;
+ that.attribute_table_update = that.update;
+
+ return that;
+};
+
+IPA.combobox_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.editable = spec.editable;
+ that.searchable = spec.searchable;
+ that.size = spec.size || 5;
+ that.empty_option = spec.empty_option === undefined ? true : spec.empty_option;
+ that.options = spec.options || [];
+ that.input_field_changed = IPA.observer();
+ that.z_index = spec.z_index ? spec.z_index + 9000000 : 9000000;
+
+ that.create = function(container) {
+ that.widget_create(container);
+
+ container.addClass('combobox-widget');
+
+ $(document).keyup(function(e) {
+ if (e.which == 27) { // Escape
+ that.close();
+ }
+ });
+
+ that.input_container = $('<div/>', {
+ 'class': 'combobox-widget-input'
+ }).appendTo(container);
+
+ that.text = $('<label/>', {
+ name: that.name,
+ style: 'display: none;'
+ }).appendTo(that.input_container);
+
+ that.input = $('<input/>', {
+ type: 'text',
+ name: that.name,
+ title: that.tooltip,
+ readonly: !that.editable || that.read_only,
+ keyup: function() {
+ that.input_field_changed.notify([], that);
+ },
+ click: function() {
+ if (that.editable) return false;
+ if (that.is_open()) {
+ that.close();
+ } else {
+ that.open();
+ }
+ return false;
+ }
+ }).appendTo(that.input_container);
+
+ that.input.bind('input', function() {
+ that.input_field_changed.notify([], that);
+ });
+
+ that.open_button = IPA.action_button({
+ name: 'open',
+ icon: 'combobox-icon',
+ click: function() {
+ if (that.is_open()) {
+ that.close();
+ } else {
+ that.open();
+ }
+ return false;
+ }
+ }).appendTo(that.input_container);
+
+ that.list_container = $('<div/>', {
+ 'class': 'combobox-widget-list',
+ css: { 'z-index': that.z_index }
+ }).appendTo(that.input_container);
+
+ var div = $('<div/>', {
+ style: 'position: relative; width: 100%;'
+ }).appendTo(that.list_container);
+
+ if (that.searchable) {
+ that.filter = $('<input/>', {
+ type: 'text',
+ name: 'filter',
+ keypress: function(e) {
+ if (e.which == 13) { // Enter
+ var filter = that.filter.val();
+ that.search(filter);
+ }
+ }
+ }).appendTo(div);
+
+ that.search_button = IPA.action_button({
+ name: 'search',
+ icon: 'search-icon',
+ click: function() {
+ var filter = that.filter.val();
+ that.search(filter);
+ return false;
+ }
+ }).appendTo(div);
+
+ div.append('<br/>');
+ }
+
+ that.list = $('<select/>', {
+ name: 'list',
+ size: that.size,
+ style: 'width: 100%',
+ change: that.select_on_change
+ }).appendTo(div);
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.select_on_change = function() {
+
+ if (!that.is_open()) return;
+
+ var value = that.list.val();
+ that.input.val(value);
+ IPA.select_range(that.input, 0, 0);
+
+ that.close();
+ that.value_changed.notify([[value]], that);
+ };
+
+ that.open = function() {
+ if (!that.read_only)
+ that.list_container.css('visibility', 'visible');
+ };
+
+ that.close = function() {
+ that.list_container.css('visibility', 'hidden');
+ };
+
+ that.is_open = function() {
+ return that.list_container.css('visibility') == 'visible';
+ };
+
+ that.search = function(filter, on_success, on_error) {
+
+ that.recreate_options();
+ if (on_success) on_success.call(this);
+ };
+
+ that.set_options = function(options) {
+ that.options = options;
+ that.recreate_options();
+ };
+
+ that.recreate_options = function() {
+
+ that.remove_options();
+
+ if (that.empty_option) {
+ that.create_option();
+ }
+
+ for (var i=0; i<that.options.length; i++) {
+ var option = that.options[i];
+
+ var label, value;
+ if (option instanceof Object) {
+ label = option.label;
+ value = option.value;
+ } else {
+ label = option;
+ value = option;
+ }
+
+ that.create_option(label, value);
+ }
+ };
+
+ that.update = function(values) {
+ that.close();
+
+ if (that.writable) {
+ that.text.css('display', 'none');
+ that.input.css('display', 'inline');
+ that.open_button.css('display', 'inline');
+ } else {
+ that.text.css('display', 'inline');
+ that.input.css('display', 'none');
+ that.open_button.css('display', 'none');
+ }
+
+ if (that.searchable) {
+ that.filter.empty();
+ }
+
+ // In a details page the following code will get the stored value.
+ // In a dialog box the value will be null.
+ var value = values.length ? values[0] : null;
+
+ // In a details page the following code will show the stored
+ // value immediately without waiting to populate the list.
+ // In a dialog box it will show blank.
+ that.set_value(value || '');
+
+ // In a details page the following code will populate the list
+ // and select the stored value.
+ // In a dialog box it will populate the list and select the first
+ // available option.
+ that.search(
+ null,
+ function(data, text_status, xhr) {
+ that.select(value);
+ }
+ );
+ };
+
+ that.set_value = function(value) {
+ that.text.text(value);
+ that.input.val(value);
+ };
+
+ that.select = function(value) {
+
+ var option;
+
+ if (value) {
+ // select specified value
+ option = $('option[value="'+value+'"]', that.list);
+ } else {
+ // select first available option
+ option = $('option', that.list).first();
+ }
+
+ // if no option found, skip
+ if (!option.length) return;
+
+ option.prop('selected', true);
+
+ that.set_value(option.val());
+ that.value_changed.notify([], that);
+ };
+
+ that.save = function() {
+ var value = that.input.val();
+ return value === '' ? [] : [value];
+ };
+
+ that.create_option = function(label, value) {
+ var option = $('<option/>', {
+ text: label,
+ value: value,
+ click: that.select_on_change
+ }).appendTo(that.list);
+ };
+
+ that.remove_options = function() {
+ that.list.empty();
+ };
+
+ that.clear = function() {
+ that.input.val('');
+ that.remove_options();
+ };
+
+ return that;
+};
+
+IPA.entity_select_widget = function(spec) {
+
+ spec = spec || {};
+ spec.searchable = spec.searchable === undefined ? true : spec.searchable;
+
+ var that = IPA.combobox_widget(spec);
+
+ that.other_entity = IPA.get_entity(spec.other_entity);
+ that.other_field = spec.other_field;
+
+ that.options = spec.options || [];
+
+ that.create_search_command = function(filter) {
+ return IPA.command({
+ entity: that.other_entity.name,
+ method: 'find',
+ args: [filter]
+ });
+ };
+
+ that.search = function(filter, on_success, on_error) {
+
+ that.on_search_success = on_success;
+
+ var command = that.create_search_command(filter);
+ command.on_success = that.search_success;
+ command.on_error = on_error;
+
+ command.execute();
+ };
+
+ that.search_success = function(data, text_status, xhr) {
+
+ //get options
+ var options = [];
+
+ var entries = data.result.result;
+ for (var i=0; i<data.result.count; i++) {
+ var entry = entries[i];
+ var values = entry[that.other_field];
+ var value = values[0];
+
+ options.push(value);
+ }
+
+ that.set_options(options);
+
+ if (that.on_search_success) that.on_search_success.call(this, data, text_status, xhr);
+ };
+
+ return that;
+};
+
+
+IPA.link_widget = function(spec) {
+ var that = IPA.input_widget(spec);
+
+ that.is_link = spec.is_link || false;
+ that.link_clicked = IPA.observer();
+
+ that.create = function(container) {
+ that.widget_create(container);
+ that.link =
+ $('<a/>', {
+ href: 'jslink',
+ title: '',
+ html: '',
+ click: function() {
+ that.link_clicked.notify([], that);
+ return false;
+ }
+ }).appendTo(container);
+
+ that.nonlink = $('<label/>').
+ appendTo(container);
+ };
+
+ that.update = function (values){
+
+ if (values || values.length > 0) {
+ that.nonlink.text(values[0]);
+ that.link.text(values[0]);
+ if(that.is_link) {
+ that.link.css('display','inline');
+ that.nonlink.css('display','none');
+ } else {
+ that.link.css('display','none');
+ that.nonlink.css('display','inline');
+ }
+ } else {
+ that.link.html('');
+ that.nonlink.html('');
+ that.link.css('display','none');
+ that.nonlink.css('display','none');
+ }
+ };
+
+ that.clear = function() {
+ that.nonlink.text('');
+ that.link.text('');
+ };
+
+
+ return that;
+};
+
+IPA.action_button = function(spec) {
+
+ spec = spec || {};
+
+ var button = $('<a/>', {
+ id: spec.id,
+ name: spec.name,
+ href: spec.href || '#' + (spec.name || 'button'),
+ title: spec.title || spec.label,
+ 'class': 'button action-button',
+ style: spec.style,
+ click: spec.click,
+ blur: spec.blur
+ });
+
+ if (spec['class']) button.addClass(spec['class']);
+
+ if (spec.icon) {
+ $('<span/>', {
+ 'class': 'icon '+spec.icon
+ }).appendTo(button);
+ }
+
+ if (spec.label) {
+ $('<span/>', {
+ 'class': 'button-label',
+ html: spec.label
+ }).appendTo(button);
+ }
+
+ return button;
+};
+
+IPA.button = function(spec) {
+
+ spec = spec || {};
+
+ var button = $('<a/>', {
+ id: spec.id,
+ name: spec.name,
+ href: spec.href || '#' + (spec.name || 'button')
+ });
+
+ var icons = { primary: spec.icon };
+ var label = spec.label;
+
+ button.button({
+ icons: icons,
+ label: label
+ });
+
+ button.click(spec.click);
+
+ return button;
+};
+
+IPA.button_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.href = spec.href;
+ that.style = spec.style;
+ that.click = spec.click;
+ that['class'] = spec['class'];
+ that.disabled_class = 'button-disabled';
+
+ that.on_click = function() {
+
+ if (that.click) {
+ that.click();
+ }
+ return false;
+ };
+
+ that.create = function(container) {
+ that.button = IPA.button({
+ id: that.id,
+ name: that.name,
+ href: that.href,
+ title: that.tooltip,
+ label: that.label,
+ 'class': that['class'],
+ style: that.style,
+ click: that.on_click
+ }).appendTo(container);
+ };
+
+ that.get_enabled = function() {
+
+ var enabled = true;
+
+ if (that.button) {
+ enabled = that.button.hasClass(that.disabled_class);
+ }
+
+ return enabled;
+ };
+
+ that.set_enabled = function(enabled) {
+
+ enabled ? that.enable() : that.disable();
+ };
+
+ that.enable = function() {
+ if (that.button) {
+ that.button.removeClass(that.disabled_class);
+ }
+ };
+
+ that.disable = function() {
+ if (that.button) {
+ that.button.addClass(that.disabled_class);
+ }
+ };
+
+ return that;
+};
+
+IPA.html_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.html = spec.html;
+ that.css_class = spec.css_class;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ if (that.css_class) {
+ container.addClass(that.css_class);
+ }
+
+ if (that.html) {
+ container.append(that.html);
+ }
+ };
+
+ return that;
+};
+
+IPA.composite_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.widgets = IPA.widget_container();
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+ that.widgets.create(container);
+ };
+
+ that.clear = function() {
+
+ var widgets = that.widgets.get_widgets();
+
+ for (var i=0; i< widgets.length; i++) {
+ widgets[i].clear();
+ }
+ };
+
+ that.composite_widget_create = that.create;
+ that.composite_widget_clear = that.clear;
+
+ return that;
+};
+
+IPA.collapsible_section = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.composite_widget(spec);
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ that.header = $('<h2/>', {
+ name: that.name,
+ title: that.label
+ }).appendTo(container);
+
+ that.icon = $('<span/>', {
+ name: 'icon',
+ 'class': 'icon section-expand '+IPA.expanded_icon
+ }).appendTo(that.header);
+
+ that.header.append(' ');
+
+ that.header.append(that.label);
+
+ that.content_container = $('<div/>', {
+ name: that.name,
+ 'class': 'details-section'
+ }).appendTo(container);
+
+ that.header.click(function() {
+ var visible = that.content_container.is(":visible");
+ that.toggle(!visible);
+ });
+
+ that.composite_widget_create(that.content_container);
+ };
+
+ that.toggle = function(visible) {
+
+ that.icon.toggleClass(IPA.expanded_icon, visible);
+ that.icon.toggleClass(IPA.collapsed_icon, !visible);
+
+ if (visible != that.content_container.is(":visible")) {
+ that.content_container.slideToggle('slow');
+ }
+ };
+
+ return that;
+};
+
+IPA.details_section = IPA.collapsible_section;
+
+IPA.layout = function(spec) {
+ return {};
+};
+
+// Creates list of widgets into table with two columns: label and widget
+IPA.table_layout = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.layout(spec);
+ that.table_class = spec.table_class || 'section-table';
+ that.label_cell_class = spec.label_cell_class || 'section-cell-label';
+ that.field_cell_class = spec.field_cell_class || 'section-cell-field';
+ that.label_class = spec.label_class || 'field-label';
+ that.field_class = spec.field_class || 'field';
+
+ that.create = function(widgets) {
+
+ that.rows = $.ordered_map();
+
+ var table = $('<table/>', {
+ 'class': that.table_class
+ });
+
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+ var tr = $('<tr/>');
+ that.rows.put(widget.name, tr);
+
+ if (widget.hidden) {
+ tr.css('display', 'none');
+ }
+
+ tr.appendTo(table);
+
+ var td = $('<td/>', {
+ 'class': that.label_cell_class,
+ title: widget.label
+ }).appendTo(tr);
+
+ var label_text = widget.label + that.get_measurement_unit_text(widget) + ':';
+
+ $('<label/>', {
+ name: widget.name,
+ 'class': that.label_class,
+ text: label_text
+ }).appendTo(td);
+
+ if(widget.create_required) {
+ widget.create_required(td);
+ }
+
+ td = $('<td/>', {
+ 'class': that.field_cell_class,
+ title: widget.label
+ }).appendTo(tr);
+
+ var widget_container = $('<div/>', {
+ name: widget.name,
+ 'class': that.field_class
+ }).appendTo(td);
+
+ widget.create(widget_container);
+ }
+ return table;
+ };
+
+
+ that.get_measurement_unit_text = function(widget) {
+
+ if (widget.measurement_unit) {
+ var unit = IPA.messages.measurement_units[widget.measurement_unit];
+ return ' (' + unit + ')';
+ }
+ return '';
+ };
+
+ return that;
+};
+
+IPA.details_table_section = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.details_section(spec);
+ that.layout = IPA.build_default(spec.layout, IPA.table_layout);
+ that.action_panel = that.build_child(spec.action_panel);
+
+ that.rows = $.ordered_map();
+
+ that.composite_widget_create = function(container) {
+
+ that.widget_create(container);
+
+ if (that.action_panel) {
+ that.action_panel.create(container);
+ }
+ var widgets = that.widgets.get_widgets();
+ var table = that.layout.create(widgets);
+ table.appendTo(container);
+ that.rows = that.layout.rows;
+ };
+
+
+ that.add_row = function(name, row) {
+ that.rows.put(name, row);
+ };
+
+ that.get_row = function(name) {
+ return that.rows.get(name);
+ };
+
+ that.set_row_visible = function(name, visible) {
+ var row = that.get_row(name);
+ row.css('display', visible ? '' : 'none');
+ };
+
+ that.table_section_create = that.composite_widget_create;
+
+ return that;
+};
+
+//non-collabsible section
+IPA.details_table_section_nc = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.details_table_section(spec);
+
+ that.create = that.table_section_create;
+
+ return that;
+};
+
+IPA.multiple_choice_section = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.composite_widget(spec);
+ that.choices = $.ordered_map().put_array(spec.choices, 'name');
+ that.layout = IPA.build_default(spec.layout, IPA.table_layout);
+
+ that.create = function(container) {
+
+ var i, choice, choices;
+
+ that.widget_create(container);
+ that.container.addClass('multiple-choice-section');
+
+ that.header_element = $('<div/>', {
+ 'class': 'multiple-choice-section-header',
+ text: that.label
+ }).appendTo(container);
+
+ that.choice_container = $('<div/>', {
+ 'class': 'choices'
+ }).appendTo(container);
+
+ choices = that.choices.values;
+ for (i=0; i<choices.length; i++) {
+ choice = choices[i];
+ that.create_choice(choice);
+ }
+ };
+
+ that.create_choice = function(choice) {
+
+ var widgets, i, widget, field, section, choice_el, header, radio,
+ enabled, radio_id;
+
+ widgets = [];
+
+ if (choice.widgets) {
+ for (i=0; i<choice.widgets.length; i++) {
+ widget = that.widgets.get_widget(choice.widgets[i]);
+ widgets.push(widget);
+ }
+ } else if (choice.fields) {
+ for (i=0; i<choice.fields.length; i++) {
+ field = that.facet.fields.get_field(choice.fields[i]);
+ widgets.push(field.widget);
+ }
+ }
+
+ choice_el = $('<div/>',{
+ 'class': 'choice',
+ name: choice.name
+ });
+
+ header = $('<div/>',{
+ 'class': 'choice-header'
+ }).appendTo(choice_el);
+
+ enabled = choice.enabled !== undefined ? choice.enabled : false;
+
+ radio_id = that.name + '_' + choice.name;
+
+ $('<input/>',{
+ type: 'radio',
+ name: that.name,
+ id: radio_id,
+ value: choice.name,
+ checked: enabled,
+ change: function() {
+ that.select_choice(this.value);
+ }
+ }).appendTo(header);
+
+ $('<label/>',{
+ text: choice.label,
+ 'for': radio_id
+ }).appendTo(header);
+
+ section = that.layout.create(widgets);
+ section.appendTo(choice_el);
+ choice_el.appendTo(that.choice_container);
+ };
+
+ that.select_choice = function(choice_name) {
+
+ var i, choice, enabled;
+
+ for (i=0; i<that.choices.values.length; i++) {
+ choice = that.choices.values[i];
+ enabled = choice.name === choice_name;
+ that.set_enabled(choice, enabled);
+ }
+ };
+
+ that.set_enabled = function (choice, enabled) {
+
+ var i, field_name, field, fields, required;
+
+ fields = that.facet.fields;
+
+ for (i=0; i<choice.fields.length; i++) {
+ field_name = choice.fields[i];
+ field = fields.get_field(field_name);
+ field.set_enabled(enabled);
+ required = enabled && choice.required.indexOf(field_name) > -1;
+ field.set_required(required);
+ field.validate(); //hide validation errors
+ }
+ };
+
+ that.init_enabled = function() {
+
+ var i, choice;
+
+ for (i=0; i<that.choices.values.length; i++) {
+ choice = that.choices.values[i];
+ if (choice.enabled) {
+ that.select_choice(choice.name);
+ break;
+ }
+ }
+ };
+
+ return that;
+};
+
+IPA.multiple_choice_section_policy = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.facet_policy(spec);
+ that.widget_name = spec.widget;
+
+ that.init = function() {
+ that.widget = that.container.widgets.get_widget(that.widget_name);
+ };
+
+ that.post_create = function() {
+ that.widget.init_enabled();
+ };
+
+ return that;
+};
+
+IPA.enable_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.radio_widget(spec);
+
+ return that;
+};
+
+
+IPA.header_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.widget(spec);
+
+ that.level = spec.level || 3;
+ that.text = spec.text;
+ that.description = spec.description;
+
+ that.create = function(container) {
+ container.append($('<h'+that.level+' />', {
+ text: that.text,
+ title: that.description
+ }));
+ };
+
+ return that;
+};
+
+IPA.observer = function(spec) {
+
+ var that = {};
+
+ that.listeners = [];
+
+ that.attach = function(callback) {
+ that.listeners.push(callback);
+ };
+
+ that.detach = function(callback) {
+ for(var i=0; i < that.listeners.length; i++) {
+ if(callback === that.listeners[i]) {
+ that.listeners.splice(i,1);
+ break;
+ }
+ }
+ };
+
+ that.notify = function(args, context) {
+ args = args || [];
+ context = context || this;
+
+ for(var i=0; i < that.listeners.length; i++) {
+ that.listeners[i].apply(context, args);
+ }
+ };
+
+ return that;
+};
+
+IPA.html_util = function() {
+
+ var that = {};
+ that.id_count = 0;
+
+ that.get_next_id = function(prefix) {
+ that.id_count++;
+ return prefix ? prefix + that.id_count : that.id_count;
+ };
+
+ return that;
+}();
+
+IPA.widget_container = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.new_container_for_child = spec.new_container_for_child !== undefined ?
+ spec.new_container_for_child : true;
+
+ that.widgets = $.ordered_map();
+ that.widget_builder = spec.widget_builder || IPA.widget_builder();
+
+ that.add_widget = function(widget) {
+ that.widgets.put(widget.name, widget);
+ };
+
+ that.get_widget = function(path) {
+
+ var path_len = path.length;
+ var i = path.indexOf('.');
+ var name, child_path, widget, child;
+
+ if (i >= 0) {
+ name = path.substring(0, i);
+ child_path = path.substring(i + 1);
+
+ child = that.widgets.get(name);
+ widget = child.widgets.get_widget(child_path);
+ } else {
+ widget = that.widgets.get(path);
+ }
+
+ return widget;
+ };
+
+ that.get_widgets = function() {
+ return that.widgets.values;
+ };
+
+ that.create = function(container) {
+
+ var widgets = that.widgets.values;
+ for (var i=0; i<widgets.length; i++) {
+ var widget = widgets[i];
+
+ var child_container = container;
+ if(that.new_container_for_child) {
+ child_container = $('<div/>', {
+ name: widget.name,
+ title: widget.label,
+ 'class': widget['class']
+ }).appendTo(container);
+ }
+ widget.create(child_container);
+
+ if(i < widgets.length - 1) {
+ that.create_widget_delimiter(container);
+ }
+ }
+ };
+
+ that.clear = function() {
+
+ var widgets = that.widgets.values;
+ for (var i=0; i<widgets.length; i++) {
+ widgets[i].clear();
+ }
+ };
+
+ that.create_widget_delimiter = function(container) {
+ };
+
+ that.widget_container_create = that.create;
+ that.widget_container_clear = that.clear;
+
+ return that;
+};
+
+IPA.widget_builder = function(spec) {
+
+ spec = spec || {};
+
+ var that = {};
+
+ that.default_factory = spec.default_factory || IPA.text_widget;
+ that.container = spec.container;
+ that.widget_options = spec.widget_options || {};
+
+ that.get_widget_factory = function(spec) {
+
+ var factory;
+ if (spec.factory) {
+ factory = spec.factory;
+ } else if(spec.type) {
+ factory = IPA.widget_factories[spec.type];
+ }
+
+ if (!factory) {
+ factory = that.default_factory;
+ }
+
+ return factory;
+ };
+
+ that.build_widget = function(spec, container) {
+
+ container = container || that.container;
+
+ if(!(spec instanceof Object)) {
+ spec = { name: spec };
+ }
+
+ if(that.widget_options) {
+ $.extend(spec, that.widget_options);
+ }
+
+ var factory = that.get_widget_factory(spec);
+
+ var widget = factory(spec);
+
+ if(container) {
+ container.add_widget(widget);
+ }
+
+ if(spec.widgets) {
+ that.build_widgets(spec.widgets, widget.widgets);
+ }
+
+ return widget;
+ };
+
+ that.build_widgets = function(specs, container) {
+
+ container = container || that.container;
+
+ for(var i=0; i<specs.length; i++) {
+ that.build_widget(specs[i], container);
+ }
+ };
+
+ return that;
+};
+
+IPA.sshkeys_widget = function(spec) {
+
+ spec = spec || {};
+ spec.widget_factory = IPA.sshkey_widget;
+
+ var that = IPA.multivalued_widget(spec);
+
+ that.test_dirty_row = function(row) {
+
+ if(row.deleted || row.is_new) return true;
+
+ var values = row.widget.save();
+
+ var key = values[0];
+ var original_key = row.original_values[0];
+
+ if (original_key && original_key.key && original_key.key !== key) {
+ return true;
+ }
+
+ return false;
+ };
+
+ return that;
+};
+
+IPA.sshkey_widget = function(spec) {
+
+ spec = spec || {};
+
+ var that = IPA.input_widget(spec);
+
+ that.key = null;
+ that.originally_set = false;
+
+ that.create = function(container) {
+
+ that.widget_create(container);
+
+ container.addClass('text-widget');
+
+ that.status_label = $('<span />', {
+ 'class': 'sshkey-status',
+ text: ''
+ }).appendTo(container);
+
+ that.link = $('<a/>', {
+ type: that.type,
+ 'class': 'sshkey-set',
+ name: that.name,
+ href: '#show-certificate',
+ title: that.tooltip,
+ text: IPA.messages.objects.sshkeystore.show_set_key,
+ click: function() {
+ that.open_edit_dialog();
+ return false;
+ }
+ }).appendTo(container);
+
+ if (that.undo) {
+ that.create_undo(container);
+ }
+
+ that.create_error_link(container);
+ };
+
+ that.update = function(values) {
+
+ var key = values && values.length ? values[0] : null;
+
+ if (!key || key === '') {
+ key = {};
+ }
+
+ that.key = $.extend({}, key);
+
+ if (that.key.key && that.key.key !== '' &&
+ that.key.fingerprint && that.key.fingerprint !== '') {
+ that.originally_set = true;
+ that.original_key = that.key.key;
+ }
+ that.update_link();
+ };
+
+ that.set_deleted = function(deleted) {
+ if (deleted) {
+ that.status_label.addClass('strikethrough');
+ } else {
+ that.status_label.removeClass('strikethrough');
+ }
+ };
+
+ that.save = function() {
+ var value = that.key.key;
+ value = value ? [value] : [''];
+ return value;
+ };
+
+ that.update_link = function() {
+ var text = that.get_status();
+ that.status_label.text(text);
+ };
+
+ that.get_status = function() {
+
+ var text = '';
+ var value = that.key.key;
+
+ if (that.original_key) {
+
+ if (value !== that.original_key) {
+ if (value === '') {
+ text = IPA.messages.objects.sshkeystore.status_mod_ns;
+ } else {
+ text = IPA.messages.objects.sshkeystore.status_mod_s;
+ }
+ } else {
+ text = that.key.fingerprint;
+ }
+
+ } else {
+
+ if (!value || value === '') {
+ text = IPA.messages.objects.sshkeystore.status_new_ns;
+ } else {
+ text = IPA.messages.objects.sshkeystore.status_new_s;
+ }
+ }
+
+ return text;
+ };
+
+ that.set_user_value = function(value) {
+
+ var previous = that.key.key;
+ that.key.key = value;
+ that.update_link();
+
+ if (value !== previous) {
+ that.value_changed.notify([], that);
+ }
+ };
+
+ that.open_edit_dialog = function() {
+
+ var dialog = that.create_edit_dialog();
+ dialog.open();
+ };
+
+ that.create_edit_dialog = function() {
+
+ var dialog = IPA.dialog({
+ name: 'sshkey-edit-dialog',
+ title: IPA.messages.objects.sshkeystore.set_dialog_title,
+ width: 500,
+ height: 380
+ });
+
+ dialog.message = IPA.messages.objects.sshkeystore.set_dialog_help;
+
+ dialog.create_button({
+ name: 'update',
+ label: IPA.messages.buttons.set,
+ click: function() {
+ var value = dialog.textarea.val();
+ that.set_user_value(value);
+ dialog.close();
+ }
+ });
+
+ dialog.create_button({
+ name: 'cancel',
+ label: IPA.messages.buttons.cancel,
+ click: function() {
+ dialog.close();
+ }
+ });
+
+ dialog.create = function() {
+
+ dialog.container.append(dialog.message);
+
+ dialog.textarea = $('<textarea/>', {
+ 'class': 'certificate',
+ readonly: that.read_only
+ }).appendTo(dialog.container);
+
+ var key = that.key.key || '';
+ dialog.textarea.val(key);
+ };
+
+ return dialog;
+ };
+
+ return that;
+};
+
+IPA.action_panel = function(spec) {
+
+ spec = spec || {};
+ spec.label = spec.label || IPA.messages.actions.title;
+
+ var that = IPA.widget(spec);
+
+ that.action_names = spec.actions;
+ that.actions = $.ordered_map();
+ that.facet = spec.facet;
+ that.initialized = false;
+
+ that.init = function() {
+
+ for (var i=0; i<that.action_names.length; i++) {
+ var name = that.action_names[i];
+ var action = that.facet.actions.get(name);
+
+ that.add_action(action, true);
+
+ that.actions.put(name, action);
+ }
+
+ that.initialized = true;
+ };
+
+ that.add_action = function(action, batch) {
+ that.actions.put(action.name, action);
+ action.enabled_changed.attach(that.action_enabled_changed);
+ action.visible_changed.attach(that.action_visible_changed);
+
+ if (!batch) {
+ that.create_items();
+ }
+ };
+
+ that.create = function(container) {
+
+ if (!that.initialized) that.init();
+
+ that.element = $('<div/>', {
+ 'data-name': that.name,
+ 'class': 'action-panel'
+ });
+
+ that.header_element = $('<h3/>', {
+ 'class': 'action-title'
+ }).appendTo(that.element);
+
+ that.list_element = $('<ul/>', {
+ 'class': 'action-panel-list'
+ }).appendTo(that.element);
+
+ that.element.appendTo(container);
+
+ that.create_items();
+ };
+
+ that.create_item = function(action) {
+
+ var classes, state, li, a;
+
+ if (!action.visible) return;
+
+ classes = ['action'];
+ state = action.enabled ? 'enabled' : 'disabled';
+ classes.push(state);
+
+ li = $('<li/>');
+ a = $('<a/>', {
+ 'data-name': action.name,
+ href: '#',
+ text: action.label,
+ 'class': classes.join(' '),
+ click: function() {
+ that.action_clicked(action);
+ return false;
+ }
+ }).appendTo(li);
+ li.appendTo(that.list_element);
+ };
+
+ that.clear_items = function() {
+
+ that.list_element.empty();
+ };
+
+ that.create_items = function() {
+
+ if (!that.element) return;
+
+ that.clear_items();
+
+ var actions = that.actions.values;
+
+ for (var i=0; i<actions.length; i++) {
+ var action = actions[i];
+ that.create_item(action);
+ }
+
+ that.header_element.text(that.label);
+ };
+
+ that.action_clicked = function(action) {
+
+ if (!action.enabled || !action.visible) return;
+
+ action.execute(that.facet);
+ };
+
+ that.action_enabled_changed = function() {
+
+ that.create_items();
+ };
+
+ that.action_visible_changed = function() {
+
+ that.create_items();
+ };
+
+
+ return that;
+};
+
+IPA.value_map_widget = function(spec) {
+
+ spec = spec || {};
+ spec.read_only = true;
+
+ var that = IPA.input_widget(spec);
+ that.value_map = spec.value_map || {};
+ that.default_label = spec.default_label || '';
+
+ that.create = function(container) {
+ that.widget_create(container);
+ container.addClass('status-widget');
+
+ that.display_control = $('<span/>', {
+ name: that.name
+ }).appendTo(container);
+ };
+
+ that.update = function(values) {
+
+ var value, found, label;
+
+ found = false;
+
+ if ($.isArray(values)) {
+ for (value in that.value_map) {
+
+ if (!that.value_map.hasOwnProperty(value)) continue;
+
+ if (values.indexOf(value) > -1) {
+ label = that.value_map[value];
+ found = true;
+ }
+ }
+ }
+
+ if (!found) {
+ label = that.default_label;
+ }
+
+ that.display_control.text(label);
+ };
+
+ that.clear = function() {
+ that.display_control.text('');
+ };
+
+ return that;
+};
+
+IPA.widget_factories['attribute_table'] = IPA.attribute_table_widget;
+IPA.widget_factories['button'] = IPA.button_widget;
+IPA.widget_factories['checkbox'] = IPA.checkbox_widget;
+IPA.widget_factories['checkboxes'] = IPA.checkboxes_widget;
+IPA.widget_factories['combobox'] = IPA.combobox_widget;
+IPA.widget_factories['composite_widget'] = IPA.composite_widget;
+IPA.widget_factories['details_table_section'] = IPA.details_table_section;
+IPA.widget_factories['details_table_section_nc'] = IPA.details_table_section_nc;
+IPA.widget_factories['multiple_choice_section'] = IPA.multiple_choice_section;
+IPA.widget_factories['enable'] = IPA.enable_widget;
+IPA.widget_factories['entity_select'] = IPA.entity_select_widget;
+IPA.widget_factories['header'] = IPA.header_widget;
+IPA.widget_factories['html'] = IPA.html_widget;
+IPA.widget_factories['link'] = IPA.link_widget;
+IPA.widget_factories['multivalued'] = IPA.multivalued_widget;
+IPA.widget_factories['password'] = IPA.password_widget;
+IPA.widget_factories['radio'] = IPA.radio_widget;
+IPA.widget_factories['select'] = IPA.select_widget;
+IPA.widget_factories['sshkeys'] = IPA.sshkeys_widget;
+IPA.widget_factories['textarea'] = IPA.textarea_widget;
+IPA.widget_factories['text'] = IPA.text_widget;
+IPA.widget_factories['value_map'] = IPA.value_map_widget; \ No newline at end of file