eco-helpers 2.0.12 → 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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -73
  3. data/eco-helpers.gemspec +6 -4
  4. data/lib/eco-helpers.rb +1 -0
  5. data/lib/eco/api/common/base_loader.rb +14 -0
  6. data/lib/eco/api/common/loaders/use_case.rb +1 -1
  7. data/lib/eco/api/common/people/default_parsers/date_parser.rb +11 -1
  8. data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +1 -1
  9. data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +11 -11
  10. data/lib/eco/api/common/people/person_entry.rb +9 -2
  11. data/lib/eco/api/common/people/supervisor_helpers.rb +27 -0
  12. data/lib/eco/api/common/session/file_manager.rb +2 -2
  13. data/lib/eco/api/common/session/mailer.rb +0 -1
  14. data/lib/eco/api/common/session/s3_uploader.rb +0 -1
  15. data/lib/eco/api/common/session/sftp.rb +0 -1
  16. data/lib/eco/api/error.rb +5 -3
  17. data/lib/eco/api/microcases.rb +3 -1
  18. data/lib/eco/api/microcases/append_usergroups.rb +0 -1
  19. data/lib/eco/api/microcases/people_cache.rb +2 -2
  20. data/lib/eco/api/microcases/people_load.rb +2 -2
  21. data/lib/eco/api/microcases/people_refresh.rb +2 -2
  22. data/lib/eco/api/microcases/people_search.rb +6 -6
  23. data/lib/eco/api/microcases/preserve_default_tag.rb +23 -0
  24. data/lib/eco/api/microcases/preserve_filter_tags.rb +28 -0
  25. data/lib/eco/api/microcases/preserve_policy_groups.rb +30 -0
  26. data/lib/eco/api/microcases/set_account.rb +0 -1
  27. data/lib/eco/api/organization.rb +1 -0
  28. data/lib/eco/api/organization/people.rb +7 -0
  29. data/lib/eco/api/organization/people_analytics.rb +60 -0
  30. data/lib/eco/api/organization/presets_factory.rb +116 -93
  31. data/lib/eco/api/organization/presets_integrity.json +58 -0
  32. data/lib/eco/api/organization/presets_values.json +5 -4
  33. data/lib/eco/api/policies/default_policies/99_user_access_policy.rb +0 -30
  34. data/lib/eco/api/session.rb +1 -20
  35. data/lib/eco/api/session/batch.rb +42 -10
  36. data/lib/eco/api/session/batch/job.rb +3 -0
  37. data/lib/eco/api/session/config.rb +16 -15
  38. data/lib/eco/api/session/config/api.rb +4 -0
  39. data/lib/eco/api/session/config/apis.rb +14 -0
  40. data/lib/eco/api/session/config/files.rb +7 -0
  41. data/lib/eco/api/session/config/people.rb +3 -19
  42. data/lib/eco/api/usecases.rb +2 -0
  43. data/lib/eco/api/usecases/default_cases.rb +4 -1
  44. data/lib/eco/api/usecases/default_cases/abstract_policygroup_abilities_case.rb +161 -0
  45. data/lib/eco/api/usecases/default_cases/analyse_people_case.rb +76 -0
  46. data/lib/eco/api/usecases/default_cases/codes_to_tags_case.rb +2 -3
  47. data/lib/eco/api/usecases/default_cases/hris_case.rb +14 -8
  48. data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +11 -1
  49. data/lib/eco/api/usecases/default_cases/restore_db_case.rb +1 -2
  50. data/lib/eco/api/usecases/default_cases/supers_cyclic_identify_case.rb +72 -0
  51. data/lib/eco/api/usecases/default_cases/supers_hierarchy_case.rb +59 -0
  52. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +104 -26
  53. data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +62 -36
  54. data/lib/eco/cli.rb +0 -10
  55. data/lib/eco/cli/config/default/options.rb +19 -17
  56. data/lib/eco/cli/config/default/people_filters.rb +3 -3
  57. data/lib/eco/cli/config/default/usecases.rb +77 -25
  58. data/lib/eco/cli/config/default/workflow.rb +6 -1
  59. data/lib/eco/cli/config/help.rb +1 -0
  60. data/lib/eco/cli/config/options_set.rb +106 -13
  61. data/lib/eco/cli/config/use_cases.rb +33 -33
  62. data/lib/eco/cli/scripting/args_helpers.rb +30 -3
  63. data/lib/eco/data.rb +1 -0
  64. data/lib/eco/data/crypto/encryption.rb +3 -3
  65. data/lib/eco/data/files/directory.rb +28 -20
  66. data/lib/eco/data/files/helpers.rb +6 -4
  67. data/lib/eco/data/fuzzy_match.rb +119 -0
  68. data/lib/eco/data/fuzzy_match/array_helpers.rb +75 -0
  69. data/lib/eco/data/fuzzy_match/chars_position_score.rb +37 -0
  70. data/lib/eco/data/fuzzy_match/ngrams_score.rb +73 -0
  71. data/lib/eco/data/fuzzy_match/pairing.rb +102 -0
  72. data/lib/eco/data/fuzzy_match/result.rb +67 -0
  73. data/lib/eco/data/fuzzy_match/results.rb +53 -0
  74. data/lib/eco/data/fuzzy_match/score.rb +44 -0
  75. data/lib/eco/data/fuzzy_match/stop_words.rb +35 -0
  76. data/lib/eco/data/fuzzy_match/string_helpers.rb +69 -0
  77. data/lib/eco/version.rb +1 -1
  78. metadata +86 -10
  79. data/lib/eco/api/microcases/refresh_abilities.rb +0 -19
  80. data/lib/eco/api/organization/presets_reference.json +0 -59
  81. data/lib/eco/api/usecases/default_cases/refresh_abilities_case.rb +0 -30
@@ -2,18 +2,17 @@ class Eco::API::UseCases::DefaultCases::HrisCase < Eco::API::Common::Loaders::Us
2
2
  name "hris"
3
3
  type :sync
4
4
 
5
+ attr_reader :creation, :update, :supers, :leavers
6
+
5
7
  def main(entries, people, session, options, usecase)
6
8
  micro = session.micro
7
- creation = session.new_job("main", "create", :create, usecase)
8
- update = session.new_job("main", "update", :update, usecase)
9
- supers = session.new_job("post", "supers", :update, usecase, :core)
10
- leavers = session.new_job("post", "leavers", :update, usecase, :account)
9
+ @creation = session.new_job("main", "create", :create, usecase)
10
+ @update = session.new_job("main", "update", :update, usecase)
11
+ @supers = session.new_job("post", "supers", :update, usecase, :core)
12
+ @leavers = session.new_job("post", "leavers", :update, usecase, :account)
11
13
 
12
14
  micro.with_each_leaver(entries, people, options) do |person|
13
- leavers.add(person) do |person|
14
- person.supervisor_id = nil
15
- person.account = nil if person.account
16
- end
15
+ leavers.add(person, &method(:leavers_callback))
17
16
  end
18
17
 
19
18
  micro.with_each(entries, people, options) do |entry, person|
@@ -24,4 +23,11 @@ class Eco::API::UseCases::DefaultCases::HrisCase < Eco::API::Common::Loaders::Us
24
23
  end
25
24
  end
26
25
 
26
+ private
27
+
28
+ def leavers_callback(person)
29
+ person.supervisor_id = nil
30
+ person.account = nil if person.account
31
+ end
32
+
27
33
  end
@@ -2,13 +2,23 @@ class Eco::API::UseCases::DefaultCases::ResetLandingPageCase < Eco::API::Common:
2
2
  name "reset-landing-page"
3
3
  type :transform
4
4
 
5
+ attr_reader :session, :options
6
+
5
7
  def main(people, session, options, usecase)
8
+ @session = session; @options = options
6
9
  update = session.new_job("main", "update", :update, usecase, :core)
7
10
 
8
11
  people.users.each do |user|
9
- user.account.landing_page_id = nil
12
+ user.account.landing_page_id = page_id
10
13
  update.add(user)
11
14
  end
12
15
  end
13
16
 
17
+ private
18
+
19
+ def page_id
20
+ options[:page_id]
21
+ end
22
+
23
+
14
24
  end
@@ -59,7 +59,6 @@ class Eco::API::UseCases::DefaultCases::RestoreDBCase < Eco::API::Common::Loader
59
59
  dst.policy_group_ids = src.policy_group_ids unless options.dig(:exclude, :policy_groups)
60
60
 
61
61
  unless options.dig(:exclude, :abilities)
62
- dst.permissions_preset = src.permissions_preset
63
62
  dst.permissions_custom = src.permissions_custom
64
63
  end
65
64
 
@@ -75,7 +74,7 @@ class Eco::API::UseCases::DefaultCases::RestoreDBCase < Eco::API::Common::Loader
75
74
  dst.starred_ids = src.starred_ids
76
75
  dst.landing_page_id = src.landing_page_id
77
76
  end
78
-
77
+
79
78
  dst&.send_invites = options[:send_invites] if options.key?(:send_invites)
80
79
  end
81
80
  end
@@ -0,0 +1,72 @@
1
+ class Eco::API::UseCases::DefaultCases::SupersCyclicIdentify < Eco::API::Common::Loaders::UseCase
2
+ name "identify-cyclic-supers"
3
+ type :export
4
+
5
+ attr_reader :session, :people, :options
6
+
7
+ def main(people, session, options, usecase)
8
+ options[:end_get] = false
9
+ @session = session; @options = options; @people = people
10
+
11
+ save!(cyclic_sets)
12
+ end
13
+
14
+ private
15
+
16
+ def cyclic_sets
17
+ Eco::API::Common::People::SupervisorHelpers.identify_cyclic_chains(people)
18
+ end
19
+
20
+ def file
21
+ @file ||= options.dig(:output, :file) || "cyclic_supers.txt"
22
+ end
23
+
24
+ def save!(data)
25
+ if data.empty?
26
+ session.logger.info("There were no cyclic supervisors identified!!")
27
+ return
28
+ end
29
+
30
+ ext = File.extname(file).downcase.delete(".")
31
+
32
+ File.open(file, "w") do |fd|
33
+ if ext == "txt"
34
+ create_file(data, file: file, format: :txt)
35
+ elsif ext == "html"
36
+ puts "html is still not supported"
37
+ exit(1)
38
+ create_file(data, file: file, format: :html)
39
+ elsif ext == "json"
40
+ puts "json is still not supported"
41
+ exit(1)
42
+ create_file(data, file: file, format: :json)
43
+ end
44
+ end
45
+ end
46
+
47
+ def create_file(sets, file:, format: :txt)
48
+ File.open(file, "w") do |fd|
49
+ fd << sets_to_str(sets, format: format)
50
+ end
51
+ puts "Generated file #{file}"
52
+ end
53
+
54
+ def sets_to_str(sets, format: :txt)
55
+ raise "Required Array. Given: #{sets.class}" unless sets.is_a?(Array)
56
+ "".tap do |str|
57
+ sets.each do |set|
58
+ str << set_to_str(set, format: format)
59
+ end
60
+ end
61
+ end
62
+
63
+ def set_to_str(set, lev: 0, format: :txt)
64
+ raise "Required Array. Given: #{set.class}" unless set.is_a?(Array)
65
+ "".tap do |str|
66
+ entry = set.shift
67
+ str << "#{" " * lev}#{(lev > 0)? "+-#{lev}- " : ""}#{entry.name} (#{entry.external_id}|#{entry.email}|#{entry.id})\n"
68
+ str << set_to_str(set, lev: lev + 1, format: format) unless !set || set.empty?
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,59 @@
1
+ class Eco::API::UseCases::DefaultCases::SupersHierarchy < Eco::API::Common::Loaders::UseCase
2
+ name "supers-hierarchy"
3
+ type :export
4
+
5
+ attr_reader :session, :people, :options
6
+
7
+ def main(people, session, options, usecase)
8
+ options[:end_get] = false
9
+ @session = session; @options = options; @people = people
10
+
11
+ save!(hierarchy)
12
+ end
13
+
14
+ private
15
+
16
+ def hierarchy
17
+ Eco::API::Common::People::SupervisorHelpers.supervisors_tree(people)
18
+ end
19
+
20
+ def file
21
+ @file ||= options.dig(:output, :file) || "supers_hierarchy.txt"
22
+ end
23
+
24
+ def save!(data)
25
+ ext = File.extname(file).downcase.delete(".")
26
+
27
+ File.open(file, "w") do |fd|
28
+ if ext == "txt"
29
+ create_file(data, file: file, format: :txt)
30
+ elsif ext == "html"
31
+ puts "html is still not supported"
32
+ exit(1)
33
+ create_file(data, file: file, format: :html)
34
+ elsif ext == "json"
35
+ puts "json is still not supported"
36
+ exit(1)
37
+ create_file(data, file: file, format: :json)
38
+ end
39
+ end
40
+ end
41
+
42
+ def create_file(tree, file:, format: :txt)
43
+ File.open(file, "w") do |fd|
44
+ fd << tree_to_str(tree, format: format)
45
+ end
46
+ puts "Generated file #{file}"
47
+ end
48
+
49
+ def tree_to_str(tree, lev: 0, format: :txt)
50
+ raise "Required Hash tree structure. Given: #{tree.class}" unless tree.is_a?(Hash)
51
+ "".tap do |str|
52
+ tree.each do |entry, subtree|
53
+ str << "#{" " * lev}#{(lev > 0)? "+-#{lev}- " : ""}#{entry.name} (#{entry.external_id}|#{entry.email}|#{entry.id})\n"
54
+ str << tree_to_str(subtree, lev: lev + 1, format: format) unless !subtree || subtree.empty?
55
+ end
56
+ end
57
+ end
58
+
59
+ end
@@ -2,44 +2,122 @@ class Eco::API::UseCases::DefaultCases::ToCsvCase < Eco::API::Common::Loaders::U
2
2
  name "to-csv"
3
3
  type :export
4
4
 
5
+ attr_reader :session, :options, :people
6
+
5
7
  def main(people, session, options, usecase)
8
+ options[:end_get] = false
9
+ @session = session; @options = options; @people = people
10
+
6
11
  unless people && !people.empty?
7
12
  session.logger.warn("No source people to create the file... aborting!")
8
13
  return false
9
14
  end
10
15
 
11
- unless file = options[:file] || options.dig(:export, :file, :name)
12
- session.logger.error("Destination file not specified")
13
- return false
14
- end
15
-
16
16
  session.logger.info("going to create file: #{file}")
17
- CSV.open(file, "w") do |csv|
18
- deps = {"supervisor_id" => {people: people}}
19
- entry = session.new_entry(people.first, dependencies: deps)
20
- header = entry.external_entry.keys
21
-
22
- if options.dig(:nice_header) || options.dig(:export, :options, :nice_header)
23
- name_maps = session.schema.fields_by_alt_id.transform_values do |fld|
24
- fld.name
25
- end.merge({
26
- "policy_group_ids" => "User Group(s)",
27
- "email" => "Email",
28
- "name" => "Name",
29
- "supervisor_id" => "Manager ID",
30
- "filter_tags" => "Locations",
31
- "default_tag" => "Default Location",
32
- "id" => "ecoPortal ID"
33
- })
34
- header = header.map {|name| name_maps[name] ? name_maps[name] : name}
35
- end
17
+ header = spot_header
36
18
 
19
+ CSV.open(file, "w") do |csv|
37
20
  csv << header
38
21
  people.each do |person|
39
- csv << session.new_entry(person, dependencies: deps).external_entry.values
22
+ csv << to_row(person)
40
23
  end
41
24
  end
42
- exit(0)
43
25
  end
44
26
 
27
+ private
28
+
29
+ def to_row(person)
30
+ entry = to_entry_type(person)
31
+ entry.values_at(*keys(entry))
32
+ end
33
+
34
+ def spot_header
35
+ header = keys(to_entry_type(people.first))
36
+ header = yield(header) if block_given?
37
+ header = nice_header_names(header) if nice_header_names?
38
+ header
39
+ end
40
+
41
+ def keys(entry)
42
+ entry.keys - ["freemium", "send_invites"]
43
+ end
44
+
45
+ def nice_header_names?
46
+ options.dig(:nice_header) || options.dig(:export, :options, :nice_header)
47
+ end
48
+
49
+ def nice_header_names(header)
50
+ name_maps = session.schema.fields_by_alt_id.each_with_object({}) do |(alt_id, fld), mappings|
51
+ mappings[alt_id] = fld.name
52
+ end.merge({
53
+ "policy_group_ids" => "User Group(s)",
54
+ "email" => "Email",
55
+ "name" => "Name",
56
+ "supervisor_id" => "Manager ID",
57
+ "filter_tags" => "Locations",
58
+ "default_tag" => "Default Location",
59
+ "id" => "ecoPortal ID",
60
+ "external_id" => "Reference ID (ext_id)",
61
+ "login_provider_ids" => "Login Methods",
62
+ "landing_page_id" => "Landing Page ID",
63
+ "show_sidebar" => "(pref) Sidebar Open?",
64
+ "show_shortcuts" => "(pref) Link to Registers?",
65
+ "show_coming_soon" => "(pref) Coming Soon List?",
66
+ "show_recently_visited_forms" => "(pref) Recently Visited Forms List?",
67
+ "show_tasks" => "(pref) Tasks List?",
68
+ "show_task_bubbles" => "(pref) Task Count Bubbles",
69
+ "kiosk_enabled" => "Kiosk User?",
70
+ "freemium" => "Freemium User?",
71
+ "files" => "(able) on Files",
72
+ "reports" => "(able) on Report Structures",
73
+ "data" => "(able) on Data (hours, datasets)",
74
+ "organization" => "(able) on Organization Config",
75
+ "pages" => "(able) on Page/Entries",
76
+ "page_editor" => "(able) page Editor Level",
77
+ "registers" => "(able) on Registers",
78
+ "tasks" => "(able) on Tasks",
79
+ "person_core" => "(able) on People",
80
+ "person_core_create" => "(able) Create People?",
81
+ "person_core_edit" => "(able) Edit People?",
82
+ "person_details" => "(able) on People Schema Details",
83
+ "person_account" => "(able) on Users",
84
+ "person_abilities" => "(able) on Users' Abilities",
85
+ "custom_files" => "(min) on Files",
86
+ "custom_reports" => "(min) on Report Structures",
87
+ "custom_data" => "(min) on Data (hours, datasets)",
88
+ "custom_organization" => "(min) on Organization Config",
89
+ "custom_pages" => "(min) on Page/Entries",
90
+ "custom_page_editor" => "(min) page Editor Level",
91
+ "custom_registers" => "(min) on Registers",
92
+ "custom_tasks" => "(min) on Tasks",
93
+ "custom_person_core" => "(min) on People",
94
+ "custom_person_core_create" => "(min) Create People?",
95
+ "custom_person_core_edit" => "(min) Edit People?",
96
+ "custom_person_details" => "(min) on People Schema Details",
97
+ "custom_person_account" => "(min) on Users",
98
+ "custom_person_abilities" => "(min) on Users' Abilities"
99
+ })
100
+ header.map {|name| name_maps[name] ? name_maps[name] : name}
101
+ end
102
+
103
+ def to_entry_type(person)
104
+ session.new_entry(person, dependencies: deps).yield_self do |person_entry|
105
+ options.dig(:export, :options, :internal_names) ? person_entry.mapped_entry : person_entry.external_entry
106
+ end
107
+ end
108
+
109
+ def deps
110
+ @deps ||= {"supervisor_id" => {people: people}}
111
+ end
112
+
113
+ def file
114
+ @file ||= (options[:file] || options.dig(:export, :file, :name)).tap do |filename|
115
+ unless filename
116
+ session.logger.error("Destination file not specified")
117
+ return false
118
+ end
119
+ end
120
+ end
121
+
122
+
45
123
  end
@@ -1,53 +1,79 @@
1
- class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::DefaultCases::ToCsvDetailedCase < Eco::API::UseCases::DefaultCases::ToCsvCase
2
2
  name "to-csv-detailed"
3
3
  type :export
4
4
 
5
- def main(people, session, options, usecase)
6
- unless people && !people.empty?
7
- session.logger.warn("No source people to create the file... aborting!")
8
- return false
9
- end
5
+ private
6
+
7
+ def to_row(person)
8
+ entry = to_entry_type(person)
9
+ data = entry.values_at(*keys(entry))
10
+ data << person.subordinates
11
+ data << person_supervisor(person)
12
+ data += user_abilities(person)
13
+ data += user_permissions_custom(person) if options.dig(:export, :options, :permissions_custom)
14
+ account = person.account
15
+ data << account&.landing_page_id
16
+ data += user_preferences(person)
17
+ data
18
+ end
10
19
 
11
- unless file = options[:file] || options.dig(:export, :file, :name)
12
- session.logger.error("Destination file not specified")
13
- return false
20
+ def person_supervisor(person)
21
+ session.micro.with_supervisor(person.supervisor_id, people) do |supervisor|
22
+ return supervisor ? supervisor.name : ""
14
23
  end
24
+ end
15
25
 
16
- login_providers = session.login_providers
17
- abilities = session.presets_factory.keys
26
+ def user_abilities(person)
27
+ account_abilities = (person.account && person.account.permissions_merged) || {}
28
+ abilities.map {|key| account_abilities[key] || "no access"}
29
+ end
18
30
 
19
- session.logger.info("going to create file: #{file}")
20
- CSV.open(file, "w") do |csv|
21
- deps = {"supervisor_id" => {people: people}}
31
+ def user_permissions_custom(person)
32
+ account_abilities = (person.account && person.account.permissions_custom) || {}
33
+ abilities.map {|key| account_abilities[key] || "no access"}
34
+ end
22
35
 
23
- person_model = people.first
24
- person_entry = session.new_entry(person_model, dependencies: deps)
25
- header = person_entry.external_entry.keys
26
- header += ["Subordinates"]
27
- header += ["Supervisor Name"]
28
- header += abilities
29
- header += ["Landing Page"]
36
+ def user_preferences(person)
37
+ user_preferences = (person.account && person.account.preferences&.doc) || {}
38
+ preferences.map {|key| user_preferences[key] || false}
39
+ end
30
40
 
31
- csv << header
32
- people.each do |person|
33
- data = session.new_entry(person, dependencies: deps).external_entry.values
41
+ def spot_header
42
+ super do |header|
43
+ header << "Subordinates"
44
+ header << "Supervisor Name"
45
+ header += abilities_header
46
+ header += abilities_header("custom") if options.dig(:export, :options, :permissions_custom)
47
+ header << "Landing Page"
48
+ header += preferences
49
+ header
50
+ end
51
+ end
34
52
 
35
- data.push(person.subordinates)
36
- session.micro.with_supervisor(person.supervisor_id, people) do |supervisor|
37
- data.push supervisor ? supervisor.name : ""
38
- end
53
+ def keys(entry)
54
+ super(entry) + ["freemium"]
55
+ end
39
56
 
40
- person_abilities = (person.account && person.account.permissions_custom) || {}
41
- data += abilities.map {|key| person_abilities[key] || "no access"}
57
+ def login_providers
58
+ session.login_providers
59
+ end
42
60
 
43
- if person.account && landing_id = person.account.landing_page_id
44
- data.push(landing_id)
45
- end
61
+ def abilities
62
+ @abilities ||= session.presets_factory.keys
63
+ end
46
64
 
47
- csv << data
48
- end
65
+ def abilities_header(prefix = nil)
66
+ abilities.map do |key|
67
+ prefix ? "#{prefix}_#{key}" : key
49
68
  end
50
- exit(0)
69
+ end
70
+
71
+ def preferences
72
+ @preferences ||= [
73
+ "show_sidebar", "show_shortcuts", "show_coming_soon", "show_recently_visited_forms",
74
+ "show_tasks", "show_task_bubbles",
75
+ "kiosk_enabled"
76
+ ]
51
77
  end
52
78
 
53
79
  end