eco-helpers 2.0.16 → 2.0.17
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/CHANGELOG.md +50 -6
- data/eco-helpers.gemspec +6 -4
- data/lib/eco-helpers.rb +1 -0
- data/lib/eco/api/common/base_loader.rb +14 -0
- data/lib/eco/api/common/people/default_parsers/date_parser.rb +11 -1
- data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +1 -1
- data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +11 -11
- data/lib/eco/api/common/people/person_entry.rb +4 -2
- data/lib/eco/api/common/session/mailer.rb +0 -1
- data/lib/eco/api/common/session/s3_uploader.rb +0 -1
- data/lib/eco/api/common/session/sftp.rb +0 -1
- data/lib/eco/api/microcases.rb +3 -1
- data/lib/eco/api/microcases/append_usergroups.rb +0 -1
- data/lib/eco/api/microcases/people_cache.rb +2 -2
- data/lib/eco/api/microcases/people_load.rb +2 -2
- data/lib/eco/api/microcases/people_refresh.rb +2 -2
- data/lib/eco/api/microcases/people_search.rb +6 -6
- data/lib/eco/api/microcases/preserve_default_tag.rb +23 -0
- data/lib/eco/api/microcases/preserve_filter_tags.rb +28 -0
- data/lib/eco/api/microcases/preserve_policy_groups.rb +30 -0
- data/lib/eco/api/microcases/set_account.rb +0 -1
- data/lib/eco/api/organization.rb +1 -0
- data/lib/eco/api/organization/people.rb +7 -0
- data/lib/eco/api/organization/people_analytics.rb +60 -0
- data/lib/eco/api/organization/presets_factory.rb +22 -83
- data/lib/eco/api/organization/presets_integrity.json +6 -0
- data/lib/eco/api/organization/presets_values.json +5 -4
- data/lib/eco/api/policies/default_policies/99_user_access_policy.rb +0 -30
- data/lib/eco/api/session.rb +1 -20
- data/lib/eco/api/session/batch.rb +23 -7
- data/lib/eco/api/session/config.rb +0 -10
- data/lib/eco/api/session/config/people.rb +1 -17
- data/lib/eco/api/usecases/default_cases.rb +1 -1
- data/lib/eco/api/usecases/default_cases/abstract_policygroup_abilities_case.rb +1 -1
- data/lib/eco/api/usecases/default_cases/analyse_people_case.rb +76 -0
- data/lib/eco/api/usecases/default_cases/codes_to_tags_case.rb +2 -3
- data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +11 -1
- data/lib/eco/api/usecases/default_cases/restore_db_case.rb +1 -2
- data/lib/eco/api/usecases/default_cases/supers_cyclic_identify_case.rb +1 -1
- data/lib/eco/api/usecases/default_cases/supers_hierarchy_case.rb +1 -1
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +85 -27
- data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +62 -36
- data/lib/eco/cli/config/default/options.rb +19 -17
- data/lib/eco/cli/config/default/people_filters.rb +3 -3
- data/lib/eco/cli/config/default/usecases.rb +66 -32
- data/lib/eco/cli/config/default/workflow.rb +1 -1
- data/lib/eco/cli/config/help.rb +1 -0
- data/lib/eco/cli/config/options_set.rb +106 -13
- data/lib/eco/cli/config/use_cases.rb +33 -33
- data/lib/eco/cli/scripting/args_helpers.rb +30 -3
- data/lib/eco/data.rb +1 -0
- data/lib/eco/data/crypto/encryption.rb +3 -3
- data/lib/eco/data/files/helpers.rb +6 -4
- data/lib/eco/data/fuzzy_match.rb +119 -0
- data/lib/eco/data/fuzzy_match/array_helpers.rb +75 -0
- data/lib/eco/data/fuzzy_match/chars_position_score.rb +37 -0
- data/lib/eco/data/fuzzy_match/ngrams_score.rb +73 -0
- data/lib/eco/data/fuzzy_match/pairing.rb +102 -0
- data/lib/eco/data/fuzzy_match/result.rb +67 -0
- data/lib/eco/data/fuzzy_match/results.rb +53 -0
- data/lib/eco/data/fuzzy_match/score.rb +44 -0
- data/lib/eco/data/fuzzy_match/stop_words.rb +35 -0
- data/lib/eco/data/fuzzy_match/string_helpers.rb +69 -0
- data/lib/eco/version.rb +1 -1
- metadata +82 -10
- data/lib/eco/api/microcases/refresh_abilities.rb +0 -19
- data/lib/eco/api/organization/presets_reference.json +0 -59
- data/lib/eco/api/usecases/default_cases/refresh_abilities_case.rb +0 -30
@@ -11,7 +11,6 @@ module Eco
|
|
11
11
|
person.account.send_invites = options[:send_invites] if options.key?(:send_invites)
|
12
12
|
micro.refresh_default_tag(entry, person, options)
|
13
13
|
micro.fix_default_group(entry, person, options)
|
14
|
-
micro.refresh_abilities(person, options)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
|
data/lib/eco/api/organization.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative 'organization/tag_tree'
|
|
9
9
|
require_relative 'organization/presets_factory'
|
10
10
|
require_relative 'organization/preferences'
|
11
11
|
require_relative 'organization/people'
|
12
|
+
require_relative 'organization/people_analytics'
|
12
13
|
require_relative 'organization/person_schemas'
|
13
14
|
require_relative 'organization/policy_groups'
|
14
15
|
require_relative 'organization/login_providers'
|
@@ -176,6 +176,12 @@ module Eco
|
|
176
176
|
end
|
177
177
|
# @!endgroup
|
178
178
|
|
179
|
+
# @!group Helper methods
|
180
|
+
def analytics
|
181
|
+
Eco::API::Organization::PeopleAnalytics.new(self.to_a)
|
182
|
+
end
|
183
|
+
# @!endgroup
|
184
|
+
|
179
185
|
protected
|
180
186
|
|
181
187
|
def on_change
|
@@ -190,6 +196,7 @@ module Eco
|
|
190
196
|
@by_external_id = to_h('external_id')
|
191
197
|
@by_users_email = users.to_h('email')
|
192
198
|
@by_non_users_email = non_users.to_h('email')
|
199
|
+
@by_email = to_h('email')
|
193
200
|
@caches_init = true
|
194
201
|
end
|
195
202
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Eco
|
2
|
+
module API
|
3
|
+
module Organization
|
4
|
+
class PeopleAnalytics < Eco::API::Organization::People
|
5
|
+
include Eco::Data::FuzzyMatch
|
6
|
+
|
7
|
+
# @!group Helpers
|
8
|
+
|
9
|
+
# @!endgroup
|
10
|
+
|
11
|
+
# @!group Searchers
|
12
|
+
|
13
|
+
# It gathers those that have the same `email`
|
14
|
+
# @return [Hash] where `keys` are `email`s and `values` an `Array<Person>`
|
15
|
+
def repeated_emails
|
16
|
+
init_caches
|
17
|
+
@by_email.select do |email, people|
|
18
|
+
people.count > 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @!endgroup
|
23
|
+
|
24
|
+
# @!group Analysers
|
25
|
+
|
26
|
+
# TODO: Sort results by `results.first.methods`
|
27
|
+
def similarity(**options)
|
28
|
+
each_with_object({}) do |person, results|
|
29
|
+
results[person.id] = find_all_with_score(person, **options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def print_analysis(threshold)
|
35
|
+
similarity.each do |id, results|
|
36
|
+
msg = results.results.select do |result|
|
37
|
+
result.threshold?(threshold)
|
38
|
+
end.map do |result|
|
39
|
+
result.print
|
40
|
+
end.join("\n ")
|
41
|
+
|
42
|
+
puts "'#{self[id].identify}':\n " + msg
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# @!endgroup
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def on_change
|
50
|
+
remove_instance_variable(@fuzzy_match)
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -3,6 +3,8 @@ module Eco
|
|
3
3
|
module Organization
|
4
4
|
|
5
5
|
class PresetsFactory
|
6
|
+
ABILITIES = File.join(__dir__, 'presets_values.json')
|
7
|
+
INTEGRITY = File.join(__dir__, 'presets_integrity.json')
|
6
8
|
|
7
9
|
class << self
|
8
10
|
|
@@ -24,44 +26,36 @@ module Eco
|
|
24
26
|
|
25
27
|
end
|
26
28
|
|
27
|
-
|
28
|
-
INTEGRITY = File.join(__dir__, 'presets_integrity.json')
|
29
|
-
DEFAULT_CUSTOM = 'presets_custom.json'
|
30
|
-
DEFAULT_MAP = 'presets_map.json'
|
31
|
-
|
32
|
-
def initialize(presets_custom: DEFAULT_CUSTOM, presets_map: DEFAULT_MAP, enviro: nil, policy_groups: nil)
|
29
|
+
def initialize(enviro: nil, policy_groups: nil)
|
33
30
|
fatal("Expecting Environment object. Given: #{enviro}") if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
|
34
31
|
@enviro = enviro
|
35
|
-
|
36
|
-
@policy_groups = policy_groups
|
37
|
-
@presets_custom_file = presets_custom || DEFAULT_CUSTOM
|
38
|
-
@presets_map_file = presets_map || DEFAULT_MAP
|
32
|
+
@policy_groups = policy_groups
|
39
33
|
end
|
40
34
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end.compact
|
35
|
+
# @return [Array<String>] all the abilities
|
36
|
+
def keys
|
37
|
+
self.class.abilities
|
38
|
+
end
|
46
39
|
|
47
|
-
|
48
|
-
|
49
|
-
else # option to do not use preset mapping (so just the policy group name)
|
50
|
-
preset_names = names
|
51
|
-
end
|
52
|
-
compile(*preset_names)
|
40
|
+
def valid?(preset)
|
41
|
+
validate(perset).length == 0
|
53
42
|
end
|
54
43
|
|
55
|
-
|
56
|
-
|
57
|
-
|
44
|
+
def validate(preset)
|
45
|
+
[].tap do |errors|
|
46
|
+
if err = preset_errors(preset)
|
47
|
+
errors << "{ '#{key}' preset -> #{err}}"
|
48
|
+
end
|
49
|
+
if err = preset_integrity(preset)
|
50
|
+
errors << "{ '#{key}' preset -> #{err}}"
|
51
|
+
end
|
52
|
+
end
|
58
53
|
end
|
59
54
|
|
60
55
|
private
|
61
56
|
|
62
|
-
def compile(*
|
63
|
-
|
64
|
-
@presets_custom.values_at(*preset_names).compact.reduce({}) do |p1, p2|
|
57
|
+
def compile(*presets)
|
58
|
+
presets.compact.reduce({}) do |p1, p2|
|
65
59
|
merge(p1, p2)
|
66
60
|
end
|
67
61
|
end
|
@@ -79,11 +73,6 @@ module Eco
|
|
79
73
|
end
|
80
74
|
end
|
81
75
|
|
82
|
-
# unsused: only play with the given abilities
|
83
|
-
def empty_model
|
84
|
-
JSON.parse(abilities_model.to_json).transform_values {|v| nil }
|
85
|
-
end
|
86
|
-
|
87
76
|
def preset_errors(preset)
|
88
77
|
return "No preset given" if !preset
|
89
78
|
errors = preset.map do |k, v|
|
@@ -146,7 +135,7 @@ module Eco
|
|
146
135
|
end
|
147
136
|
|
148
137
|
def ability_value_idx(ability, value)
|
149
|
-
abilities_model[ability].index(value)
|
138
|
+
abilities_model[ability].index(value) || -1
|
150
139
|
end
|
151
140
|
|
152
141
|
def abilities_model
|
@@ -163,56 +152,6 @@ module Eco
|
|
163
152
|
@policy_groups
|
164
153
|
end
|
165
154
|
|
166
|
-
def presets_custom
|
167
|
-
return @presets_custom if instance_variable_defined?(:@presets_custom)
|
168
|
-
@presets_custom = nil
|
169
|
-
if @presets_custom_file
|
170
|
-
if (file = File.expand_path(@presets_custom_file)) && File.exists?(file)
|
171
|
-
@presets_custom = JSON.load(File.open(file)).tap do |custom_presets|
|
172
|
-
errors = custom_presets.each_with_object([]) do |(key, preset), errors|
|
173
|
-
if err = preset_errors(preset)
|
174
|
-
errors << "{ '#{key}' preset -> #{err}}"
|
175
|
-
end
|
176
|
-
if err = preset_integrity(preset)
|
177
|
-
errors << "{ '#{key}' preset -> #{err}}"
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
fatal("File '#{file}' contains invalid presets:\n #{errors.join("\n ")}") if errors.length > 0
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def presets_map
|
188
|
-
return @presets_map if instance_variable_defined?(:@presets_map)
|
189
|
-
@presets_map = nil
|
190
|
-
if @presets_map_file
|
191
|
-
if (file = File.expand_path(@presets_map_file)) && File.exists?(file)
|
192
|
-
fatal("Maps file specified without 'presets_custom.json' file. Aborting!") if !presets_custom
|
193
|
-
@presets_map = JSON.load(File.open(file)).tap do |map_presets|
|
194
|
-
|
195
|
-
errors = []
|
196
|
-
if policy_groups.length > 0
|
197
|
-
errors = policy_groups.map do |pg|
|
198
|
-
exists = map_presets[pg.name.downcase] || presets_custom[pg.name.downcase]
|
199
|
-
exists ? nil : "'#{pg.name}'"
|
200
|
-
end.compact
|
201
|
-
|
202
|
-
warn("No maps or no preset for policy group(s): #{errors.join(", ")}") if errors.length > 0
|
203
|
-
end
|
204
|
-
|
205
|
-
errors = map_presets.map do |source, dest|
|
206
|
-
presets_custom[dest] ? nil : "'#{dest}'"
|
207
|
-
end.compact
|
208
|
-
|
209
|
-
warn("Unexisting mapped preset(s): #{errors.uniq.join(", ")}") if errors.length > 0
|
210
|
-
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
155
|
def fatal(msg)
|
217
156
|
raise msg if !@enviro
|
218
157
|
@enviro.logger.fatal(msg)
|
@@ -2,14 +2,15 @@
|
|
2
2
|
"files": [null, "download", "upload", "browse", "administrate"],
|
3
3
|
"data": [null, "view", "update", "administrate", "implement"],
|
4
4
|
"reports": [null, "view", "edit", "administrate"],
|
5
|
+
"pages": [null, "view", "update", "create", "administrate"],
|
6
|
+
"page_editor": [null, "basic", "intermediate", "advanced", "implement"],
|
7
|
+
"registers": [null, "view", "dashboard", "administrate", "implement"],
|
5
8
|
"tasks": [null, "reassign_self", "reassign", "administrate"],
|
6
9
|
"organization": [null, "view", "administrate", "implement"],
|
7
10
|
"person_core": [null, "attach", "view_people_manager", "dashboard"],
|
8
11
|
"person_core_create": [null, "create"],
|
9
12
|
"person_core_edit": [null, "edit"],
|
10
|
-
"person_account": [null, "view", "create", "edit"],
|
11
13
|
"person_details": [null, "view", "edit_public", "view_private", "edit_private"],
|
12
|
-
"
|
13
|
-
"
|
14
|
-
"registers": [null, "view", "dashboard", "administrate", "implement"]
|
14
|
+
"person_account": [null, "view", "create", "edit"],
|
15
|
+
"person_abilities": [null, "view", "edit"]
|
15
16
|
}
|
@@ -12,7 +12,6 @@ class Eco::API::Policies::DefaultPolicies::UserAccess < Eco::API::Common::Loader
|
|
12
12
|
people.each do |person|
|
13
13
|
remove_account_when_no_email!(person) if person.email.to_s.empty?
|
14
14
|
person.account.policy_group_ids = defid if no_policy_group_ids?(person)
|
15
|
-
refresh_abilities!(person)
|
16
15
|
end
|
17
16
|
|
18
17
|
warn_account_removal!
|
@@ -40,39 +39,10 @@ class Eco::API::Policies::DefaultPolicies::UserAccess < Eco::API::Common::Loader
|
|
40
39
|
return !!person.original_doc["account"]
|
41
40
|
end
|
42
41
|
|
43
|
-
def refresh_abilities!(person)
|
44
|
-
return nil if options.dig(:exclude, :abilities)
|
45
|
-
return nil unless account = person.account
|
46
|
-
account.permissions_custom = session.new_preset(person)
|
47
|
-
account.permissions_custom = min_abilities if no_abilities?(person)
|
48
|
-
end
|
49
|
-
|
50
42
|
def no_policy_group_ids?(person)
|
51
43
|
(account = person.account) && account.policy_group_ids.empty?
|
52
44
|
end
|
53
45
|
|
54
|
-
def no_abilities?(person)
|
55
|
-
return true unless account = person.account
|
56
|
-
account.permissions_custom && account.permissions_custom.values.all?(&:nil?)
|
57
|
-
end
|
58
|
-
|
59
|
-
def min_abilities
|
60
|
-
{
|
61
|
-
"files" => "upload",
|
62
|
-
"data" => nil,
|
63
|
-
"reports" => nil,
|
64
|
-
"pages" => "create",
|
65
|
-
"page_editor" => "basic",
|
66
|
-
"registers" => "view",
|
67
|
-
"organization" => nil,
|
68
|
-
"person_core" => "attach",
|
69
|
-
"person_core_edit" => nil,
|
70
|
-
"person_core_create" => nil,
|
71
|
-
"person_details" => "view",
|
72
|
-
"person_account" => nil
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
76
46
|
def defid
|
77
47
|
@defid ||= policy_groups.to_id([default_group]).compact
|
78
48
|
end
|
data/lib/eco/api/session.rb
CHANGED
@@ -61,28 +61,9 @@ module Eco
|
|
61
61
|
self
|
62
62
|
end
|
63
63
|
|
64
|
-
# Builds the presets using the usergroup ids of the input.
|
65
|
-
# @note for each flag/ability it will take the highest among those mapped for the present usergroups.
|
66
|
-
# @param input [Ecoportal::API::Internal::Person, Array<String>] the array should be of usegroup names or ids.
|
67
|
-
# @return [Hash] with custom presets.
|
68
|
-
def new_preset(input)
|
69
|
-
case input
|
70
|
-
when Ecoportal::API::Internal::Person
|
71
|
-
presets_factory.new(*input&.account&.policy_group_ids)
|
72
|
-
when Array
|
73
|
-
presets_factory.new(*input)
|
74
|
-
else
|
75
|
-
presets_factory.new(input)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
64
|
# Helper to state the abilities that a person should have with given their usergroups
|
80
65
|
def presets_factory
|
81
|
-
@presets_factory ||= Eco::API::Organization::PresetsFactory.new(
|
82
|
-
presets_custom: file_manager.dir.file(config.people.presets_custom, should_exist: true),
|
83
|
-
presets_map: file_manager.dir.file(config.people.presets_map, should_exist: true),
|
84
|
-
enviro: enviro
|
85
|
-
})
|
66
|
+
@presets_factory ||= Eco::API::Organization::PresetsFactory.new(enviro: enviro)
|
86
67
|
end
|
87
68
|
|
88
69
|
# Helper to obtain a EntryFactory
|
@@ -114,14 +114,16 @@ module Eco
|
|
114
114
|
logger.info(msg) unless silent
|
115
115
|
|
116
116
|
start_slice = Time.now
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
offer_retry_on(Ecoportal::API::Errors::TimeOut) do
|
118
|
+
people_api.batch do |batch|
|
119
|
+
slice.each do |person|
|
120
|
+
batch.public_send(method, person) do |response|
|
121
|
+
faltal("Request with no response") unless !!response
|
122
|
+
status[person] = response
|
123
|
+
end
|
122
124
|
end
|
123
|
-
end
|
124
|
-
end
|
125
|
+
end # end batch
|
126
|
+
end
|
125
127
|
|
126
128
|
iteration += 1
|
127
129
|
done += slice.length
|
@@ -129,6 +131,20 @@ module Eco
|
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
134
|
+
def offer_retry_on(error_type, retries_left = 3, &block)
|
135
|
+
begin
|
136
|
+
block.call
|
137
|
+
rescue error_type => e
|
138
|
+
raise unless retries_left > 0
|
139
|
+
print "Batch TimeOut. You have #{retries_left} retries left. Do you want to retry (y/N)? "
|
140
|
+
if (res = STDIN.gets.chomp) && res[0].downcase == "y"
|
141
|
+
offer_retry_on(error_type, retries_left - 1, &block)
|
142
|
+
else
|
143
|
+
raise
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
132
148
|
def str_stats(start, count)
|
133
149
|
now = Time.now
|
134
150
|
secs = (now - start).round(3)
|
@@ -297,16 +297,6 @@ module Eco
|
|
297
297
|
people.default_schema = name
|
298
298
|
end
|
299
299
|
|
300
|
-
# Specify the file with the account custom abilities presets
|
301
|
-
def presets_custom=(file)
|
302
|
-
people.presets_custom = file
|
303
|
-
end
|
304
|
-
|
305
|
-
# Specify the file with the usergroup to custom presets mapping
|
306
|
-
def presets_map=(file)
|
307
|
-
people.presets_map = file
|
308
|
-
end
|
309
|
-
|
310
300
|
# @see Eco::API::Session::Config::People
|
311
301
|
# @param (see Eco::API::Session::Config::People)
|
312
302
|
# @return [Eco::API::Common::People::PersonParser] parser/serializer for the defined `format`.
|
@@ -86,23 +86,7 @@ module Eco
|
|
86
86
|
def default_schema?
|
87
87
|
!!self["default_schema"]
|
88
88
|
end
|
89
|
-
|
90
|
-
def presets_custom=(file)
|
91
|
-
self["presets_custom"] = file
|
92
|
-
end
|
93
|
-
|
94
|
-
def presets_custom
|
95
|
-
self["presets_custom"]
|
96
|
-
end
|
97
|
-
|
98
|
-
def presets_map=(file)
|
99
|
-
self["presets_map"] = file
|
100
|
-
end
|
101
|
-
|
102
|
-
def presets_map
|
103
|
-
self["presets_map"]
|
104
|
-
end
|
105
|
-
|
89
|
+
|
106
90
|
# @return [Hash] with defined pairs format `key` and Person parsers.
|
107
91
|
def parsers
|
108
92
|
self["parsers"] ||= {}
|