klastera 1.1.4 → 1.2.0

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/app/assets/stylesheets/klastera/clusters.css.scss +11 -0
  3. data/app/models/klastera/cluster_entity.rb +5 -0
  4. data/app/models/klastera/concerns/cluster_entity.rb +12 -0
  5. data/app/models/klastera/concerns/cluster_user.rb +38 -1
  6. data/app/models/klastera/concerns/clusterizable.rb +28 -3
  7. data/app/models/klastera/concerns/user.rb +23 -2
  8. data/app/views/layouts/klastera/_cluster_entity_fields.html.erb +10 -0
  9. data/app/views/layouts/klastera/_cluster_filter.html.erb +1 -1
  10. data/app/views/layouts/klastera/_cluster_selector.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 +114 -34
  18. data/lib/klastera/version.rb +2 -2
  19. data/lib/tasks/klastera_tasks.rake +23 -0
  20. metadata +9 -76
  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: 9bd206c969548ea6d299cb57564aa67e9f7b88a5ba753ad5d0c112b7670ad4f0
4
- data.tar.gz: 62580be564273b2a461808c9edbe2e9ef6c1cefa88f8b813ec9d2d02441a0836
3
+ metadata.gz: ae9963c78d2880fca43b1fd6bef6be6c7ebcdd957289dd1117d81b815fdef707
4
+ data.tar.gz: 3ae1a3a37239c56675aaa9b9c82cfd65f6262777746bf6e720465c62e66af069
5
5
  SHA512:
6
- metadata.gz: d5f9073b9968cab43d2a88be5d1bcb9ac4cb6254670b480ac2adeadbe9c00bef78cd35a022f52626c75157844f9ad428c26afaab33b73b55e51b1bcfd0f0c682
7
- data.tar.gz: 900d61f55072bfc19110dc4efda73c996dd7ec57e327165279e2c15b5eb86352c1f1aa98a28130b2b1f87a7d753a7891b388badee4a7771e6249fd758b662f5e
6
+ metadata.gz: ed36fabfe91b44b8d8209a1484081021be21cb0309bfd8731cd1380aa6dcf210464f0e1e6cd5dbba218691cbae023223160ee287d6b698ce99756bc452e4c563
7
+ data.tar.gz: 62ce187ce73ebf4bf07e045835a1f3c79a0c2a911c0f45c54d980938851afdf38dfe8f632641f0b6da40b5c62e82d03cf7d0286b321fed90c3873c267cce2574
@@ -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,14 +7,51 @@ 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) {
13
+ Rails.logger.warn("DON'T USE THIS SCOPE DIRECTLY: Use ::ClusterUser.clusters_from class method instead!")
14
14
  includes(:cluster).where(user_id: user, "clusters.organization_id": organization)
15
15
  }
16
16
  end
17
17
 
18
18
  module ClassMethods
19
+
20
+ ##
21
+ # Returns a hash with the users with cluster relation
22
+ #
23
+ def user_clusters_from(organization)
24
+ users_hash = {}
25
+ organization_cluster_ids = ::Cluster.of(organization).map(&: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
30
+ end
31
+ users_hash
32
+ end
33
+
34
+ ##
35
+ # Returns a Cluster::ActiveRecord_Relation
36
+ #
37
+ ##
38
+ def clusters_from(user,organization)
39
+ clusters = []
40
+ unless user.can_admin_clusters?
41
+ # We could return cu.clusters but you may quering this result and a array can't handle order, where and etc.
42
+ # So we take only the cluster_ids and perfome a new search in order to get a Cluster::ActiveRecord_Relation
43
+ # like the else block.
44
+ # TODO: resolve it without quering twice
45
+ clusters_id = ::ClusterUser.of(user,organization).map(&:cluster_id)
46
+ clusters = ::Cluster.where(id: clusters_id)
47
+ # Add a empty cluster instance to handle models without a cluster assignation. Only for use and show modes
48
+ if organization.optional_mode?
49
+ clusters << ::Cluster.new({nid: :without_cluster, name: I18n.t('klastera.without_cluster')})
50
+ end
51
+ else
52
+ clusters = ::Cluster.of(organization)
53
+ end
54
+ clusters
55
+ end
19
56
  end
20
57
  end
@@ -3,12 +3,37 @@ module Klastera::Concerns::Clusterizable
3
3
  included do
4
4
  attr_accessor :lonely_cluster
5
5
  belongs_to :cluster
6
- validates :cluster_id, presence: true, if: proc { self.organization.required_suborganization_mode? }
6
+
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? }
12
+
13
+ scope :related_clusters, ->() {
14
+ includes(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
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
7
32
  end
8
33
 
9
34
  module ClassMethods
10
- def cluster_params
11
- [ :cluster_id, :lonely_cluster ]
35
+ def cluster_entity_params
36
+ [ :cluster_id, :lonely_cluster, { cluster_entities_attributes: [:id, :cluster_id, :_destroy] } ]
12
37
  end
13
38
  end
14
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)]} %>
@@ -4,7 +4,7 @@
4
4
  %>
5
5
  <% if cluster_organization.is_in_cluster_mode? || other_visibility_reason %>
6
6
  <%
7
- cluster_collection = cluster_clusters
7
+ cluster_collection = @cluster_clusters || cluster_clusters
8
8
  label = t('klastera.cluster.title')
9
9
  %>
10
10
  <% if f.nil? %>
@@ -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,29 +3,92 @@ 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
- def cluster_scope!(user,organization,scope,includes=[])
11
- scope_klass = scope_class(scope)
12
- raise RelatedClusterEntityComplianceError, "attribute cluster_id was not found in #{scope_klass}" unless scope_klass.try(:column_names).try(:include?,'cluster_id')
13
- scope_klass = scope_klass.includes(includes) if includes.present?
14
- scope_klass = scope_klass.where(organization_id: organization)
15
9
 
16
- session_clusters(user,organization) do |clusters|
17
- clusters = clusters.reject{|c|c.id.blank?}
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
18
20
 
19
- if organization.required_suborganization_mode?
20
- scope_klass = scope_klass.where("#{scope.table_name}.cluster_id IN (?)",clusters)
21
- elsif organization.optional_mode?
22
- with_clusters = clusters.present? ? "#{scope.table_name}.cluster_id IN (#{clusters.map(&:id).join(',')})" : nil
23
- without_clusters = "#{with_clusters.blank? ? '' : ' OR ' }#{scope.table_name}.cluster_id IS NULL"
24
- scope_klass = scope_klass.where("#{with_clusters}#{without_clusters}")
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)
25
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
26
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)
27
60
  end
61
+ end
62
+
63
+ ##
64
+ # Returns a ::Cluster::ActiveRecord_Relation from a given scope
65
+ #
66
+ def clusters_from!(user,organization,scope,includes=[])
67
+ cluster_scope!(user,organization,scope,includes).related_clusters
68
+ end
28
69
 
70
+ ##
71
+ # Returns a scope filtered by clusters or its
72
+ # organization if the cluster mode is not active.
73
+ #
74
+ def cluster_scope!(user,organization,scope,includes=[])
75
+ scope_klass = scope_class(scope).where(organization_id: organization)
76
+ session_clusters(user,organization) do |clusters|
77
+ if organization.is_in_cluster_mode?
78
+ scope_klass = scope_klass.includes(includes) if includes.present?
79
+ cluster_ids = clusters.map(&:id)
80
+ if organization.required_suborganization_mode?
81
+ scope_klass = scope_klass.joins(:cluster_entities).where( cluster_entities: { cluster_id: cluster_ids } )
82
+ else
83
+ scope_klass = scope_klass.joins("
84
+ LEFT OUTER JOIN cluster_entities
85
+ ON cluster_entities.cluster_id IN (#{cluster_ids.join(",")})
86
+ AND entity_id = #{scope.table_name}.id
87
+ AND entity_type = '#{scope}'
88
+ ")
89
+ end
90
+ end
91
+ end
29
92
  scope_klass
30
93
  end
31
94
 
@@ -33,6 +96,7 @@ module Klastera
33
96
  # TODO:
34
97
  # Implement a validation to ensure that
35
98
  # object is a ActiveRecord::Base class
99
+ # (or just try to guess how to retrieve the argument class)
36
100
  #
37
101
  ##
38
102
  def scope_class(object)
@@ -40,22 +104,17 @@ module Klastera
40
104
  end
41
105
 
42
106
  ##
107
+ # Returns a cluster array if organization is using the cluster mode
43
108
  #
109
+ # Use this only to get current_user/organization clusters
110
+ # understanding this wont be useful out of a cluster mode context.
44
111
  #
45
112
  ##
46
113
  def session_clusters(user,organization)
47
- clusters = []
48
- if organization.is_in_cluster_mode?
49
- unless user.can_admin_clusters?
50
- # TODO: 1: return a Cluster::ActiveRecord_Relation and then remove to_a in ::Cluster.of line
51
- # TODO: 2: fix call to ::Cluster instead of Klastera::Cluster
52
- clusters = ::ClusterUser.of(user,organization).map{|cu|::Cluster.find(cu.cluster_id)}
53
- clusters << ::Cluster.new({nid: :without_cluster, name: I18n.t('klastera.without_cluster')}) if organization.optional_mode?
54
- else
55
- # TODO: remove "to_a" after ClusterUser.of result became a Cluster::ActiveRecord_Relation object
56
- clusters = ::Cluster.of(organization).to_a
57
- end
58
- yield(clusters) if block_given?
114
+ clusters = organization.is_in_cluster_mode? ? ::ClusterUser.clusters_from(user,organization) : []
115
+ if block_given?
116
+ clusters = clusters.reject{|c|c.id.blank?}
117
+ yield(clusters)
59
118
  end
60
119
  clusters
61
120
  end
@@ -68,7 +127,9 @@ module Klastera
68
127
  helper_method :cluster_user
69
128
  helper_method :cluster_organization
70
129
  helper_method :cluster_clusters
71
- # helper_method :cluster_clusters_ids
130
+ helper_method :cluster_scope_filtered
131
+ helper_method :user_has_more_than_one_cluster
132
+ helper_method :clusters_from
72
133
  end
73
134
  if respond_to?(:hide_action)
74
135
  hide_action :cluster_scope
@@ -81,18 +142,22 @@ module Klastera
81
142
  hide_action :cluster_organization=
82
143
  hide_action :cluster_clusters
83
144
  hide_action :cluster_clusters=
84
- # hide_action :cluster_clusters_ids
85
- # hide_action :cluster_clusters_ids=
145
+ hide_action :cluster_scope_filtered
146
+ hide_action :cluster_scope_filtered=
147
+ hide_action :user_has_more_than_one_cluster
148
+ hide_action :user_has_more_than_one_cluster=
149
+ hide_action :clusters_from
150
+ hide_action :clusters_from=
86
151
  end
87
152
  before_action :set_the_lonely_cluster, only: %i[ create update ]
88
153
  end
89
154
 
90
155
  def set_the_lonely_cluster
91
- form_model = params[:controller].singularize
156
+ form_model = @form_record ? model_name_from_record_or_class(@form_record).param_key : params[:controller].singularize
92
157
  parameters = params.require( form_model ) rescue nil
93
158
  lonely_cluster = parameters.blank? ? false : parameters.permit( :lonely_cluster ).present?
94
159
  if lonely_cluster
95
- params[form_model][:cluster_id] = ::ClusterUser.of(cluster_user,cluster_organization).first.try(:cluster_id)
160
+ params[form_model][:cluster_id] = cluster_clusters.first.try(:id)
96
161
  end
97
162
  end
98
163
 
@@ -112,9 +177,24 @@ module Klastera
112
177
  Klastera.session_clusters(cluster_user,cluster_organization)
113
178
  end
114
179
 
115
- # def cluster_clusters_ids
116
- # cluster_clusters.map(&:id)
117
- # end
180
+ def cluster_scope_filtered(scope,cluster_id,includes=[])
181
+ Klastera.cluster_scope_filtered!(
182
+ scope,
183
+ cluster_id,
184
+ cluster_user,
185
+ cluster_organization,
186
+ includes
187
+ )
188
+ end
189
+
190
+ def user_has_more_than_one_cluster
191
+ @cluster_clusters ||= cluster_clusters
192
+ @cluster_clusters.size > 1
193
+ end
194
+
195
+ def clusters_from(scope,includes=[])
196
+ Klastera.clusters_from!(cluster_user,cluster_organization,scope,includes)
197
+ end
118
198
 
119
199
  def set_cluster_filter
120
200
  @filter = ::ClusterFilter.new(cluster_filter_params)