klastera 1.1.5 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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