eco-helpers 2.6.4 → 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +95 -0
  4. data/CHANGELOG.md +139 -2
  5. data/Rakefile +13 -7
  6. data/eco-helpers.gemspec +2 -2
  7. data/lib/eco/api/common/loaders/base.rb +2 -2
  8. data/lib/eco/api/common/loaders/case_base.rb +1 -1
  9. data/lib/eco/api/common/loaders/config/workflow/mailer.rb +5 -5
  10. data/lib/eco/api/common/loaders/error_handler.rb +8 -5
  11. data/lib/eco/api/common/loaders/parser.rb +44 -22
  12. data/lib/eco/api/common/loaders/policy.rb +6 -4
  13. data/lib/eco/api/common/loaders/use_case.rb +13 -7
  14. data/lib/eco/api/common/people/base_parser.rb +0 -2
  15. data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +0 -1
  16. data/lib/eco/api/common/people/default_parsers/csv_parser.rb +1 -1
  17. data/lib/eco/api/common/people/default_parsers/date_parser.rb +64 -12
  18. data/lib/eco/api/common/people/default_parsers/freemium_parser.rb +0 -1
  19. data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +13 -5
  20. data/lib/eco/api/common/people/default_parsers/multi_parser.rb +0 -1
  21. data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +18 -5
  22. data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +8 -8
  23. data/lib/eco/api/common/people/default_parsers/select_parser.rb +50 -26
  24. data/lib/eco/api/common/people/default_parsers/send_invites_parser.rb +6 -6
  25. data/lib/eco/api/common/people/default_parsers/xls_parser.rb +9 -12
  26. data/lib/eco/api/common/people/default_parsers.rb +1 -12
  27. data/lib/eco/api/common/people/entries.rb +13 -13
  28. data/lib/eco/api/common/people/entry_factory.rb +76 -45
  29. data/lib/eco/api/common/people/person_attribute_parser.rb +8 -12
  30. data/lib/eco/api/common/people/person_entry.rb +86 -75
  31. data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +60 -44
  32. data/lib/eco/api/common/people/person_factory.rb +30 -22
  33. data/lib/eco/api/common/people/person_modifier.rb +11 -13
  34. data/lib/eco/api/common/people/person_parser.rb +101 -39
  35. data/lib/eco/api/common/people/supervisor_helpers.rb +25 -26
  36. data/lib/eco/api/common/session/base_session.rb +9 -9
  37. data/lib/eco/api/common/session/environment.rb +7 -5
  38. data/lib/eco/api/common/session/sftp.rb +59 -32
  39. data/lib/eco/api/common/version_patches/exception.rb +11 -13
  40. data/lib/eco/api/error.rb +32 -20
  41. data/lib/eco/api/organization/node_classifications.rb +82 -0
  42. data/lib/eco/api/organization/policy_groups.rb +4 -6
  43. data/lib/eco/api/organization/tag_tree.rb +169 -93
  44. data/lib/eco/api/organization.rb +1 -0
  45. data/lib/eco/api/session/batch/job.rb +1 -1
  46. data/lib/eco/api/session/config/tagtree.rb +41 -23
  47. data/lib/eco/api/session/config/workflow.rb +113 -88
  48. data/lib/eco/api/session/config.rb +6 -0
  49. data/lib/eco/api/session.rb +51 -29
  50. data/lib/eco/api/usecases/base_io.rb +28 -25
  51. data/lib/eco/api/usecases/default/locations/cli/tagtree_extract_cli.rb +7 -2
  52. data/lib/eco/api/usecases/default/locations/cli/tagtree_upload_cli.rb +21 -0
  53. data/lib/eco/api/usecases/default/locations/csv_to_tree_case.rb +3 -3
  54. data/lib/eco/api/usecases/default/locations/tagtree_extract_case.rb +54 -23
  55. data/lib/eco/api/usecases/default/locations/tagtree_upload_case.rb +87 -0
  56. data/lib/eco/api/usecases/default/locations.rb +1 -0
  57. data/lib/eco/api/usecases/default/people/analyse_people_case.rb +60 -56
  58. data/lib/eco/api/usecases/default/people/change_email_case.rb +8 -9
  59. data/lib/eco/api/usecases/default/people/clean_unknown_tags_case.rb +13 -11
  60. data/lib/eco/api/usecases/default/people/clear_abilities_case.rb +2 -2
  61. data/lib/eco/api/usecases/default/people/org_data_convert_case.rb +25 -27
  62. data/lib/eco/api/usecases/default/people/refresh_case.rb +2 -2
  63. data/lib/eco/api/usecases/default/people/reinvite_trans_case.rb +1 -1
  64. data/lib/eco/api/usecases/default/people/reinvite_trans_cli.rb +0 -1
  65. data/lib/eco/api/usecases/default/people/restore_db_case.rb +39 -34
  66. data/lib/eco/api/usecases/default/people/set_default_tag_case.rb +19 -15
  67. data/lib/eco/api/usecases/default/people/supers_cyclic_identify_case.rb +16 -12
  68. data/lib/eco/api/usecases/default_cases/hris_case.rb +17 -15
  69. data/lib/eco/api/usecases/default_cases/samples/sftp_case.rb +30 -16
  70. data/lib/eco/api/usecases/graphql/base.rb +5 -3
  71. data/lib/eco/api/usecases/graphql/helpers/base/case_env.rb +4 -1
  72. data/lib/eco/api/usecases/graphql/helpers/base/graphql_env.rb +14 -0
  73. data/lib/eco/api/usecases/graphql/helpers/base.rb +5 -4
  74. data/lib/eco/api/usecases/graphql/helpers/location/base/classifications_parser.rb +60 -0
  75. data/lib/eco/api/usecases/graphql/helpers/location/base/tree_tracking.rb +72 -0
  76. data/lib/eco/api/usecases/graphql/helpers/location/base.rb +25 -59
  77. data/lib/eco/api/usecases/graphql/helpers/location/command/diff/as_update.rb +59 -0
  78. data/lib/eco/api/usecases/graphql/helpers/location/command/diff/compare.rb +49 -0
  79. data/lib/eco/api/usecases/graphql/helpers/location/command/diff.rb +11 -0
  80. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/commandable.rb +46 -0
  81. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_archive.rb +23 -0
  82. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_unarchive.rb +65 -0
  83. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable.rb +49 -0
  84. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable/relation_safe_sort.rb +119 -0
  85. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable.rb +59 -0
  86. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages.rb +82 -0
  87. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs.rb +20 -0
  88. data/lib/eco/api/usecases/graphql/helpers/location/command/optimizations.rb +84 -0
  89. data/lib/eco/api/usecases/graphql/helpers/location/command/result.rb +4 -4
  90. data/lib/eco/api/usecases/graphql/helpers/location/command/results.rb +24 -12
  91. data/lib/eco/api/usecases/graphql/helpers/location/command.rb +21 -24
  92. data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_map.rb +1 -1
  93. data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_set.rb +10 -11
  94. data/lib/eco/api/usecases/graphql/helpers/location/tags_remap.rb +8 -9
  95. data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +41 -12
  96. data/lib/eco/api/usecases/graphql/samples/location/command/results.rb +11 -80
  97. data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +89 -0
  98. data/lib/eco/api/usecases/graphql/samples/location/command/service.rb +6 -0
  99. data/lib/eco/api/usecases/graphql/samples/location/command/track_changed_ids.rb +89 -0
  100. data/lib/eco/api/usecases/graphql/samples/location/command.rb +3 -0
  101. data/lib/eco/api/usecases/graphql/samples/location/service/base.rb +9 -0
  102. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/heading.rb +18 -0
  103. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/inputable.rb +53 -0
  104. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/classifications.rb +34 -0
  105. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/helpers.rb +28 -0
  106. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing.rb +46 -0
  107. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible.rb +38 -0
  108. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +105 -0
  109. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/discarded.rb +16 -0
  110. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/input.rb +15 -0
  111. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/node_attr_maps.rb +22 -0
  112. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/parser.rb +45 -0
  113. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter.rb +36 -0
  114. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/output.rb +56 -0
  115. data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list.rb +41 -0
  116. data/lib/eco/api/usecases/graphql/samples/location/service.rb +8 -0
  117. data/lib/eco/api/usecases/graphql/samples/location.rb +1 -0
  118. data/lib/eco/api/usecases/graphql/utils/sftp.rb +96 -36
  119. data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +8 -6
  120. data/lib/eco/api/usecases/ooze_samples/helpers/creatable.rb +4 -3
  121. data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +39 -25
  122. data/lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb +13 -15
  123. data/lib/eco/api/usecases/ooze_samples/helpers/filters.rb +50 -21
  124. data/lib/eco/api/usecases/ooze_samples/helpers/ooze_handlers.rb +21 -11
  125. data/lib/eco/api/usecases/ooze_samples/helpers/rescuable.rb +2 -0
  126. data/lib/eco/api/usecases/ooze_samples/helpers/shortcuts.rb +49 -43
  127. data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +17 -19
  128. data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +48 -43
  129. data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +33 -34
  130. data/lib/eco/api/usecases/ooze_samples/target_oozes_update_case.rb +8 -10
  131. data/lib/eco/api/usecases.rb +0 -1
  132. data/lib/eco/cli/config/use_cases.rb +31 -29
  133. data/lib/eco/cli_default/workflow.rb +13 -14
  134. data/lib/eco/csv/table.rb +34 -25
  135. data/lib/eco/data/hashes/array_diff.rb +24 -35
  136. data/lib/eco/data/hashes/diff_result/meta.rb +131 -0
  137. data/lib/eco/data/hashes/diff_result.rb +65 -57
  138. data/lib/eco/data/hashes/sanke_camel_indifferent_access.rb +278 -0
  139. data/lib/eco/data/hashes.rb +1 -1
  140. data/lib/eco/data/locations/convert.rb +1 -1
  141. data/lib/eco/data/locations/node_base/csv_convert.rb +19 -9
  142. data/lib/eco/data/locations/node_base/parsing.rb +4 -2
  143. data/lib/eco/data/locations/node_base/treeify.rb +149 -132
  144. data/lib/eco/data/locations/node_base.rb +15 -4
  145. data/lib/eco/data/locations/node_diff/accessors.rb +13 -5
  146. data/lib/eco/data/locations/node_diff/nodes_diff/clustered_treeify.rb +101 -0
  147. data/lib/eco/data/locations/node_diff/nodes_diff/diffs_tree.rb +99 -0
  148. data/lib/eco/data/locations/node_diff/{selectors.rb → nodes_diff/selectors.rb} +1 -1
  149. data/lib/eco/data/locations/node_diff/nodes_diff.rb +50 -35
  150. data/lib/eco/data/locations/node_diff.rb +45 -17
  151. data/lib/eco/data/locations/node_level/parsing.rb +15 -21
  152. data/lib/eco/data/locations/node_level.rb +66 -22
  153. data/lib/eco/data/locations/node_plain/parsing.rb +1 -1
  154. data/lib/eco/data/locations/node_plain.rb +60 -7
  155. data/lib/eco/data/strings/camel_case.rb +35 -0
  156. data/lib/eco/data/strings/snake_case.rb +18 -0
  157. data/lib/eco/data/strings.rb +8 -0
  158. data/lib/eco/data.rb +1 -0
  159. data/lib/eco/language/auxiliar_logger.rb +7 -5
  160. data/lib/eco/language/methods/call_detector.rb +11 -0
  161. data/lib/eco/language/methods/dsl_able.rb +7 -1
  162. data/lib/eco/language/methods.rb +2 -1
  163. data/lib/eco/language/models/collection.rb +23 -25
  164. data/lib/eco/language/models/parser_serializer.rb +24 -5
  165. data/lib/eco/version.rb +1 -1
  166. data/lib/eco-helpers.rb +0 -1
  167. metadata +52 -7
  168. data/lib/eco/data/hashes/diff_meta.rb +0 -52
@@ -1,12 +1,9 @@
1
1
  class Eco::API::UseCases::GraphQL::Samples::Location
2
- # Logic to:
3
- # 1. Track-down results and errors
4
- # 2. Create tags remap csv table batch design
2
+ # Logic to: Track-down results and errors
5
3
  module Command::Results
6
- include Eco::API::UseCases::GraphQL::Helpers::Location::Base
4
+ include Eco::API::UseCases::GraphQL::Helpers::Base::CaseEnv
7
5
 
8
6
  attr_accessor :error, :exception
9
- attr_accessor :tags_remap_csv_file
10
7
 
11
8
  def rescued
12
9
  yield
@@ -18,39 +15,35 @@ class Eco::API::UseCases::GraphQL::Samples::Location
18
15
  Eco::API::UseCases::GraphQL::Helpers::Location::Command::Results
19
16
  end
20
17
 
21
- def tags_remap_class
22
- Eco::API::UseCases::GraphQL::Helpers::Location::TagsRemap
23
- end
24
-
25
18
  # Capture results
26
19
  def results
27
20
  @results ||= {}
28
21
  end
29
22
 
30
- # The maps of tags to be used in batch remap tags
31
- # @return [Array<Array>] source/destination pairs of `Array<String>`
32
- def tags_remap_table
33
- @tags_remap_table ||= tags_remap_class.new
34
- end
35
-
36
23
  # Errors tracking/logging.
37
24
  # @note it gives feedback on where an error has occurred.
38
25
  # @param page_results [Eco::API::UseCases::GraphQL::Helpers::Locations::Commands::CommandResults]
39
26
  # @param stage [Symbol] used when we launch an update in different phases (i.e. rename, move, etc.)
40
27
  # @return [Boolean] whether or not there was an error
41
28
  def page_errors?(page_results, page, pages, done, total, stage: nil)
42
- raise "Expecting CommandResults object. Given: #{page_results.class}" unless page_results.is_a?(request_results_class)
29
+ msg = "Expecting CommandResults object. Given: #{page_results.class}"
30
+ raise msg unless page_results.is_a?(request_results_class)
31
+
43
32
  stage_str = stage ? "'#{stage}' " : ''
44
33
  fingerprint = "#{stage_str}#{page} (of #{pages})"
45
34
  errored = false
46
35
 
47
36
  if page_results.error?
48
37
  errored = true
49
- log(:error) { "Error on #{fingerprint}: #{page_results.error.doc.pretty_inspect}" }
38
+ log(:error) {
39
+ "Error on #{fingerprint}: #{page_results.error.doc.pretty_inspect}"
40
+ }
50
41
  end
51
42
 
52
43
  if page_results.applied?
53
- log(:info) { "Success on #{fingerprint}: #{done} (of #{total}) commands applied!" }
44
+ log(:info) {
45
+ "Success on #{fingerprint}: #{done} (of #{total}) commands applied!"
46
+ }
54
47
  elsif page_results.errored?
55
48
  errored = true
56
49
  msg = "Some command failed on #{fingerprint}:\n#{page_results.stats}"
@@ -63,67 +56,5 @@ class Eco::API::UseCases::GraphQL::Samples::Location
63
56
 
64
57
  errored
65
58
  end
66
-
67
- # Based on commands that succeded, and the batch stage, it tracks
68
- # the tag remaps that should be batches against existing pages
69
- # @note
70
- # 1. This requires to have available the `current_tree` locations structure
71
- # - Fortunatelly this is being tracked, as it is returned as payload of the response.
72
- # 2. Based on the assumption that the order of the commands (stages) happens like this:
73
- # - :unarchive, :id_name, :insert, :move, :archive
74
- # 3. The only update operations that generate tag remaps are `:id` (or `:id_name`) and `:move`.
75
- def update_tags_remap_table(results, stage)
76
- return false if [:unarchive, :archive].include?(stage)
77
- raise "Expecting CommandResults object. Given: #{results.class}" unless results.is_a?(request_results_class)
78
- results.applied.each do |result|
79
- case stage
80
- when :id, :id_name
81
- prev_id, curr_id = result.command_input_data.values_at(:nodeId, :newId)
82
-
83
- unless current_tree.tag?(curr_id)
84
- msg = "Node '#{prev_id}' was updated to '#{curr_id}', "
85
- msg << "but in current structure '#{curr_id}' is not present"
86
- log(:warn) { msg }
87
- end
88
-
89
- tags_remap_table << [[prev_id], [curr_id]]
90
- when :move
91
- node_id, parent_id = result.command_input_data.values_at(:nodeId, :parentId)
92
- prev_node = previous_tree.node(node_id)
93
- curr_node = current_tree.node(node_id)
94
- prev_path = prev_node.path.reverse
95
- new_path = curr_node.path.reverse
96
-
97
- curr_parent = curr_node.parent.top? ? nil : curr_node.parent
98
- unless curr_parent&.id == parent_id
99
- msg = "Node '#{node_id}' was moved under '#{parent_id}', "
100
- msg << "but in current structure has parent '#{curr_parent&.id}'"
101
- log(:warn) { msg }
102
- end
103
-
104
- tags_remap_table << [prev_path, new_path]
105
- end
106
- end
107
- end
108
-
109
- # Generates the final tags remap file
110
- def generate_tags_remap_csv(filename = "cache/remap_tags.csv")
111
- return nil if tags_remap_table.empty?
112
- timestamp_file(filename).tap do |file|
113
- CSV.open(file, 'w') do |csv|
114
- csv << ["source_tags", "destination_tags"]
115
- tags_remap_table.each do |tags_remap|
116
- csv << tags_remap.to_csv_row
117
- end
118
- end
119
- log(:info) { "Generated file '#{file}'" }
120
- end
121
- end
122
-
123
- # Makes the file relative to the enviro
124
- def timestamp_file(filename, enviro_relative: true)
125
- filename = session.file_manager.dir.file(filename) if enviro_relative
126
- Eco::Data::Files.timestamp_file(filename)
127
- end
128
59
  end
129
60
  end
@@ -0,0 +1,89 @@
1
+ class Eco::API::UseCases::GraphQL::Samples::Location
2
+ module Command::Service
3
+ # Service to generate the command updates.
4
+ module TreeUpdate
5
+ include Eco::API::UseCases::GraphQL::Samples::Location::Service::TreeDiff
6
+ include Eco::API::UseCases::GraphQL::Samples::Location::Command::DSL
7
+ include Eco::API::UseCases::GraphQL::Utils::Sftp
8
+
9
+ # Whether to stop or continue on command fail
10
+ FORCE_CONTINUE = false
11
+
12
+ def process
13
+ super
14
+ ensure
15
+ rescued { re_archive }
16
+ rescued { email_digest('TagTree Update') }
17
+ end
18
+
19
+ # Before closing, run RE-ARCHIVE: those that where unarchived via archivedToken
20
+ # that should remain archived.
21
+ # @note this is an additional necessary step
22
+ def re_archive
23
+ return if simulate?
24
+ stage = :rearchive
25
+
26
+ nodes_diff_class.new(
27
+ hash_list(current_tree),
28
+ file_nodes_list,
29
+ original_tree: current_tree,
30
+ logger: logger
31
+ ).tap do |nodes_diff|
32
+ archive_input = input(nodes_diff.stage_commands(:archive), force_continue: true)
33
+ sliced_batches(
34
+ archive_input,
35
+ desc: stage,
36
+ track_tree_mode: :once
37
+ ) do |sliced_input, response, page, pages, count, total| # rubocop:disable Metrics/ParameterLists
38
+ page_results = request_results_class.new(sliced_input, response)
39
+ (results[stage] ||= []) << page_results
40
+ self.error ||= page_errors?(page_results, page, pages, count, total, stage: stage)
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ # Work with adapted diff builders.
48
+ def nodes_diff_class
49
+ Eco::API::UseCases::GraphQL::Helpers::Location::Command::Diffs
50
+ end
51
+
52
+ def inputs(nodes_diff = comparer, force_continue: force_continue?)
53
+ {}.tap do |sequence|
54
+ nodes_diff.commands do |comms, stage|
55
+ sequence[stage] = input(comms, force_continue: force_continue)
56
+ end
57
+ end.tap do |sequence|
58
+ sequence.each do |stage, input|
59
+ yield(input, stage) if block_given?
60
+ end
61
+ end
62
+ end
63
+
64
+ # Generates the file and pushes to the SFTP folder
65
+ # @note this method can only work if we can run cummulative dry-runs to the back-end.
66
+ # This is only possible using a draft, which is not that desired.
67
+ # @note the SFTP push only happens if `remote_subfolder` is defined, via:
68
+ # 1. `options.dig(:sftp, :remote_subfolder)`
69
+ # 2. `REMOTE_FOLDER` const
70
+ def close_handling_tags_remap_csv
71
+ return false unless super
72
+ upload(tags_remap_csv_file) unless remote_subfolder.nil?
73
+ true
74
+ end
75
+
76
+ def email_digest(title)
77
+ return if simulate?
78
+ digest_msgs = logger.cache.logs(level: %i[info error warn])
79
+ exception = exception ? " - Exception!" : ''
80
+ subject = "#{config.active_enviro} - #{title}#{exception}"
81
+ session.mail(subject: subject, body: digest_msgs.join)
82
+ end
83
+
84
+ def print_diff_details?
85
+ false
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,6 @@
1
+ require_relative 'service/tree_update'
2
+
3
+ class Eco::API::UseCases::GraphQL::Samples::Location
4
+ module Command::Service
5
+ end
6
+ end
@@ -0,0 +1,89 @@
1
+ class Eco::API::UseCases::GraphQL::Samples::Location
2
+ # Logic to: Create tags remap csv table batch design
3
+ module Command::TrackChangedIds
4
+ include Eco::API::UseCases::GraphQL::Helpers::Base::CaseEnv
5
+
6
+ attr_accessor :tags_remap_csv_file
7
+
8
+ REMAP_LOC_IDS_FOLDER = 'cache'.freeze
9
+ REMAP_LOC_IDS_FILENAME = 'remap_loc_ids.csv'.freeze
10
+
11
+ def tags_remap_csv_full_filename
12
+ folder = self.class::REMAP_LOC_IDS_FOLDER
13
+ filename = self.class::REMAP_LOC_IDS_FILENAME
14
+ File.join(folder, filename)
15
+ end
16
+
17
+ def tags_remap_class
18
+ Eco::API::UseCases::GraphQL::Helpers::Location::TagsRemap
19
+ end
20
+
21
+ # The maps of tags to be used in batch remap tags
22
+ # @return [Array<Array>] source/destination pairs of `Array<String>`
23
+ def tags_remap_table
24
+ @tags_remap_table ||= tags_remap_class.new
25
+ end
26
+
27
+ # Generates the file
28
+ # @note this method can only work if we can run cummulative dry-runs to the back-end.
29
+ # This is only possible using a draft, which is not that desired.
30
+ def close_handling_tags_remap_csv
31
+ return false if simulate?
32
+ if tags_remap_table.any?
33
+ puts "REMAP LOC IDs CSV (content):"
34
+ puts tags_remap_table
35
+ true
36
+ else
37
+ log(:info) { "Remap location ids NOT needed :)" }
38
+ false
39
+ end
40
+ end
41
+
42
+ # Based on commands that succeded, and the batch stage, it tracks
43
+ # the tag remaps that should be batches against existing pages
44
+ # @note The only update operation that generate tag remaps
45
+ # is `:id` (or `:id_name`).
46
+ # @return [Boolean] whether new maps were inserted to the tracking table
47
+ def update_tags_remap_table(results, stage, ref_tree = nil)
48
+ return false unless %i[id id_name].include?(stage)
49
+
50
+ msg = "Expecting CommandResults object. Given: #{results.class}"
51
+ raise msg unless results.is_a?(request_results_class)
52
+
53
+ results.applied.each do |result|
54
+ prev_id, new_id = result.command_input_data.values_at(:nodeId, :newId)
55
+ next if new_id.nil? # not an id change
56
+ next if prev_id == new_id
57
+
58
+ tags_remap_table << [[prev_id], [new_id]]
59
+
60
+ next unless ref_tree.is_a?(Eco::API::Organization::TagTree)
61
+ next unless ref_tree.tag?(new_id)
62
+
63
+ msg = "Node '#{prev_id}' was updated to '#{new_id}', "
64
+ msg << "but in current structure '#{new_id}' is not present"
65
+ log(:warn) { msg }
66
+ end
67
+ end
68
+
69
+ # Generates the final tags remap file
70
+ def generate_tags_remap_csv(filename = tags_remap_csv_full_filename)
71
+ return nil if tags_remap_table.empty?
72
+ timestamp_file(filename).tap do |file|
73
+ CSV.open(file, 'w') do |csv|
74
+ csv << %w[prev_node_ids new_node_ids]
75
+ tags_remap_table.each do |tags_remap|
76
+ csv << tags_remap.to_csv_row
77
+ end
78
+ end
79
+ log(:info) { "Generated file '#{file}'" }
80
+ end
81
+ end
82
+
83
+ # Makes the file relative to the enviro
84
+ def timestamp_file(filename, enviro_relative: true)
85
+ filename = session.file_manager.dir.file(filename) if enviro_relative
86
+ Eco::Data::Files.timestamp_file(filename)
87
+ end
88
+ end
89
+ end
@@ -4,7 +4,10 @@ module Eco::API::UseCases::GraphQL::Samples
4
4
  name "location-command"
5
5
 
6
6
  require_relative 'command/results'
7
+ require_relative 'command/track_changed_ids'
7
8
  require_relative 'command/dsl'
8
9
  include Eco::API::UseCases::GraphQL::Samples::Location::Command::DSL
9
10
  end
10
11
  end
12
+
13
+ require_relative 'command/service'
@@ -0,0 +1,9 @@
1
+ module Eco::API::UseCases::GraphQL::Samples
2
+ module Location::Service
3
+ # Base class to create service classes that work like a use case
4
+ class Base
5
+ include Eco::API::UseCases::GraphQL::Samples::Location::DSL
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
2
+ module TreeDiff
3
+ module Convertible
4
+ # Converting headers
5
+ module Heading
6
+ # Define the maps src -> dst heading name
7
+ # @example {'parent_id' => 'parentId' }
8
+ HEADER_MAPS = {}.freeze
9
+
10
+ private
11
+
12
+ def header_maps
13
+ self.class::HEADER_MAPS
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,53 @@
1
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
2
+ module TreeDiff
3
+ module Convertible
4
+ module Inputable
5
+ class << self
6
+ def included(base)
7
+ super(base)
8
+ base.send :include, Eco::Data::Files
9
+ end
10
+ end
11
+
12
+ include Eco::API::UseCases::GraphQL::Helpers::Base::CaseEnv
13
+
14
+ IN_FILENAME = /requested_tree\.csv/.freeze
15
+ IN_FOLDER = 'sftp'.freeze
16
+
17
+ private
18
+
19
+ def input_encoding
20
+ options.dig(:input, :file, :encoding) || 'utf-8'
21
+ end
22
+
23
+ def input_file
24
+ @input_file ||= (options.dig(:input, :file, :name) || newest_file).tap do |file|
25
+ if file
26
+ log(:info) { "Using input file '#{file}'" }
27
+ else
28
+ log(:warn) { "Could not find any input file" }
29
+ exit(1)
30
+ end
31
+ end
32
+ end
33
+
34
+ def newest_file
35
+ @newest_file ||= csv_files.last
36
+ end
37
+
38
+ #@note via Eco::Data::Files
39
+ def csv_files
40
+ self.class.csv_files(input_folder, regexp: input_file_pattern)
41
+ end
42
+
43
+ def input_file_pattern
44
+ self.class::IN_FILENAME
45
+ end
46
+
47
+ def input_folder
48
+ "#{config.active_enviro}/#{self.class::IN_FOLDER}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,34 @@
1
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
2
+ module TreeDiff
3
+ module Convertible
4
+ module Parsing
5
+ module Classifications
6
+ include Helpers
7
+
8
+ # Input classification values into actual
9
+ # classification values
10
+ CLASSIFICATION_MAPS = {}.freeze
11
+
12
+ private
13
+
14
+ def transform_classifications(row)
15
+ return row if node_classifications_maping.empty?
16
+ row['classifications'] = into_a(row['classifications']).map do |type|
17
+ node_classifications_map(type)
18
+ end.join('|')
19
+ end
20
+
21
+ # Helper to map classifications
22
+ def node_classifications_map(value)
23
+ return value unless node_classifications_maping.key?(value)
24
+ node_classifications_maping[value]
25
+ end
26
+
27
+ def node_classifications_maping
28
+ self.class::CLASSIFICATION_MAPS
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
2
+ module TreeDiff
3
+ module Convertible
4
+ module Parsing
5
+ module Helpers
6
+ private
7
+
8
+ def as_boolean(value)
9
+ return false if value.nil? || value == false
10
+ return true if value == true
11
+ return false if value.to_s.strip.empty?
12
+ return true if %w[yes x true].include?(value.downcase)
13
+ false
14
+ end
15
+
16
+ # Helper to convert to array
17
+ def into_a(value)
18
+ if value.is_a?(String)
19
+ value.split('|')
20
+ else
21
+ [value].flatten
22
+ end.compact
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ require_relative 'parsing/helpers'
2
+ require_relative 'parsing/classifications'
3
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
4
+ module TreeDiff
5
+ module Convertible
6
+ # Helpers for transform
7
+ module Parsing
8
+ include Helpers
9
+ include Classifications
10
+
11
+ private
12
+
13
+ # Custom callback to some required convertions to the input file
14
+ # provided that it fits to the required input format.
15
+ def transform_input_csv(csv)
16
+ row_transform = custom_input_row_transform_block
17
+ csv_transform = custom_input_csv_transform_block
18
+
19
+ csv = csv_transform.call(csv) if csv_transform
20
+
21
+ msg = "Expecting Eco::CSV::Table (i.e. from 'custom_input_csv_transform')."
22
+ msg << "Given: #{csv.class}"
23
+ raise ArgumentError, msg unless csv.is_a?(Eco::CSV::Table)
24
+
25
+ csv.each do |row|
26
+ row_transform&.call(row)
27
+ transform_classifications(row)
28
+ end
29
+ csv
30
+ end
31
+
32
+ # The user define block for row transformation
33
+ def custom_input_row_transform_block
34
+ return nil unless respond_to?(:custom_input_row_transform, true)
35
+ method(:custom_input_row_transform)
36
+ end
37
+
38
+ # The user define block for row transformation
39
+ def custom_input_csv_transform_block
40
+ return nil unless respond_to?(:custom_input_csv_transform, true)
41
+ method(:custom_input_csv_transform)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'convertible/heading'
2
+ require_relative 'convertible/parsing'
3
+ require_relative 'convertible/inputable'
4
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
5
+ module TreeDiff
6
+ # Offers a way to convert the values and keys/headers
7
+ # of the input csv file/rows
8
+ module Convertible
9
+ class << self
10
+ def included(base)
11
+ super(base)
12
+ base.send :include, Inputable
13
+ end
14
+ end
15
+
16
+ include Parsing
17
+ include Heading
18
+
19
+ private
20
+
21
+ def input_csv
22
+ @input_csv ||= Eco::CSV.read(input_file, encoding: input_encoding).then do |csv|
23
+ next csv unless header_maps&.any?
24
+
25
+ csv.transform_headers do |name|
26
+ next name unless header_maps.key?(name)
27
+ header_maps[name]
28
+ end
29
+ end.then do |csv|
30
+ transform_input_csv(csv).tap do |res|
31
+ next if res.is_a?(Eco::CSV::Table)
32
+ raise ArgumentError, "Expecting and Eco::CSV::Table. Given: #{res.class}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,105 @@
1
+ module Eco::API::UseCases::GraphQL::Samples
2
+ module Location::Service
3
+ # Service to spot the differences between an input file and a locations tree.
4
+ # @example
5
+ # class Custom::UseCase::TagtreeDiff < Eco::API::UseCases::GraphQL::Samples::Location
6
+ # name 'tagtree-diff'
7
+ # type :other
8
+
9
+ # require_relative 'cli/10_tagtree_diff_cli'
10
+
11
+ # include Eco::API::UseCases::GraphQL::Samples::Location::Service::TreeDiff
12
+
13
+ # IN_FILENAME = /requested_tree\.csv/.freeze
14
+ # IN_FOLDER = 'sftp'.freeze
15
+ # HEADER_MAPS = {
16
+ # 'Code' => 'id',
17
+ # 'Description' => 'name',
18
+ # 'ParentCode' => 'parent_id',
19
+ # 'IsActive' => 'active',
20
+ # 'LevelDescription' => 'classifications'
21
+ # }.freeze
22
+ # CLASSIFICATION_MAPS = {
23
+ # 'Directorate' => 'agency',
24
+ # 'Subsection' => 'sub-section',
25
+ # 'WorkUnit' => 'work-unit'
26
+ # }.freeze
27
+ #
28
+ # def process
29
+ # compare
30
+ # end
31
+ #
32
+ # private
33
+ #
34
+ # def custom_input_csv_transform(csv)
35
+ # csv.add_column('archived')
36
+ # end
37
+ #
38
+ # def custom_input_row_transform(row)
39
+ # row['archived'] = !as_boolean(row['active'])
40
+ # end
41
+ # end
42
+ module TreeDiff
43
+ include Eco::API::UseCases::GraphQL::Samples::Location::Service::TreeToList
44
+
45
+ require_relative 'tree_diff/convertible'
46
+ include Convertible
47
+
48
+ def process
49
+ compare
50
+ end
51
+
52
+ def compare
53
+ comparer.tap do |cmp|
54
+ puts comparer.diffs_details if print_diff_details? && cmp.diffs?
55
+ log(:info) { cmp.diffs_summary }
56
+ sleep(5)
57
+ end
58
+ end
59
+
60
+ def comparer(source_1 = live_nodes_list, source_2 = file_nodes_list)
61
+ @comparer ||= nodes_diff_class.new(
62
+ source_1,
63
+ source_2,
64
+ original_tree: input_tagtree,
65
+ logger: logger
66
+ ).tap do
67
+ log(:info) {
68
+ "Comparing #{source_1.count} nodes with #{source_2.count} file nodes."
69
+ }
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def nodes_diff_class
76
+ Eco::Data::Locations::NodeDiff::NodesDiff
77
+ end
78
+
79
+ def print_diff_details?
80
+ true
81
+ end
82
+
83
+ def generate_live_nodes_file?
84
+ false
85
+ end
86
+
87
+ def live_nodes_list
88
+ @live_nodes_list ||= as_nodes_json(input_tagtree).tap do |list|
89
+ log(:info) { "Converted live tree to list of #{list.count} hash-nodes" }
90
+ end
91
+ end
92
+
93
+ # We accept csv input as a `:tree` or as `:nodes`
94
+ # @note
95
+ # 1. uses custom converter inherited from base case '01_tatree_to_list_case'
96
+ # - `as_nodes_json`
97
+ # 2. `org_tree` is native from `Eco::Data::Locations::NodeBase::CsvConvert`
98
+ def file_nodes_list
99
+ @file_nodes_list ||= as_nodes_json(org_tree(input_csv)).tap do |list|
100
+ log(:info) { "Converted input csv file to list of #{list.count} hash-nodes" }
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,16 @@
1
+ module Eco::API::UseCases::GraphQL::Samples::Location::Service
2
+ module TreeToList
3
+ module Converter
4
+ module Discarded
5
+ # List of discarded node ids
6
+ DISCARDED_NODES = [].freeze
7
+
8
+ private
9
+
10
+ def discarded?(tag)
11
+ self.class::DISCARDED_NODES.include?(tag)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end