From 5a428608beb3752b111b558ba2355ef112a057f1 Mon Sep 17 00:00:00 2001 From: Petr Vobornik Date: Wed, 28 May 2014 14:45:57 +0200 Subject: webui: move RPC result extraction logic to Adapter It enables declarative extraction of values from partial results of a batch commands and also further extensibility in custom adapters. The default adapter has detection logic for this extraction so it can use bare record or extract data from normal or batch RPC command. Minor change of user plugin fixed: https://fedorahosted.org/freeipa/ticket/4355 Reviewed-By: Endi Sukma Dewata --- install/ui/src/freeipa/automember.js | 2 +- install/ui/src/freeipa/details.js | 39 ++++++++++++++----- install/ui/src/freeipa/dns.js | 19 ++------- install/ui/src/freeipa/field.js | 74 +++++++++++++++++++++++++++++------- install/ui/src/freeipa/rule.js | 6 +-- install/ui/src/freeipa/service.js | 6 ++- install/ui/src/freeipa/user.js | 65 ++++++++++--------------------- install/ui/src/freeipa/util.js | 3 -- 8 files changed, 122 insertions(+), 92 deletions(-) (limited to 'install/ui/src/freeipa') diff --git a/install/ui/src/freeipa/automember.js b/install/ui/src/freeipa/automember.js index 95f6960d2..5eff3e69b 100644 --- a/install/ui/src/freeipa/automember.js +++ b/install/ui/src/freeipa/automember.js @@ -455,7 +455,7 @@ IPA.automember.condition_field = function(spec) { IPA.automember.condition_adapter = declare([field_mod.Adapter], { - load: function(record) { + load: function(data) { var regexes = this.inherited(arguments); var values = []; if (regexes) { diff --git a/install/ui/src/freeipa/details.js b/install/ui/src/freeipa/details.js index a3aac27c7..b7fa36469 100644 --- a/install/ui/src/freeipa/details.js +++ b/install/ui/src/freeipa/details.js @@ -237,15 +237,15 @@ exp.section_builder = IPA.section_builder = function(spec) { */ that.build_section = function(section_spec, index) { - var spec = section_spec; + var spec = {}; var overrides = {}; var spec_type = typeof that.section_spec; if (spec_type === 'object') { spec = lang.mixin({}, that.section_spec); - spec = lang.mixin(spec, section_spec); } else if (spec_type === "function") { overrides = that.section_spec; } + spec = lang.mixin(spec, section_spec); if (!spec.label && spec.name && that.container.entity) { var section_label = '@i18n:objects.'+that.container.entity.name+ @@ -261,7 +261,9 @@ exp.section_builder = IPA.section_builder = function(spec) { }, overrides); that.container.widgets.add_widget(section); + section.$field_adapter = spec.field_adapter; that.create_fields(section, spec.fields); + delete section.$field_adapter; }; /** @@ -283,8 +285,18 @@ exp.section_builder = IPA.section_builder = function(spec) { */ that.create_field = function(section, field_spec) { + if (typeof field_spec === 'string') { + field_spec = { + name: field_spec + }; + } + var widget = that.widget_builder.build_widget(field_spec, section.widgets); + if (section.$field_adapter && !field_spec.adapter) { + field_spec.adapter = section.$field_adapter; + } + //spec.$factory refers to widget factory if(field_spec.$factory) delete field_spec.$factory; @@ -714,7 +726,7 @@ exp.details_facet = IPA.details_facet = function(spec, no_init) { var fields = that.fields.get_fields(); for (var i=0; i -1; @@ -740,10 +741,10 @@ field.field = IPA.field = function(spec) { }; /** - * Adapter's task is to select wanted data from record and vice-versa. + * Adapter's task is to select wanted data from RPC response * - * This default adapter expects that context will be field and record - * will be FreeIPA JsonRPC result. + * This default adapter expects that context will be a field and data + * will be FreeIPA JsonRPC response. * * @class */ @@ -756,6 +757,41 @@ field.Adapter = declare(null, { */ context: null, + /** + * Index of result in batch results array + * @type {Number} + */ + result_index: 0, + + /** + * Extract record from RPC call response + * + * Tries to detect if supplied data is RPC call response if so, it + * extracts the record. Otherwise it returns supplied data as the record. + * + * @param {Object} data Response data or record + * @return {Object} record + */ + get_record: function(data) { + + // detection if it's result or raw RPC command response + // all raw responses should contain `version` and `principal` + if (!data.version || !data.principal) { + return data; + } + + var dr = data.result; + var record = null; + if (dr) { + if (dr.result) record = dr.result; + else if (dr.results) { + var result = dr.results[this.result_index]; + if (result) record = result.result; + } + } + return record; + }, + /** * Get single value from record * @param {Object} record Record @@ -772,13 +808,21 @@ field.Adapter = declare(null, { * By default just select attribute with name defined by `context.param` * from a record. Uses default value if value is not in record and context * defines it. - * @param {Object} record + * @param {Object} data Object which contains the record or the record + * @param {string} [attribute] attribute name - overrides `context.param` + * @param {Mixed} [def_val] default value - overrides `context.default_value` * @returns {Array} attribute value */ - load: function(record) { - var value = this.get_value(record, this.context.param); - if (util.is_empty(value) && !util.is_empty(this.context.default_value)) { - value = util.normalize_value(this.context.default_value); + load: function(data, attribute, def_val) { + var record = this.get_record(data); + var value = null; + var attr = attribute || this.context.param; + var def = def_val || this.context.default_value; + if (record) { + value = this.get_value(record, attr); + } + if (util.is_empty(value) && !util.is_empty(def)) { + value = util.normalize_value(def); } return value; }, @@ -803,6 +847,7 @@ field.Adapter = declare(null, { }, constructor: function(spec) { + declare.safeMixin(this, spec); this.context = spec.context || {}; } }); @@ -1127,7 +1172,9 @@ field.SshKeysAdapter = declare([field.Adapter], { * ] * """ */ - load: function(record) { + load: function(data) { + + var record = this.get_record(data); var keys = this.get_value(record, this.context.param); var fingerprints = this.get_value(record, 'sshpubkeyfp'); var values = []; @@ -1392,6 +1439,7 @@ reg.set('validator', field.validator_builder.registry); * @member field */ field.adapter_builder = builder.get('adapter'); +field.adapter_builder.ctor = field.Adapter; field.adapter_builder.post_ops.push(function(obj, spec, context) { obj.context = context.context; return obj; diff --git a/install/ui/src/freeipa/rule.js b/install/ui/src/freeipa/rule.js index 7ad08e1f2..11a8e8201 100644 --- a/install/ui/src/freeipa/rule.js +++ b/install/ui/src/freeipa/rule.js @@ -193,12 +193,12 @@ IPA.rule_association_table_field = function(spec) { } }; - that.load = function(result) { - that.values = result[that.param] || []; + that.load = function(data) { + that.values = that.adapter.load(data); if (that.external) { that.set_values_external(that.values, ''); - var external_values = result[that.external] || []; + var external_values = that.adapter.load(data, that.external, []); that.set_values_external(external_values, 'true'); $.merge(that.values, external_values); } diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js index 82f9ab3b3..4b04878c0 100644 --- a/install/ui/src/freeipa/service.js +++ b/install/ui/src/freeipa/service.js @@ -269,7 +269,8 @@ IPA.service_adder_dialog = function(spec) { }; IPA.service_name_adapter = declare([field_mod.Adapter], { - load: function(record) { + load: function(data) { + var record = this.get_record(data); var krbprincipalname = record.krbprincipalname[0]; var value = krbprincipalname.replace(/\/.*$/, ''); return [value]; @@ -277,7 +278,8 @@ IPA.service_name_adapter = declare([field_mod.Adapter], { }); IPA.service_host_adapter = declare([field_mod.Adapter], { - load: function(record) { + load: function(data) { + var record = this.get_record(data); var krbprincipalname = record.krbprincipalname[0]; var value = krbprincipalname.replace(/^.*\//, '').replace(/@.*$/, ''); return [value]; diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js index 270f0b2cc..c5b9686a0 100644 --- a/install/ui/src/freeipa/user.js +++ b/install/ui/src/freeipa/user.js @@ -153,6 +153,7 @@ return { { name: 'pwpolicy', label: '@i18n:objects.pwpolicy.identity', + field_adapter: { result_index: 1 }, fields: [ { name: 'krbmaxpwdlife', @@ -202,6 +203,7 @@ return { { name: 'krbtpolicy', label: '@i18n:objects.krbtpolicy.identity', + field_adapter: { result_index: 2 }, fields: [ { name: 'krbmaxrenewableage', @@ -272,9 +274,15 @@ return { { $factory: IPA.enable_state_evaluator, field: 'nsaccountlock', + adapter: { $type: 'batch', result_index: 0 }, invert_value: true }, - IPA.user.reset_password_acl_evaluator + { + $factory: IPA.acl_state_evaluator, + name: 'reset_password_acl_evaluator', + adapter: { $type: 'batch', result_index: 0 }, + attribute: 'userpassword' + } ], summary_conditions: [ IPA.enabled_summary_cond, @@ -358,12 +366,6 @@ IPA.user.details_facet = function(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 = that.get_pkey(); @@ -373,19 +375,12 @@ IPA.user.details_facet = function(spec) { }); 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 = rpc.command({ entity: 'pwpolicy', method: 'show', + retry: false, options: { user: pkey, all: true, @@ -394,16 +389,11 @@ IPA.user.details_facet = function(spec) { }); 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