/* Authors: * Adam Young * Petr Vobornik * * 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 . */ /* CURRENTLY ALSO REQUIRES search.js, because it reuses it's code to create * the AssociationList elements; IT NEEDS IT'S OWN CODE! */ define([ 'dojo/_base/lang', 'dojo/Deferred', './metadata', './ipa', './jquery', './navigation', './phases', './reg', './spec_util', './text', './facet', './search', './dialog'], function(lang, Deferred, metadata_provider, IPA, $, navigation, phases, reg, su, text) { /** * Association module * @class association * @singleton */ var exp = {}; /** * Associator base class * @class */ IPA.associator = function (spec) { spec = spec || {}; var that = IPA.object(); 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; }; /** * Serial associator * This associator is built for the case where each association requires a separate rpc * @class * @extends IPA.associator */ 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 * @class */ 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. * @class * @extends IPA.entity_adder_dialog */ 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 || text.get('@i18n:dialogs.add_title').replace('${entity}', metadata.label); spec.subject = metadata.label; var that = IPA.entity_adder_dialog(spec); that.pkeys = spec.pkeys || []; that.create_add_command = function(record) { var command = that.entity_adder_dialog_create_add_command(record); command.add_args(that.pkeys); return command; }; that.create_buttons = function() { that.buttons.remove('add_and_edit'); }; that.on_add = function() { that.hide_message(); that.add( function(data, text_status, xhr) { if (data.result.completed > 0) { that.added.notify(); that.close(); that.notify_success(data); } }, that.on_error); }; that.create_buttons(); return that; }; /** * This dialog is used for adding associations between two entities. * @class * @extends IPA.adder_dialog */ 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; /** * Map of options for search method * @property {Object} */ that.search_options = spec.search_options; 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.normalize_values(that.get_selected_values()); var exclude = that.normalize_values(that.exclude); var results = data.result; var same_entity = that.entity === that.other_entity; for (var i=0; i= 0) continue; if (selected.indexOf(pkey) >= 0) continue; that.add_available_value(result); } } var options = { all: true }; if (that.search_options) { lang.mixin(options, that.search_options); } 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(); }; that.normalize_values = function(values) { var norm = []; for (var i=0; i -1); return has_indirect; }; var entity = context.entity; su.context_entity(spec, context); 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 = '@i18n:association.add.'+spec.attribute_member; spec.remove_title = '@i18n:association.remove.'+spec.attribute_member; spec.facet_group = spec.facet_group || spec.attribute_member; spec.label = spec.label || entity.metadata.label_singular; spec.tab_label = spec.tab_label || metadata_provider.get('@mo:'+spec.other_entity+'.label') || spec.other_entity; if (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; } /* Link parameter is used to turn off the links in self-service 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( 'refresh', { 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: '@i18n:buttons.refresh', icon: 'fa-refresh' }, { name: 'remove', label: '@i18n:buttons.remove', icon: 'fa-trash-o' }, { name: 'add', label: '@i18n:buttons.add', icon: 'fa-plus' }); 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); entity.policies.add_policy(IPA.build({ $factory: IPA.facet_update_policy, source_facet: 'search', dest_facet: spec.name })); return spec; }; /** * Association facet * @class association.association_facet * @alternateClassName IPA.association_facet * @extends facet.table_facet */ exp.association_facet = IPA.association_facet = function (spec, no_init) { spec = spec || {}; 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 = text.get(spec.add_title || '@i18n:association.add.member'); that.remove_title = text.get(spec.remove_title || '@i18n:association.remove.member'); that.adder_columns = $.ordered_map(); /** * Map of search options for adder dialog * @property {Object} */ that.search_options = spec.search_options; 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', { 'class': 'right-aligned-facet-controls' }).appendTo(that.controls); div.append(text.get('@i18n: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 = $('', { id: direct_id, type: 'radio', name: name, value: 'direct', click: function() { that.association_type = $(this).val(); that.refresh(); return true; } }).appendTo(div); $('