klastera 1.2.2 → 1.2.4.2
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.
- checksums.yaml +4 -4
- data/app/models/klastera/concerns/clusterizable.rb +16 -2
- data/app/views/layouts/klastera/_cluster_entity_fields.html.erb +1 -1
- data/app/views/layouts/klastera/_nested_cluster_entity.html.erb +2 -0
- data/config/locales/es.yml +1 -0
- data/lib/klastera.rb +125 -82
- data/lib/klastera/version.rb +2 -2
- metadata +2 -3
- data/app/helpers/klastera/clusters_helper.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8780a6928f5249deb34be42cac1f52a226113865b9f29ddb12e1a36f018141ed
|
4
|
+
data.tar.gz: 1d99b709cea49a08533192ad8a1df621d78ea4d4ee59e1c266f06e952e6d8063
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62c72441e00d9edb6c17525453cde71d864389c9342dbe54df3538609814aef0cdcbc3f7c49f49134d526e2da1f99ff1cc258b750cd024a7031afd3a80977d2d
|
7
|
+
data.tar.gz: 806978a3fae34b0a2ddda331ce37b90de2e66f9c77bd707859b721ac7c83980f706b5eb432a00875db8b26b4c8901b11307ef62ab063952d013eef30eca69772
|
@@ -9,9 +9,10 @@ module Klastera::Concerns::Clusterizable
|
|
9
9
|
|
10
10
|
validates :cluster_id, presence: true, if: proc { self.try(:cluster_id) && self.organization.required_suborganization_mode? }
|
11
11
|
validate :at_least_one_cluster_entity, if: proc { self.organization.required_suborganization_mode? }
|
12
|
+
validate :uniqueness_of_cluster_entity_record
|
12
13
|
|
13
14
|
scope :related_clusters, ->() {
|
14
|
-
|
15
|
+
joins(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
|
15
16
|
}
|
16
17
|
|
17
18
|
def at_least_one_cluster_entity
|
@@ -20,8 +21,15 @@ module Klastera::Concerns::Clusterizable
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
24
|
+
##
|
25
|
+
# This is a legacy method and we don't recommend using it.
|
26
|
+
# Implement directly Klastera.entity_clusters_string_list instead of this method.
|
27
|
+
# TODO: In order to deprecate it, you will need to perform some changes in the main app
|
28
|
+
##
|
23
29
|
def clusters_string_separated_by(separator,attribute=:name)
|
24
|
-
|
30
|
+
Klastera.entity_clusters_string_list!(
|
31
|
+
self.cluster_entities, separator, attribute
|
32
|
+
)
|
25
33
|
end
|
26
34
|
|
27
35
|
def has_one_cluster_entity
|
@@ -29,6 +37,12 @@ module Klastera::Concerns::Clusterizable
|
|
29
37
|
return errors.add(:cluster_entities, I18n.t('klastera.messages.has_one_cluster_entity'))
|
30
38
|
end
|
31
39
|
end
|
40
|
+
|
41
|
+
def uniqueness_of_cluster_entity_record
|
42
|
+
if cluster_entities.map(&:cluster_id).uniq.size != cluster_entities.size
|
43
|
+
return errors.add(:cluster_entities, I18n.t('klastera.messages.duplicated_cluster_entity') )
|
44
|
+
end
|
45
|
+
end
|
32
46
|
end
|
33
47
|
|
34
48
|
module ClassMethods
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<tr class="nested-fields">
|
2
2
|
<td class="field">
|
3
|
-
<%= f.select :cluster_id, cluster_clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
|
3
|
+
<%= f.select :cluster_id, @cluster_clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
|
4
4
|
</td>
|
5
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 %>
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<% if cluster_organization.is_in_cluster_mode? %>
|
2
|
+
<% @cluster_clusters = cluster_clusters %>
|
2
3
|
<div class="col-xs-12">
|
3
4
|
<% if hide_title||=false %>
|
4
5
|
<div class="form-group file required <%=f.object.class.name.parameterize%>_cluster_entity<%=' has-error' if f.object.errors.has_key?(:cluster_entities)%>">
|
@@ -26,6 +27,7 @@
|
|
26
27
|
<table id="cluster-entities" class="table table-striped">
|
27
28
|
<tbody class="cluster-entity-rows">
|
28
29
|
<%= f.fields_for :cluster_entities do |cluster_entity|%>
|
30
|
+
<% next unless @cluster_clusters.map(&:id).include?(cluster_entity.try(:object).try(:cluster_id)) %>
|
29
31
|
<%= render 'layouts/klastera/cluster_entity_fields', f: cluster_entity %>
|
30
32
|
<% end %>
|
31
33
|
</body>
|
data/config/locales/es.yml
CHANGED
@@ -61,6 +61,7 @@ es:
|
|
61
61
|
at_least_one_cluster_entity: Debe agregar al menos un cluster
|
62
62
|
record_action_successfully: Registro %{a} exitosamente
|
63
63
|
cant_delete_the_last_record_in_required_suborganization_mode: No se puede eliminar el único cluster de esta organización
|
64
|
+
duplicated_cluster_entity: Hay un cluster duplicado
|
64
65
|
new_cluster_id:
|
65
66
|
nil: Cluster no existe
|
66
67
|
same: Cluster no puede ser el mismo
|
data/lib/klastera.rb
CHANGED
@@ -5,6 +5,12 @@ module Klastera
|
|
5
5
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
|
+
KLSTR_HELPERS = %i[
|
9
|
+
cluster_user cluster_organization user_has_more_than_one_cluster
|
10
|
+
cluster_scope cluster_clusters cluster_scope_filtered clusters_from
|
11
|
+
user_clusters_string_list set_collection_before_group_by_entity
|
12
|
+
]
|
13
|
+
|
8
14
|
class << self
|
9
15
|
|
10
16
|
def set_cluster_entities_attributes!(entity,array_cluster_ids)
|
@@ -30,13 +36,15 @@ module Klastera
|
|
30
36
|
end
|
31
37
|
|
32
38
|
#
|
33
|
-
#
|
39
|
+
# In cases you don't have the active_record_collection object to filter, this method helps you
|
40
|
+
# calling cluster_scope! before and pass the collction to filter_clusterized_collection_with!,
|
41
|
+
# but at the end of the day, I just like to wrap methods.
|
34
42
|
#
|
35
|
-
def cluster_scope_filtered!(scope,cluster_id,user,organization
|
43
|
+
def cluster_scope_filtered!(scope,cluster_id,user,organization)
|
36
44
|
self.filter_clusterized_collection_with!(
|
37
|
-
organization,
|
38
45
|
cluster_id,
|
39
|
-
self.cluster_scope!(user,organization,
|
46
|
+
self.cluster_scope!(scope,user,organization),
|
47
|
+
organization
|
40
48
|
)
|
41
49
|
end
|
42
50
|
|
@@ -44,74 +52,88 @@ module Klastera
|
|
44
52
|
# In order to this works, active_record_collection argument
|
45
53
|
# should be passed through cluster_scope! method before.
|
46
54
|
#
|
47
|
-
def filter_clusterized_collection_with!(
|
55
|
+
def filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
|
48
56
|
if cluster_organization.is_in_cluster_mode?
|
57
|
+
|
58
|
+
# IMPORTANT
|
59
|
+
# The next block was commented on because cluster_scope! method is not returning
|
60
|
+
# the cluster_entities within the scope anymore and it doesn't make any sense trying
|
61
|
+
# to filter based on force/use/show logic. Nevertheless, someday we will need it again.
|
62
|
+
|
63
|
+
# # If cluster_id is nil we will try to filter including unclustered entities active_record_collection wsas
|
64
|
+
# unless cluster_id.present?
|
65
|
+
# # Based on force/use/show definition we don't really need this validation. A force cluster organization won't return an entity that
|
66
|
+
# # doesn't belong to a cluster. Nevertheless we don't know if active_record_collection argument is fully definition-compliant.
|
67
|
+
# if cluster_organization.optional_suborganization_mode?
|
68
|
+
# cluster_array << nil
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
|
49
72
|
if cluster_id.present?
|
50
|
-
cluster_array = [cluster_id]
|
51
|
-
#
|
52
|
-
# A force cluster organization won't return an entity out of a cluster, but
|
53
|
-
# we don't know if the clusterized entities are fully definition-compliant.
|
54
|
-
cluster_array << nil if cluster_organization.optional_suborganization_mode?
|
73
|
+
cluster_array = [cluster_id] unless cluster_id.is_a?(Array)
|
74
|
+
# The ActiveRecordCollection argument should have previously eager-loaded the cluster entities, thus the join statement is unnecessary.
|
55
75
|
active_record_collection = active_record_collection.joins(:cluster_entities).where("cluster_entities.cluster_id": cluster_array)
|
56
76
|
end
|
57
|
-
|
77
|
+
|
78
|
+
# You should use a block with clusterable data only
|
58
79
|
yield(active_record_collection) if block_given?
|
59
80
|
end
|
60
81
|
active_record_collection
|
61
82
|
end
|
62
83
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
84
|
+
##
|
85
|
+
#
|
86
|
+
#
|
87
|
+
##
|
88
|
+
def set_collection_before_group_by_entity!(active_record_collection,entity_params,cluster_organization)
|
67
89
|
entity_params_keys = [:entity_name,:entity_attribute,:entity_id,:entity_id_attribute,:unamed]
|
90
|
+
entity_params[:entity_id] ||= nil #Ensures the entity_id attribute presence even if there is no filter
|
68
91
|
entity_params = entity_params.slice(*entity_params_keys).values
|
69
|
-
|
92
|
+
model_class = active_record_collection.model.base_class
|
93
|
+
model_relations = model_class.reflections.keys
|
94
|
+
if model_relations.include?(entity_params[0])
|
70
95
|
entity_params << "#{entity_params[0]}_id".to_sym
|
71
96
|
if entity_params[0] == 'cluster'
|
72
97
|
entity_params << :unclustered if cluster_organization.is_in_cluster_mode?
|
73
98
|
active_record_collection = Klastera.filter_clusterized_collection_with!(
|
74
|
-
cluster_organization,
|
75
99
|
entity_params[2],
|
76
|
-
active_record_collection
|
100
|
+
active_record_collection,
|
101
|
+
cluster_organization
|
77
102
|
)
|
78
103
|
end
|
79
|
-
yield(
|
80
|
-
active_record_collection,
|
81
|
-
entity_params_keys.zip(entity_params).to_h)
|
104
|
+
yield( active_record_collection, entity_params_keys.zip(entity_params).to_h )
|
82
105
|
end
|
83
106
|
end
|
84
107
|
|
85
108
|
##
|
86
109
|
# Returns a ::Cluster::ActiveRecord_Relation from a given scope
|
87
110
|
#
|
88
|
-
def clusters_from!(user,organization
|
89
|
-
cluster_scope!(user,organization
|
111
|
+
def clusters_from!(scope,user,organization)
|
112
|
+
cluster_scope!(scope,user,organization).related_clusters
|
90
113
|
end
|
91
114
|
|
92
115
|
##
|
93
116
|
# Returns a scope filtered by clusters or its
|
94
117
|
# organization if the cluster mode is not active.
|
95
118
|
#
|
96
|
-
def cluster_scope!(user,organization
|
119
|
+
def cluster_scope!(scope,user,organization)
|
97
120
|
scope_klass = scope_class(scope).where(organization_id: organization)
|
98
121
|
session_clusters(user,organization) do |clusters|
|
99
122
|
if organization.is_in_cluster_mode?
|
100
123
|
scope_klass = scope_klass.select("DISTINCT ON (#{scope.table_name}.id) #{scope.table_name}.id, #{scope.table_name}.*")
|
101
|
-
scope_klass = scope_klass.includes(includes) if includes.present?
|
102
124
|
cluster_ids = clusters.map(&:id)
|
103
125
|
if organization.required_suborganization_mode?
|
104
126
|
scope_klass = scope_klass.joins(:cluster_entities).where( cluster_entities: { cluster_id: cluster_ids } )
|
105
127
|
else
|
128
|
+
or_these_cluster_ids = cluster_ids.present? ? " OR cluster_entities.cluster_id IN (#{cluster_ids.join(",")})" : ""
|
106
129
|
scope_klass = scope_klass.joins("
|
107
130
|
LEFT OUTER JOIN cluster_entities
|
108
|
-
ON
|
109
|
-
AND entity_id = #{scope.table_name}.id
|
131
|
+
ON entity_id = #{scope.table_name}.id
|
110
132
|
AND entity_type = '#{scope}'
|
111
|
-
")
|
133
|
+
").where("cluster_entities.id IS NULL#{or_these_cluster_ids}")
|
112
134
|
end
|
113
135
|
# Provisional fix to avoid SQL clashes due to DISTINCT ON clause
|
114
|
-
scope_klass = scope_class(scope).
|
136
|
+
scope_klass = scope_class(scope).eager_load(:cluster_entities).where(id: scope_klass.map(&:id), organization_id: organization)
|
115
137
|
end
|
116
138
|
end
|
117
139
|
scope_klass
|
@@ -143,38 +165,42 @@ module Klastera
|
|
143
165
|
end
|
144
166
|
clusters
|
145
167
|
end
|
146
|
-
end
|
147
168
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
169
|
+
##
|
170
|
+
# Return a string with cluster attribute separated by separator argument
|
171
|
+
# A array of cluster ids can be passed fo filter the result
|
172
|
+
#
|
173
|
+
def entity_clusters_string_list!(cluster_entities,separator,attribute=:name,allowed_cluster_ids=nil)
|
174
|
+
_cluster_entities = cluster_entities.reject(&:nil?)
|
175
|
+
if allowed_cluster_ids.is_a?(Array)
|
176
|
+
_cluster_entities.select!{|ce| allowed_cluster_ids.include?(ce.cluster_id)}
|
177
|
+
end
|
178
|
+
_cluster_entities.map do |ce|
|
179
|
+
ce.cluster.try(attribute)
|
180
|
+
end.compact.join(separator)
|
158
181
|
end
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
hide_action :cluster_organization=
|
168
|
-
hide_action :cluster_clusters
|
169
|
-
hide_action :cluster_clusters=
|
170
|
-
hide_action :cluster_scope_filtered
|
171
|
-
hide_action :cluster_scope_filtered=
|
172
|
-
hide_action :user_has_more_than_one_cluster
|
173
|
-
hide_action :user_has_more_than_one_cluster=
|
174
|
-
hide_action :clusters_from
|
175
|
-
hide_action :clusters_from=
|
182
|
+
|
183
|
+
##
|
184
|
+
# cluster_clusters needs the logged user and its organization
|
185
|
+
# that why, we perfomed this logic here
|
186
|
+
#
|
187
|
+
def user_clusters_string_list!(user,organization,cluster_entities,separator,attribute=:name)
|
188
|
+
@_session_clusters ||= self.session_clusters(user,organization)
|
189
|
+
self.entity_clusters_string_list!(cluster_entities, separator, attribute, @_session_clusters.map(&:id))
|
176
190
|
end
|
177
|
-
|
191
|
+
end
|
192
|
+
|
193
|
+
def cluster_user
|
194
|
+
current_user
|
195
|
+
end
|
196
|
+
|
197
|
+
def cluster_organization
|
198
|
+
current_organization
|
199
|
+
end
|
200
|
+
|
201
|
+
def user_has_more_than_one_cluster
|
202
|
+
@cluster_clusters ||= cluster_clusters
|
203
|
+
@cluster_clusters.size > 1
|
178
204
|
end
|
179
205
|
|
180
206
|
def set_the_lonely_cluster
|
@@ -186,52 +212,69 @@ module Klastera
|
|
186
212
|
end
|
187
213
|
end
|
188
214
|
|
189
|
-
def
|
190
|
-
|
215
|
+
def set_cluster_filter
|
216
|
+
@filter = ::ClusterFilter.new(cluster_filter_params)
|
217
|
+
end
|
218
|
+
|
219
|
+
def cluster_filter_params
|
220
|
+
parameters = params.require(:cluster_filter) rescue nil
|
221
|
+
return {} if parameters.blank?
|
222
|
+
parameters.permit(*cluster_filter_permit_params)
|
191
223
|
end
|
192
224
|
|
193
|
-
def
|
194
|
-
|
225
|
+
def cluster_filter_permit_params
|
226
|
+
[ :cluster_id ].concat( ::ClusterFilter.attributes )
|
195
227
|
end
|
196
228
|
|
197
|
-
def
|
198
|
-
|
229
|
+
def filter_clusterized_collection_with(cluster_id,active_record_collection)
|
230
|
+
Klastera.filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
|
231
|
+
end
|
232
|
+
|
233
|
+
def cluster_scope(scope)
|
234
|
+
Klastera.cluster_scope!(scope,cluster_user,cluster_organization)
|
199
235
|
end
|
200
236
|
|
201
237
|
def cluster_clusters
|
202
238
|
Klastera.session_clusters(cluster_user,cluster_organization)
|
203
239
|
end
|
204
240
|
|
205
|
-
def cluster_scope_filtered(scope,cluster_id
|
241
|
+
def cluster_scope_filtered(scope,cluster_id)
|
206
242
|
Klastera.cluster_scope_filtered!(
|
207
243
|
scope,
|
208
244
|
cluster_id,
|
209
245
|
cluster_user,
|
210
|
-
cluster_organization
|
211
|
-
includes
|
246
|
+
cluster_organization
|
212
247
|
)
|
213
248
|
end
|
214
249
|
|
215
|
-
def
|
216
|
-
|
217
|
-
@cluster_clusters.size > 1
|
218
|
-
end
|
219
|
-
|
220
|
-
def clusters_from(scope,includes=[])
|
221
|
-
Klastera.clusters_from!(cluster_user,cluster_organization,scope,includes)
|
250
|
+
def clusters_from(scope)
|
251
|
+
Klastera.clusters_from!(scope,cluster_user,cluster_organization)
|
222
252
|
end
|
223
253
|
|
224
|
-
def
|
225
|
-
|
254
|
+
def user_clusters_string_list(object_entity,separator,attribute=:name)
|
255
|
+
Klastera.user_clusters_string_list!(
|
256
|
+
cluster_user,
|
257
|
+
cluster_organization,
|
258
|
+
object_entity.try(:cluster_entities),
|
259
|
+
separator,
|
260
|
+
attribute
|
261
|
+
)
|
226
262
|
end
|
227
263
|
|
228
|
-
def
|
229
|
-
|
230
|
-
return {} if parameters.blank?
|
231
|
-
parameters.permit(*cluster_filter_permit_params)
|
264
|
+
def set_collection_before_group_by_entity(active_record_collection,entity_params,&block)
|
265
|
+
Klastera.set_collection_before_group_by_entity!(active_record_collection,params,cluster_organization,&block)
|
232
266
|
end
|
233
267
|
|
234
|
-
|
235
|
-
|
268
|
+
included do
|
269
|
+
Klastera::KLSTR_HELPERS.each do |action|
|
270
|
+
if respond_to?(:helper_method)
|
271
|
+
helper_method(action)
|
272
|
+
end
|
273
|
+
if respond_to?(:hide_action)
|
274
|
+
hide_action(helper)
|
275
|
+
hide_action("#{helper}=")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
before_action :set_the_lonely_cluster, only: %i[ create update ]
|
236
279
|
end
|
237
280
|
end
|
data/lib/klastera/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Klastera
|
2
|
-
VERSION = "1.2.2"
|
3
|
-
end
|
2
|
+
VERSION = "1.2.4.2"
|
3
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: klastera
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.2
|
4
|
+
version: 1.2.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gino Barahona
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-06-
|
11
|
+
date: 2020-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -54,7 +54,6 @@ files:
|
|
54
54
|
- app/controllers/klastera/application_controller.rb
|
55
55
|
- app/controllers/klastera/clusters_controller.rb
|
56
56
|
- app/helpers/klastera/application_helper.rb
|
57
|
-
- app/helpers/klastera/clusters_helper.rb
|
58
57
|
- app/models/klastera/cluster.rb
|
59
58
|
- app/models/klastera/cluster_entity.rb
|
60
59
|
- app/models/klastera/cluster_filter.rb
|