commit 1f1367d62a716e90b04ad647d607d82ddb0d2ce0
Author: Amos Benari <abenari@redhat.com>
Date:   Thu Feb 21 13:28:04 2013 +0200

    fixes #2222 hostgroup form can be scoped by multiple taxonomys.

diff --git a/app/controllers/hosts_controller.rb b/app/controllers/hosts_controller.rb
index 377e806..bd9346a 100644
--- a/app/controllers/hosts_controller.rb
+++ b/app/controllers/hosts_controller.rb
@@ -21,7 +21,7 @@ class HostsController < ApplicationController
     :multiple_puppetrun]
   before_filter :find_by_name, :only => %w[show edit update destroy puppetrun setBuild cancelBuild
     storeconfig_klasses clone pxe_config toggle_manage power console]
-
+  before_filter :taxonomy_scope, :only => [:hostgroup_or_environment_selected, :process_hostgroup]
   helper :hosts, :reports
 
   def index (title = nil)
@@ -129,10 +129,7 @@ class HostsController < ApplicationController
   def hostgroup_or_environment_selected
     return head(:method_not_allowed) unless request.xhr?
 
-    @organization = params[:organization_id] ? Organization.find(params[:organization_id]) : nil
-    @location = params[:location_id] ? Location.find(params[:location_id]) : nil
     Taxonomy.as_taxonomy @organization, @location do
-
       @environment = Environment.find(params[:environment_id]) unless params[:environment_id].empty?
       @hostgroup   = Hostgroup.find(params[:hostgroup_id])     unless params[:hostgroup_id].empty?
       @host        = Host.find(params[:host_id])               if params[:host_id].to_i > 0
@@ -409,10 +406,7 @@ class HostsController < ApplicationController
     @hostgroup = Hostgroup.find(params[:hostgroup_id]) if params[:hostgroup_id].to_i > 0
     return head(:not_found) unless @hostgroup
 
-    @organization = params[:organization_id] ? Organization.find(params[:organization_id]) : nil
-    @location = params[:location_id] ? Location.find(params[:location_id]) : nil
     Taxonomy.as_taxonomy @organization, @location do
-
       @architecture    = @hostgroup.architecture
       @operatingsystem = @hostgroup.operatingsystem
       @environment     = @hostgroup.environment
@@ -486,6 +480,11 @@ class HostsController < ApplicationController
 
   private
 
+  def taxonomy_scope
+    @organization = params[:organization_id].blank? ? nil : params[:organization_id].to_a.map{ |id| Organization.find(id) }
+    @location     = params[:location_id].blank? ? nil : params[:location_id].to_a.map{ |id| Location.find(id) }
+  end
+
   def find_by_name
     # find host first, if we fail, do nothing
     params[:id].downcase! if params[:id].present?
diff --git a/app/helpers/layout_helper.rb b/app/helpers/layout_helper.rb
index f3d4ed8..ecaa12d 100644
--- a/app/helpers/layout_helper.rb
+++ b/app/helpers/layout_helper.rb
@@ -78,26 +73,17 @@ module LayoutHelper
   end
 
   # add hidden field for options[:disabled]
-  def multiple_selects(f, attr, klass, associations, selected_ids, options={}, html_options={})
+  def multiple_selects(f, attr, associations, selected_ids, options={}, html_options={})
     field(f, attr,options) do
       attr_ids = (attr.to_s.singularize+"_ids").to_sym
-      hidden_fields = f.hidden_field(attr_ids, :multiple => true, :value => '')
-      options[:disabled] ||=[]
-      options[:disabled].each do |disabled_value|
-        hidden_fields += f.hidden_field(attr_ids, :multiple => true, :value => disabled_value )
-      end
-      hidden_fields + f.collection_select(attr_ids, associations.all, :id, :to_s ,options.merge(:selected => selected_ids), html_options.merge(:multiple => true))
-    end
-  end
-
-  def multiple_select_array(f, field_name, klass, array_list, selected_ids, options={}, html_options={})
-    field(f, field_name,options) do
-      hidden_fields = f.hidden_field(field_name, :multiple => true, :value => '')
+      hidden_fields = f.hidden_field(attr_ids, :multiple => true, :value => '', :id=>'')
       options[:disabled] ||=[]
       options[:disabled].each do |disabled_value|
-        hidden_fields += f.hidden_field(field_name, :multiple => true, :value => disabled_value )
+        hidden_fields += f.hidden_field(attr_ids, :multiple => true, :value => disabled_value, :id=>'' )
       end
-      hidden_fields + f.select(field_name, options_for_select(array_list, :selected => selected_ids), options,html_options.merge(:multiple => true))
+      hidden_fields + f.collection_select(attr_ids, associations.all.sort_by { |a| a.to_s },
+                                          :id, :to_s ,options.merge(:selected => selected_ids),
+                                          html_options.merge(:multiple => true))
     end
   end
 
diff --git a/app/models/taxonomix.rb b/app/models/taxonomix.rb
index 8aa4875..4b52413 100644
--- a/app/models/taxonomix.rb
+++ b/app/models/taxonomix.rb
@@ -16,13 +16,14 @@ module Taxonomix
 
       def self.with_taxonomy_scope
         scope =  block_given? ? yield : where('1=1')
-        scope = scope.where("#{self.table_name}.id in (#{inner_select(Location.current.id)}) #{user_conditions}") if SETTINGS[:locations_enabled] && Location.current && !Location.current.ignore?(self.to_s)
-        scope = scope.where("#{self.table_name}.id in (#{inner_select(Organization.current.id)}) #{user_conditions}") if SETTINGS[:organizations_enabled] and Organization.current && !Organization.current.ignore?(self.to_s)
+        scope = scope.where("#{self.table_name}.id in (#{inner_select(Location.current)}) #{user_conditions}") if SETTINGS[:locations_enabled] && Location.current && !Location.ignore?(self.to_s)
+        scope = scope.where("#{self.table_name}.id in (#{inner_select(Organization.current)}) #{user_conditions}") if SETTINGS[:organizations_enabled] and Organization.current && !Organization.ignore?(self.to_s)
         scope.readonly(false)
       end
 
-      def self.inner_select taxonomy_id
-        "SELECT taxable_id from taxable_taxonomies WHERE taxable_type = '#{self.name}' AND taxonomy_id in (#{taxonomy_id}) "
+      def self.inner_select taxonomy
+        taxonomy_ids = Array.wrap(taxonomy).map(&:id).join(',')
+        "SELECT taxable_id from taxable_taxonomies WHERE taxable_type = '#{self.name}' AND taxonomy_id in (#{taxonomy_ids}) "
       end
 
       # I the case of users we want the taxonomy scope to get both the users of the taxonomy and admins.
diff --git a/app/models/taxonomy.rb b/app/models/taxonomy.rb
index 1675db6..52eaf09 100644
--- a/app/models/taxonomy.rb
+++ b/app/models/taxonomy.rb
@@ -57,6 +57,13 @@ class Taxonomy < ActiveRecord::Base
     end
   end
 
+  def self.ignore?(taxable_type)
+    Array.wrap(self.current).each{ |current|
+      return true if current.ignore?(taxable_type)
+    }
+    false
+  end
+
   def ignore?(taxable_type)
     if ignore_types.empty?
       false
diff --git a/app/views/taxonomies/_form.html.erb b/app/views/taxonomies/_form.html.erb
index 45f016c..fe08134 100644
--- a/app/views/taxonomies/_form.html.erb
+++ b/app/views/taxonomies/_form.html.erb
@@ -29,14 +29,14 @@
 
       <div class="tab-pane" id="users">
         <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Users", :multiple => true, :onchange => 'ignore_checked(this)'}, "User") %>
-        <%= multiple_selects f, :users, taxonomy, User.except_admin, taxonomy.selected_ids[:user_ids],
+        <%= multiple_selects f, :users, User.except_admin, taxonomy.selected_ids[:user_ids],
            {:disabled => taxonomy.used_and_selected_ids[:user_ids]},
            {'data-mismatches' => taxonomy.need_to_be_selected_ids[:user_ids].to_json} %>
       </div>
 
       <div class="tab-pane" id="smart_proxies">
         <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Smart Proxies", :multiple => true, :onchange => 'ignore_checked(this)'}, "SmartProxy") %>
-        <%= multiple_selects f, :smart_proxies, taxonomy, SmartProxy, taxonomy.selected_ids[:smart_proxy_ids],
+        <%= multiple_selects f, :smart_proxies, SmartProxy, taxonomy.selected_ids[:smart_proxy_ids],
            {:disabled => taxonomy.used_and_selected_ids[:smart_proxy_ids]},
            {'data-mismatches' => taxonomy.need_to_be_selected_ids[:smart_proxy_ids].to_json} %>
       </div>
@@ -44,35 +44,35 @@
       <% if SETTINGS[:unattended] %>
         <div class="tab-pane" id="subnets">
           <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Subnets", :multiple => true, :onchange => 'ignore_checked(this)'}, "Subnet") %>
-          <%= multiple_selects f, :subnets, taxonomy, Subnet, taxonomy.selected_ids[:subnet_ids],
+          <%= multiple_selects f, :subnets, Subnet, taxonomy.selected_ids[:subnet_ids],
                                {:disabled => taxonomy.used_and_selected_ids[:subnet_ids]},
                                {'data-mismatches' => taxonomy.need_to_be_selected_ids[:subnet_ids].to_json} %>
         </div>
 
         <div class="tab-pane" id="compute_resources">
           <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Compute Resources", :multiple => true, :onchange => 'ignore_checked(this)'}, "ComputeResource") %>
-          <%= multiple_selects f, :compute_resources, taxonomy, ComputeResource, taxonomy.selected_ids[:compute_resource_ids],
+          <%= multiple_selects f, :compute_resources, ComputeResource, taxonomy.selected_ids[:compute_resource_ids],
                                {:disabled => taxonomy.used_and_selected_ids[:compute_resource_ids]},
                                {'data-mismatches' => taxonomy.need_to_be_selected_ids[:compute_resource_ids].to_json} %>
         </div>
 
         <div class="tab-pane" id="media">
           <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Media", :multiple => true, :onchange => 'ignore_checked(this)'}, "Medium") %>
-          <%= multiple_selects f, :media, taxonomy, Medium, taxonomy.selected_ids[:medium_ids],
+          <%= multiple_selects f, :media, Medium, taxonomy.selected_ids[:medium_ids],
                                {:disabled => taxonomy.used_and_selected_ids[:medium_ids]},
                                {'data-mismatches' => taxonomy.need_to_be_selected_ids[:medium_ids].to_json} %>
         </div>
 
         <div class="tab-pane" id="template">
           <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Templates", :multiple => true, :onchange => 'ignore_checked(this)'}, "ConfigTemplate") %>
-          <%= multiple_selects f, :config_templates, taxonomy, ConfigTemplate, taxonomy.selected_ids[:config_template_ids],
+          <%= multiple_selects f, :config_templates, ConfigTemplate, taxonomy.selected_ids[:config_template_ids],
                                {:disabled => taxonomy.used_and_selected_ids[:config_template_ids]},
                                {'data-mismatches' => taxonomy.need_to_be_selected_ids[:config_template_ids].to_json} %>
         </div>
 
         <div class="tab-pane" id="domains">
           <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Domains", :multiple => true, :onchange => 'ignore_checked(this)'}, "Domain") %>
-          <%= multiple_selects f, :domains, taxonomy, Domain, taxonomy.selected_ids[:domain_ids],
+          <%= multiple_selects f, :domains, Domain, taxonomy.selected_ids[:domain_ids],
                                {:disabled => taxonomy.used_and_selected_ids[:domain_ids]},
                                {'data-mismatches' => taxonomy.need_to_be_selected_ids[:domain_ids].to_json} %>
         </div>
@@ -80,27 +80,27 @@
 
       <div class="tab-pane" id="environments">
         <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Environments", :multiple => true, :onchange => 'ignore_checked(this)'}, "Environment") %>
-        <%= multiple_selects f, :environments, taxonomy, Environment, taxonomy.selected_ids[:environment_ids],
+        <%= multiple_selects f, :environments, Environment, taxonomy.selected_ids[:environment_ids],
             {:disabled => taxonomy.used_and_selected_ids[:environment_ids]},
             {'data-mismatches' => taxonomy.need_to_be_selected_ids[:environment_ids].to_json} %>
       </div>
 
       <div class="tab-pane" id="hostgroups">
         <%= checkbox_f(f, :ignore_types, {:label => "", :help_inline => "All Hostgroups", :multiple => true, :onchange => 'ignore_checked(this)'}, "Hostgroup") %>
-        <%= multiple_selects f, :hostgroups, taxonomy, Hostgroup, taxonomy.selected_ids[:hostgroup_ids],
+        <%= multiple_selects f, :hostgroups, Hostgroup, taxonomy.selected_ids[:hostgroup_ids],
             {:disabled => taxonomy.used_and_selected_ids[:hostgroup_ids]},
             {'data-mismatches' => taxonomy.need_to_be_selected_ids[:hostgroup_ids].to_json} %>
      </div>
 
       <% if taxonomy.is_a?(Location) && SETTINGS[:locations_enabled] %>
         <div class="tab-pane" id="organizations">
-          <%= multiple_selects f, :organizations, taxonomy, Organization, taxonomy.selected_ids[:organization_ids],
+          <%= multiple_selects f, :organizations, Organization, taxonomy.selected_ids[:organization_ids],
             {:disabled => taxonomy.used_and_selected_ids[:organization_ids]},
             {'data-mismatches' => taxonomy.need_to_be_selected_ids[:organization_ids].to_json} %>
         </div>
       <% elsif taxonomy.is_a?(Organization) && SETTINGS[:organizations_enabled] %>
         <div class="tab-pane" id="locations">
-          <%= multiple_selects f, :locations, taxonomy, Location, taxonomy.selected_ids[:location_ids],
+          <%= multiple_selects f, :locations, Location, taxonomy.selected_ids[:location_ids],
             {:disabled => taxonomy.used_and_selected_ids[:location_ids]},
             {'data-mismatches' => taxonomy.need_to_be_selected_ids[:location_ids].to_json} %>
         </div>
diff --git a/lib/foreman/controller/host_details.rb b/lib/foreman/controller/host_details.rb
index 29cdb92..b2869bc 100644
--- a/lib/foreman/controller/host_details.rb
+++ b/lib/foreman/controller/host_details.rb
@@ -20,8 +20,7 @@ module Foreman::Controller::HostDetails
     respond_to do |format|
       format.html {assign_parameter "domain", "common/"}
       format.json do
-        @organization = params[:organization_id].blank? ? nil : Organization.find(params[:organization_id])
-        @location     = params[:location_id].blank? ? nil : Location.find(params[:location_id])
+        taxonomy_scope
         Taxonomy.as_taxonomy @organization, @location do
           if (domain = Domain.find(params[:domain_id]))
             render :json => domain.subnets
@@ -40,8 +39,7 @@ module Foreman::Controller::HostDetails
 
   private
   def assign_parameter name, root = ""
-    @organization = params[:organization_id] ? Organization.find(params[:organization_id]) : nil
-    @location = params[:location_id] ? Location.find(params[:location_id]) : nil
+    taxonomy_scope
     Taxonomy.as_taxonomy @organization, @location do
       if params["#{name}_id"].to_i > 0 and eval("@#{name} = #{name.capitalize}.find(params['#{name}_id'])")
         item = eval("@#{controller_name.singularize} || #{controller_name.singularize.capitalize}.new(params[:#{controller_name.singularize}])")
@@ -63,4 +61,9 @@ module Foreman::Controller::HostDetails
     eval("@#{name} = #{name.capitalize}.new params[:#{name}]")
   end
 
+  def taxonomy_scope
+    @organization = params[:organization_id].blank? ? nil : params[:organization_id].to_a.map{ |id| Organization.find(id) }
+    @location     = params[:location_id].blank? ? nil : params[:location_id].to_a.map{ |id| Location.find(id) }
+  end
+
 end
diff --git a/lib/foreman/thread_session.rb b/lib/foreman/thread_session.rb
index fee1ff0..4bf3e42 100644
--- a/lib/foreman/thread_session.rb
+++ b/lib/foreman/thread_session.rb
@@ -83,7 +83,7 @@ module Foreman
           end
 
           def self.current=(organization)
-            unless organization.nil? || organization.is_a?(self)
+            unless organization.nil? || organization.is_a?(self) || organization.is_a?(Array)
               raise(ArgumentError, "Unable to set current organization, expected class '#{self}', got #{organization.inspect}")
             end
 
@@ -118,7 +118,7 @@ module Foreman
           end
 
           def self.current=(location)
-            unless location.nil? || location.is_a?(self)
+            unless location.nil? || location.is_a?(self) || location.is_a?(Array)
               raise(ArgumentError, "Unable to set current location, expected class '#{self}'. got #{location.inspect}")
             end
 
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index ae79602..32c557f 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -325,7 +325,16 @@ function attribute_hash(attributes){
   var attrs = {};
   for (i=0;i < attributes.length; i++) {
     var attr = $('*[id*='+attributes[i]+']');
-    if (attr.size() > 0) { attrs[attributes[i]] = attr.val(); }
+    if (attr.size() > 0) {
+      if(attr.attr("type")=="checkbox"){
+        attrs[attributes[i]] = [];
+        $("*[id*="+attributes[i]+"]:checked").each(function(index,item){
+          attrs[attributes[i]].push($(item).val());
+        })
+      }else{
+        attrs[attributes[i]] = attr.val();
+      }
+    }
   }
   return attrs;
 }
diff --git a/public/javascripts/host_edit.js b/public/javascripts/host_edit.js
index a161e97..5dc0cac 100644
--- a/public/javascripts/host_edit.js
+++ b/public/javascripts/host_edit.js
@@ -181,7 +181,7 @@ function load_puppet_class_parameters(item) {
   if ($('[id^="#puppetclass_' + id + '_params\\["]').length > 0) return; // already loaded
 
   var url = $(item).attr('data-url');
-  var data = $("form").serialize().replace('method=put', 'method=post');;
+  var data = $("form").serialize().replace('method=put', 'method=post');
 
   if (url == undefined) return; // no parameters
   var placeholder = $('<tr id="puppetclass_'+id+'_params_loading">'+
@@ -328,8 +328,7 @@ function architecture_selected(element){
 }
 
 function os_selected(element){
-  var attrs   = attribute_hash(['operatingsystem_id', 'organization_id', 'location_id']);
-  var os_id = $(element).val();
+  var attrs = attribute_hash(['operatingsystem_id', 'organization_id', 'location_id']);
   var url = $(element).attr('data-url');
   $.ajax({
     data: attrs,
@@ -436,7 +435,7 @@ function override_class_param(item){
 
 function reload_params(){
   var url = $('#params-tab').attr('data-url');
-  var data = $("[data-submit='progress_bar']").serialize();
+  var data = $("[data-submit='progress_bar']").serialize().replace('method=put', 'method=post');
   load_with_placeholder('inherited_parameters', url, data)
 
   var url2 = $('#params-tab').attr('data-url2');
@@ -444,6 +443,7 @@ function reload_params(){
 }
 
 function load_with_placeholder(target, url, data){
+  if(url==undefined) return;
   var placeholder = $('<tr id="' + target + '_loading" >'+
             '<td colspan="4"><p><img src="/images/spinner.gif" alt="Wait" /> Loading parameters...</p></td></tr>');
         $('#' + target + ' tbody').replaceWith(placeholder);
