klastera 1.1.4 → 1.2.0

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/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)