klastera 1.1.5 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/assets/stylesheets/klastera/clusters.css.scss +11 -0
  4. data/app/models/klastera/cluster_entity.rb +5 -0
  5. data/app/models/klastera/concerns/cluster_entity.rb +12 -0
  6. data/app/models/klastera/concerns/cluster_user.rb +7 -8
  7. data/app/models/klastera/concerns/clusterizable.rb +24 -4
  8. data/app/models/klastera/concerns/user.rb +23 -2
  9. data/app/views/layouts/klastera/_cluster_entity_fields.html.erb +10 -0
  10. data/app/views/layouts/klastera/_cluster_filter.html.erb +1 -1
  11. data/app/views/layouts/klastera/_cluster_user_fields.html.erb +2 -2
  12. data/app/views/layouts/klastera/_nested_cluster_entity.html.erb +41 -0
  13. data/app/views/layouts/klastera/_nested_cluster_user.html.erb +18 -16
  14. data/app/views/layouts/klastera/_options.html.erb +1 -1
  15. data/config/locales/es.yml +2 -0
  16. data/db/migrate/20200518142609_create_klastera_cluster_entities.rb +8 -0
  17. data/lib/klastera.rb +91 -28
  18. data/lib/klastera/version.rb +2 -2
  19. data/lib/tasks/klastera_tasks.rake +23 -0
  20. metadata +8 -75
  21. data/app/assets/stylesheets/klastera/application.css +0 -15
  22. data/app/assets/stylesheets/klastera/clusters.css +0 -4
  23. data/app/assets/stylesheets/scaffold.css +0 -56
  24. data/test/dummy/README.rdoc +0 -28
  25. data/test/dummy/Rakefile +0 -6
  26. data/test/dummy/app/assets/javascripts/application.js +0 -13
  27. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  28. data/test/dummy/app/controllers/application_controller.rb +0 -5
  29. data/test/dummy/app/helpers/application_helper.rb +0 -2
  30. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  31. data/test/dummy/bin/bundle +0 -3
  32. data/test/dummy/bin/rails +0 -4
  33. data/test/dummy/bin/rake +0 -4
  34. data/test/dummy/bin/setup +0 -29
  35. data/test/dummy/config.ru +0 -4
  36. data/test/dummy/config/application.rb +0 -26
  37. data/test/dummy/config/boot.rb +0 -5
  38. data/test/dummy/config/database.yml +0 -1
  39. data/test/dummy/config/environment.rb +0 -5
  40. data/test/dummy/config/environments/development.rb +0 -41
  41. data/test/dummy/config/environments/production.rb +0 -79
  42. data/test/dummy/config/environments/test.rb +0 -42
  43. data/test/dummy/config/initializers/assets.rb +0 -11
  44. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  45. data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  46. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  47. data/test/dummy/config/initializers/inflections.rb +0 -16
  48. data/test/dummy/config/initializers/mime_types.rb +0 -4
  49. data/test/dummy/config/initializers/session_store.rb +0 -3
  50. data/test/dummy/config/initializers/to_time_preserves_timezone.rb +0 -10
  51. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  52. data/test/dummy/config/locales/en.yml +0 -23
  53. data/test/dummy/config/routes.rb +0 -4
  54. data/test/dummy/config/secrets.yml +0 -22
  55. data/test/dummy/public/404.html +0 -67
  56. data/test/dummy/public/422.html +0 -67
  57. data/test/dummy/public/500.html +0 -66
  58. data/test/dummy/public/favicon.ico +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d4f51a31ad550a707ac854779af0d6335062752af2bf79eeb41e23eefc0ddce
4
- data.tar.gz: 4abd8e21893258c0dd037d7596168a9266247441be74a751c0d6ee8ae2231796
3
+ metadata.gz: 3d1ff69c5abf0d989e26c1bfa2be9da2f8c9f5e8100bd4670f1c70d05c91cb13
4
+ data.tar.gz: 3bda3826a8d07270008bd4789ecc0eee72706984d9e3065f64bcc7475b844296
5
5
  SHA512:
6
- metadata.gz: 29c527c10bbb047607183891488a773655ff8d394ca28961e9745dd067cf77f0a8aa6012f096d334c3209a70e4adb1359b0623b4f3a28dd3d9dca08594328783
7
- data.tar.gz: d55827e7deaa63de06c32a27a0ece3df1217d8eb4a553e1cdedee6b0efd882d33c77e9bcc9a574e89f0c7c7ae4ba4c7380c1ac74e3db79eef5f7892b4c6d62b4
6
+ metadata.gz: 39e4ec148db926bd2881d1e88e45b4c6071eccbd9aee45964e5c8d547d83f7513e6b1fc9882dfd6c1b06fe2bd146f0153aa935f4869809e09c554736ca8288e3
7
+ data.tar.gz: '09cbc4eb782c613ddfa68c4704dc6511ba77c49137539b2fc7d52c084e25a5ecfc28e52b38231081ddbea920468eac23aadca10449009196bd25a7d7c36e46d0'
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
14
14
  rdoc.rdoc_files.include('lib/**/*.rb')
15
15
  end
16
16
 
17
- APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
17
+ #APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
18
  load 'rails/tasks/engine.rake'
19
19
 
20
20
 
@@ -0,0 +1,11 @@
1
+ .nested-cluster-user,
2
+ .nested-cluster-entity {
3
+ .panel {
4
+ margin: 0;
5
+ border-bottom: 0;
6
+ .panel-heading {
7
+ padding: 10px 12px 10px 15px;
8
+ background: none;
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,5 @@
1
+ module Klastera
2
+ class ClusterEntity < ActiveRecord::Base
3
+ include Klastera::Concerns::ClusterEntity
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module Klastera::Concerns::ClusterEntity
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ self.table_name = 'cluster_entities'
6
+ belongs_to :entity, polymorphic: true
7
+ belongs_to :cluster, class_name: ::Cluster
8
+ end
9
+
10
+ module ClassMethods
11
+ end
12
+ end
@@ -7,11 +7,10 @@ module Klastera::Concerns::ClusterUser
7
7
  belongs_to :user
8
8
  belongs_to :cluster
9
9
 
10
- validates :user_id, presence: true
11
10
  validates :cluster_id, presence: true
12
11
 
13
12
  scope :of, -> (user,organization) {
14
- Rails.logger.warn("DON'T USE THIS SCOPE DIRECTLY: Use ::ClusterUser.get_from class method instead!")
13
+ Rails.logger.warn("DON'T USE THIS SCOPE DIRECTLY: Use ::ClusterUser.clusters_from class method instead!")
15
14
  includes(:cluster).where(user_id: user, "clusters.organization_id": organization)
16
15
  }
17
16
  end
@@ -21,13 +20,13 @@ module Klastera::Concerns::ClusterUser
21
20
  ##
22
21
  # Returns a hash with the users with cluster relation
23
22
  #
24
- def get_user_clusters_from(organization)
23
+ def user_clusters_from(organization)
25
24
  users_hash = {}
26
25
  organization_cluster_ids = ::Cluster.of(organization).map(&:id)
27
- ::ClusterUser.includes(:user).where(cluster_id: organization_cluster_ids).each do |cluster|
28
- user_id = cluster.user.id
29
- users_hash[user_id] ||= [];
30
- users_hash[user_id] << cluster.id
26
+ ::ClusterUser.includes(:user).where(cluster_id: organization_cluster_ids).each do |cluster_user|
27
+ user_id = cluster_user.user_id || :uncluster
28
+ users_hash[user_id] ||= []
29
+ users_hash[user_id] << cluster_user.cluster_id
31
30
  end
32
31
  users_hash
33
32
  end
@@ -36,7 +35,7 @@ module Klastera::Concerns::ClusterUser
36
35
  # Returns a Cluster::ActiveRecord_Relation
37
36
  #
38
37
  ##
39
- def get_clusters_from(user,organization)
38
+ def clusters_from(user,organization)
40
39
  clusters = []
41
40
  unless user.can_admin_clusters?
42
41
  # We could return cu.clusters but you may quering this result and a array can't handle order, where and etc.
@@ -4,16 +4,36 @@ module Klastera::Concerns::Clusterizable
4
4
  attr_accessor :lonely_cluster
5
5
  belongs_to :cluster
6
6
 
7
- validates :cluster_id, presence: true, if: proc { self.organization.required_suborganization_mode? }
7
+ has_many :cluster_entities, as: :entity, class_name: Klastera::ClusterEntity
8
+ accepts_nested_attributes_for :cluster_entities, reject_if: :all_blank, allow_destroy: true
9
+
10
+ validates :cluster_id, presence: true, if: proc { self.try(:cluster_id) && self.organization.required_suborganization_mode? }
11
+ validate :at_least_one_cluster_entity, if: proc { self.organization.required_suborganization_mode? }
8
12
 
9
13
  scope :related_clusters, ->() {
10
- includes(:cluster).where("#{self.table_name}.cluster_id IS NOT NULL")
14
+ includes(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
11
15
  }
16
+
17
+ def at_least_one_cluster_entity
18
+ if cluster_entities.length == 0 || cluster_entities.reject{|cluster_entity| cluster_entity._destroy == true}.empty?
19
+ return errors.add(:cluster_entities, I18n.t('klastera.messages.at_least_one_cluster_entity'))
20
+ end
21
+ end
22
+
23
+ def clusters_string_separated_by(separator)
24
+ self.cluster_entities.map{|ce|ce.cluster.name}.join(separator)
25
+ end
26
+
27
+ def has_one_cluster_entity
28
+ if cluster_entities.length > 1
29
+ return errors.add(:cluster_entities, I18n.t('klastera.messages.has_one_cluster_entity'))
30
+ end
31
+ end
12
32
  end
13
33
 
14
34
  module ClassMethods
15
- def cluster_params
16
- [ :cluster_id, :lonely_cluster ]
35
+ def cluster_entity_params
36
+ [ :cluster_id, :lonely_cluster, { cluster_entities_attributes: [:id, :cluster_id, :_destroy] } ]
17
37
  end
18
38
  end
19
39
  end
@@ -14,8 +14,6 @@ module Klastera::Concerns::User
14
14
  validates :cluster_role, presence: true, if: proc{ self.organization.is_in_cluster_mode? }
15
15
  validates :cluster_role, inclusion: { in: CLUSTER_ROLES , message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ cluster_role.present? }
16
16
  validate :at_least_one_role, if: proc{ self.use_cluster? && self.try(:need_cluster_assignation?) }
17
- before_destroy do |record|
18
- end
19
17
 
20
18
  def use_cluster?; self.cluster_role.present?; end
21
19
 
@@ -35,6 +33,29 @@ module Klastera::Concerns::User
35
33
  self.organization.is_in_cluster_mode? && ( self.is_a_cluster_admin? || self.is_a_cluster_root? )
36
34
  end
37
35
 
36
+ #
37
+ # We will try to create a cluster_user record whether
38
+ # the organization is using force mode (if cluster_id isn't present, it will raise a validation error)
39
+ # or
40
+ # cluster_id is present (on show/use mode organizations).
41
+ #
42
+ def try_to_clusterify!(role,cluster_ids)
43
+ if self.try(:organization).try(:is_in_cluster_mode?)
44
+ self.cluster_role = role
45
+ if self.try(:organization).try(:required_suborganization_mode?) || cluster_ids.present?
46
+ timestamp = DateTime.now.to_i
47
+ nested_attributes = {}
48
+ cluster_ids.each do |cluster_id|
49
+ nested_attributes["#{cluster_id}_#{timestamp}"] = {
50
+ cluster_id: cluster_id,
51
+ _destroy: false
52
+ }
53
+ end
54
+ self.cluster_users_attributes = nested_attributes
55
+ end
56
+ end
57
+ end
58
+
38
59
  private
39
60
 
40
61
  def at_least_one_role
@@ -0,0 +1,10 @@
1
+ <tr class="nested-fields">
2
+ <td class="field">
3
+ <%= f.select :cluster_id, cluster_clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
4
+ </td>
5
+ <td class="action vertical-align-middle text-center" width="44">
6
+ <%= link_to_remove_association f, class: 'btn btn-danger btn-xs text-danger' do %>
7
+ <i class="fa fa-trash"></i>
8
+ <% end %>
9
+ </td>
10
+ </tr>
@@ -4,7 +4,7 @@
4
4
  <%= button_tag(t('klastera.actions.filter'), class: 'btn btn-primary btn-sm float-right', data: { disable_with: "<i class='fa fa-spinner spin'></i>" }) %>
5
5
  </div>
6
6
 
7
- <%=yield(f)%>
7
+ <%=yield(f) if block_given? %>
8
8
 
9
9
  <% if cluster_organization.is_in_cluster_mode? %>
10
10
  <% cluster_collection = cluster_clusters.map{|c|[c.name,(c.id||c.nid)]} %>
@@ -1,8 +1,8 @@
1
1
  <tr class="nested-fields">
2
2
  <td class="field">
3
3
  <%= f.select :cluster_id, @user.organization.clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
4
- </td>
5
- <td class="action vertical-align-middle" width="44">
4
+ </td>
5
+ <td class="action vertical-align-middle text-center" width="44">
6
6
  <%= link_to_remove_association f, class: 'btn btn-danger btn-xs text-danger' do %>
7
7
  <i class="fa fa-trash"></i>
8
8
  <% end %>
@@ -0,0 +1,41 @@
1
+ <% if cluster_organization.is_in_cluster_mode? %>
2
+ <div class="col-xs-12">
3
+ <% if hide_title||=false %>
4
+ <div class="form-group file required <%=f.object.class.name.parameterize%>_cluster_entity<%=' has-error' if f.object.errors.has_key?(:cluster_entities)%>">
5
+ <label class="text" for="<%=f.object.class.name.parameterize%>_cluster_entity">
6
+ <%=t('klastera.clusters.title')%>
7
+ <% if cluster_organization.required_suborganization_mode? %>
8
+ <abbr title="required">*</abbr>
9
+ <% end %>
10
+ </label>
11
+ <% end %>
12
+
13
+ <div class="nested-cluster-entity">
14
+ <div class="panel panel-default">
15
+ <div class="panel-heading<%=' custom-required' if cluster_organization.required_suborganization_mode? %>">
16
+ <h4 class="panel-title">
17
+ <% unless hide_title||=false %>
18
+ <div class="float-left" style="line-height: 20px"><%=t('klastera.clusters.title')%></div>
19
+ <% end %>
20
+ <%= link_to_add_association f, :cluster_entities, partial: 'layouts/klastera/cluster_entity_fields', data: { 'association-insertion-node': :'tbody.cluster-entity-rows', 'association-insertion-method': :append }, class: 'btn btn-success btn-xs float-right color-white' do %>
21
+ <i class="fa fa-plus"></i>
22
+ <% end %>
23
+ <div class="clearfix"></div>
24
+ </h4>
25
+ </div>
26
+ <table id="cluster-entities" class="table table-striped">
27
+ <tbody class="cluster-entity-rows">
28
+ <%= f.fields_for :cluster_entities do |cluster_entity|%>
29
+ <%= render 'layouts/klastera/cluster_entity_fields', f: cluster_entity %>
30
+ <% end %>
31
+ </body>
32
+ </table>
33
+ </div>
34
+ </div>
35
+
36
+ <% if hide_title||=false %>
37
+ <div class="invalid-feedback"><%=f.object.try(:errors)&.[](:cluster_entities).try(:first)%></div>
38
+ </div>
39
+ <% end %>
40
+ </div>
41
+ <% end %>
@@ -1,20 +1,22 @@
1
1
  <% if @user.try(:is_a_cluster_user?) %>
2
- <div class="panel panel-default">
3
- <div class="panel-heading">
4
- <h4 class="panel-title">
5
- <div class="float-left" style="line-height: 20px"><%=t('klastera.clusters.title')%></div>
6
- <%= link_to_add_association f, :cluster_users, partial: 'layouts/klastera/cluster_user_fields', data: { 'association-insertion-node': :'tbody.cluster-user-rows', 'association-insertion-method': :append }, class: 'btn btn-success btn-xs float-right color-white' do %>
7
- <i class="fa fa-plus"></i>
8
- <% end %>
9
- <div class="clearfix">
10
- </h4>
2
+ <div class="nested-cluster-user">
3
+ <div class="panel panel-default">
4
+ <div class="panel-heading">
5
+ <h4 class="panel-title">
6
+ <div class="float-left" style="line-height: 20px"><%=t('klastera.clusters.title')%></div>
7
+ <%= link_to_add_association f, :cluster_users, partial: 'layouts/klastera/cluster_user_fields', data: { 'association-insertion-node': :'tbody.cluster-user-rows', 'association-insertion-method': :append }, class: 'btn btn-success btn-xs float-right color-white' do %>
8
+ <i class="fa fa-plus"></i>
9
+ <% end %>
10
+ <div class="clearfix"></div>
11
+ </h4>
12
+ </div>
13
+ <table id="cluster-users" class="table table-striped">
14
+ <tbody class="cluster-user-rows">
15
+ <%= f.fields_for :cluster_users do |cluster_user|%>
16
+ <%= render 'layouts/klastera/cluster_user_fields', f: cluster_user %>
17
+ <% end %>
18
+ </body>
19
+ </table>
11
20
  </div>
12
- <table id="cluster-users" class="table">
13
- <tbody class="cluster-user-rows">
14
- <%= f.fields_for :cluster_users do |cluster_user|%>
15
- <%= render 'layouts/klastera/cluster_user_fields', f: cluster_user %>
16
- <% end %>
17
- </body>
18
- </table>
19
21
  </div>
20
22
  <% end %>
@@ -13,7 +13,7 @@
13
13
  >
14
14
  <%= fa_icon 'info-circle', class: 'btn-link' %>
15
15
  </span>
16
- <%= f.select :use_cluster_as, Cluster::MODES.map{|cm|[t("klastera.#{cm}"),cm]}, { include_blank: true }, { class: 'form-control' } %>
16
+ <%= f.select :use_cluster_as, ::Cluster::MODES.map{|cm|[t("klastera.#{cm}"),cm]}, { include_blank: true }, { class: 'form-control' } %>
17
17
  </div>
18
18
 
19
19
  <script type="text/javascript">
@@ -57,6 +57,8 @@ es:
57
57
  created: Creado
58
58
  updated: Actualizado
59
59
  messages:
60
+ has_one_cluster_entity: Está permitido agregar un sólo cluster
61
+ at_least_one_cluster_entity: Debe agregar al menos un cluster
60
62
  record_action_successfully: Registro %{a} exitosamente
61
63
  cant_delete_the_last_record_in_required_suborganization_mode: No se puede eliminar el único cluster de esta organización
62
64
  new_cluster_id:
@@ -0,0 +1,8 @@
1
+ class CreateKlasteraClusterEntities < ActiveRecord::Migration
2
+ def change
3
+ create_table :cluster_entities do |t|
4
+ t.integer :cluster_id, index: true
5
+ t.references :entity, polymorphic: true, index: true
6
+ end
7
+ end
8
+ end
@@ -3,42 +3,95 @@ require "klastera/engine"
3
3
  module Klastera
4
4
  mattr_accessor :organization_class
5
5
 
6
- class RelatedClusterEntityComplianceError < StandardError; end
7
6
  extend ActiveSupport::Concern
8
7
 
9
8
  class << self
10
9
 
10
+ #
11
+ # I like to wrap methods
12
+ #
13
+ def cluster_scope_filtered!(scope,cluster_id,user,organization,includes=[])
14
+ self.filter_clusterized_collection_with!(
15
+ organization,
16
+ cluster_id,
17
+ self.cluster_scope!(user,organization,scope,includes)
18
+ )
19
+ end
20
+
21
+ #
22
+ # In order to this works, active_record_collection argument
23
+ # should be passed through cluster_scope! method before.
24
+ #
25
+ def filter_clusterized_collection_with!(cluster_organization,cluster_id,active_record_collection)
26
+ if cluster_organization.is_in_cluster_mode?
27
+ if cluster_id.present?
28
+ cluster_array = [cluster_id]
29
+ # Based on force/use/show definition we don't really need this validation.
30
+ # A force cluster organization won't return an entity out of a cluster, but
31
+ # we don't know if the clusterized entities are fully definition-compliant.
32
+ cluster_array << nil if cluster_organization.optional_suborganization_mode?
33
+ active_record_collection = active_record_collection.where("cluster_entities.cluster_id": cluster_array)
34
+ end
35
+ # you may use a block only with clusterizable data
36
+ yield(active_record_collection) if block_given?
37
+ end
38
+ active_record_collection
39
+ end
40
+
41
+ #
42
+ #
43
+ #
44
+ def set_collection_before_group_by_entity!(cluster_organization,active_record_collection,model_class,entity_params)
45
+ entity_params_keys = [:entity_name,:entity_attribute,:entity_id,:entity_id_attribute,:unamed]
46
+ entity_params = entity_params.slice(*entity_params_keys).values
47
+ if model_class.try(:reflections).try(:keys).try(:include?,entity_params[0])
48
+ entity_params << "#{entity_params[0]}_id".to_sym
49
+ if entity_params[0] == 'cluster'
50
+ entity_params << :unclustered if cluster_organization.is_in_cluster_mode?
51
+ active_record_collection = Klastera.filter_clusterized_collection_with!(
52
+ cluster_organization,
53
+ entity_params[2],
54
+ active_record_collection
55
+ )
56
+ end
57
+ yield(
58
+ active_record_collection,
59
+ entity_params_keys.zip(entity_params).to_h)
60
+ end
61
+ end
62
+
11
63
  ##
12
64
  # Returns a ::Cluster::ActiveRecord_Relation from a given scope
13
65
  #
14
66
  def clusters_from!(user,organization,scope,includes=[])
15
- _scope_result = scope.respond_to?(:map) ? scope : cluster_scope!(user,organization,scope,includes)
16
- ::Cluster.where(id: _scope_result.related_clusters.map(&:cluster_id))
67
+ cluster_scope!(user,organization,scope,includes).related_clusters
17
68
  end
18
69
 
19
70
  ##
20
- # Returns a scope with filtered by clusters or
21
- # the scope filterd its organization if
22
- # the organization haven't active the cluster mode
23
- #
71
+ # Returns a scope filtered by clusters or its
72
+ # organization if the cluster mode is not active.
24
73
  #
25
74
  def cluster_scope!(user,organization,scope,includes=[])
26
- scope_klass = scope_class(scope)
27
- raise RelatedClusterEntityComplianceError, "attribute cluster_id was not found in #{scope_klass}" unless scope_klass.try(:column_names).try(:include?,'cluster_id')
28
- scope_klass = scope_klass.includes(includes) if includes.present?
29
- scope_klass = scope_klass.where(organization_id: organization)
30
-
75
+ scope_klass = scope_class(scope).where(organization_id: organization)
31
76
  session_clusters(user,organization) do |clusters|
32
- clusters = clusters.reject{|c|c.id.blank?}
33
- if organization.required_suborganization_mode?
34
- scope_klass = scope_klass.where("#{scope.table_name}.cluster_id IN (?)",clusters)
35
- elsif organization.optional_mode? && user.is_a_cluster_user?
36
- with_clusters = clusters.present? ? "#{scope.table_name}.cluster_id IN (#{clusters.map(&:id).join(',')})" : nil
37
- without_clusters = "#{with_clusters.blank? ? '' : ' OR ' }#{scope.table_name}.cluster_id IS NULL"
38
- scope_klass = scope_klass.where("#{with_clusters}#{without_clusters}")
77
+ if organization.is_in_cluster_mode?
78
+ scope_klass = scope_klass.select("DISTINCT ON (#{scope.table_name}.id) #{scope.table_name}.id, #{scope.table_name}.*")
79
+ scope_klass = scope_klass.includes(includes) if includes.present?
80
+ cluster_ids = clusters.map(&:id)
81
+ if organization.required_suborganization_mode?
82
+ scope_klass = scope_klass.joins(:cluster_entities).where( cluster_entities: { cluster_id: cluster_ids } )
83
+ else
84
+ scope_klass = scope_klass.joins("
85
+ LEFT OUTER JOIN cluster_entities
86
+ ON cluster_entities.cluster_id IN (#{cluster_ids.join(",")})
87
+ AND entity_id = #{scope.table_name}.id
88
+ AND entity_type = '#{scope}'
89
+ ")
90
+ end
91
+ # Provisional fix to avoid SQL clashes due to DISTINCT ON clause
92
+ scope_klass = scope_class(scope).where(organization_id: organization).where(id: scope_klass.map(&:id))
39
93
  end
40
94
  end
41
-
42
95
  scope_klass
43
96
  end
44
97
 
@@ -46,6 +99,7 @@ module Klastera
46
99
  # TODO:
47
100
  # Implement a validation to ensure that
48
101
  # object is a ActiveRecord::Base class
102
+ # (or just try to guess how to retrieve the argument class)
49
103
  #
50
104
  ##
51
105
  def scope_class(object)
@@ -60,8 +114,11 @@ module Klastera
60
114
  #
61
115
  ##
62
116
  def session_clusters(user,organization)
63
- clusters = organization.is_in_cluster_mode? ? ::ClusterUser.get_clusters_from(user,organization) : []
64
- yield(clusters) if block_given?
117
+ clusters = organization.is_in_cluster_mode? ? ::ClusterUser.clusters_from(user,organization) : []
118
+ if block_given?
119
+ clusters = clusters.reject{|c|c.id.blank?}
120
+ yield(clusters)
121
+ end
65
122
  clusters
66
123
  end
67
124
  end
@@ -73,7 +130,7 @@ module Klastera
73
130
  helper_method :cluster_user
74
131
  helper_method :cluster_organization
75
132
  helper_method :cluster_clusters
76
- # helper_method :cluster_clusters_ids
133
+ helper_method :cluster_scope_filtered
77
134
  helper_method :user_has_more_than_one_cluster
78
135
  helper_method :clusters_from
79
136
  end
@@ -88,8 +145,8 @@ module Klastera
88
145
  hide_action :cluster_organization=
89
146
  hide_action :cluster_clusters
90
147
  hide_action :cluster_clusters=
91
- # hide_action :cluster_clusters_ids
92
- # hide_action :cluster_clusters_ids=
148
+ hide_action :cluster_scope_filtered
149
+ hide_action :cluster_scope_filtered=
93
150
  hide_action :user_has_more_than_one_cluster
94
151
  hide_action :user_has_more_than_one_cluster=
95
152
  hide_action :clusters_from
@@ -123,9 +180,15 @@ module Klastera
123
180
  Klastera.session_clusters(cluster_user,cluster_organization)
124
181
  end
125
182
 
126
- # def cluster_clusters_ids
127
- # cluster_clusters.map(&:id)
128
- # end
183
+ def cluster_scope_filtered(scope,cluster_id,includes=[])
184
+ Klastera.cluster_scope_filtered!(
185
+ scope,
186
+ cluster_id,
187
+ cluster_user,
188
+ cluster_organization,
189
+ includes
190
+ )
191
+ end
129
192
 
130
193
  def user_has_more_than_one_cluster
131
194
  @cluster_clusters ||= cluster_clusters