eco-helpers 2.7.11 → 2.7.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -4
  3. data/Gemfile +2 -0
  4. data/eco-helpers.gemspec +17 -15
  5. data/lib/eco/api/common/session/logger.rb +12 -8
  6. data/lib/eco/api/session/batch/jobs.rb +10 -9
  7. data/lib/eco/api/usecases/default/people/{clean_unknown_tags_case.rb → amend/clean_unknown_tags_case.rb} +2 -2
  8. data/lib/eco/api/usecases/default/people/{clear_abilities_case.rb → amend/clear_abilities_case.rb} +2 -2
  9. data/lib/eco/api/usecases/default/people/{refresh_case.rb → amend/refresh_case.rb} +1 -1
  10. data/lib/eco/api/usecases/default/people/amend/reinvite_sync_case.rb +11 -0
  11. data/lib/eco/api/usecases/default/people/{reinvite_trans_case.rb → amend/reinvite_trans_case.rb} +2 -2
  12. data/lib/eco/api/usecases/default/people/amend/reinvite_trans_cli.rb +4 -0
  13. data/lib/eco/api/usecases/default/people/{restore_db_case.rb → amend/restore_db_case.rb} +1 -1
  14. data/lib/eco/api/usecases/default/people/amend.rb +11 -0
  15. data/lib/eco/api/usecases/default/people/migrate/cli/remap_tags_cli.rb +23 -0
  16. data/lib/eco/api/usecases/default/people/migrate/remap_tags_case.rb +269 -0
  17. data/lib/eco/api/usecases/default/people/migrate.rb +6 -0
  18. data/lib/eco/api/usecases/default/people/{analyse_people_case.rb → treat/analyse_people_case.rb} +1 -1
  19. data/lib/eco/api/usecases/default/people/{org_data_convert_case.rb → treat/org_data_convert_case.rb} +1 -1
  20. data/lib/eco/api/usecases/default/people/{supers_cyclic_identify_case.rb → treat/supers_cyclic_identify_case.rb} +2 -2
  21. data/lib/eco/api/usecases/default/people/{supers_hierarchy_case.rb → treat/supers_hierarchy_case.rb} +18 -17
  22. data/lib/eco/api/usecases/default/people/treat.rb +9 -0
  23. data/lib/eco/api/usecases/default/people/{change_email_case.rb → utils/change_email_case.rb} +1 -1
  24. data/lib/eco/api/usecases/default/people/{set_default_tag_case.rb → utils/set_default_tag_case.rb} +1 -1
  25. data/lib/eco/api/usecases/default/people/{switch_supervisor_case.rb → utils/switch_supervisor_case.rb} +1 -1
  26. data/lib/eco/api/usecases/default/people/{transfer_account_case.rb → utils/transfer_account_case.rb} +1 -1
  27. data/lib/eco/api/usecases/default/people/utils.rb +9 -0
  28. data/lib/eco/api/usecases/default/people.rb +4 -14
  29. data/lib/eco/api/usecases/default/utils/cli/split_csv_cli.rb +15 -0
  30. data/lib/eco/api/usecases/default/utils/split_csv_case.rb +34 -0
  31. data/lib/eco/api/usecases/default/utils.rb +12 -0
  32. data/lib/eco/api/usecases/default.rb +1 -0
  33. data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +1 -2
  34. data/lib/eco/api/usecases/graphql/samples/location/command/track_changed_ids.rb +3 -3
  35. data/lib/eco/csv/split.rb +114 -0
  36. data/lib/eco/csv/stream.rb +66 -0
  37. data/lib/eco/csv.rb +14 -0
  38. data/lib/eco/language/basic_logger.rb +7 -6
  39. data/lib/eco/version.rb +1 -1
  40. metadata +159 -120
  41. data/lib/eco/api/usecases/default/people/reinvite_sync_case.rb +0 -9
  42. data/lib/eco/api/usecases/default/people/reinvite_trans_cli.rb +0 -4
@@ -1,10 +1,10 @@
1
- class Eco::API::UseCases::Default::People::SupersHierarchy < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::Default::People::Treat::SupersHierarchy < Eco::API::Common::Loaders::UseCase
2
2
  name "supers-hierarchy"
3
3
  type :export
4
4
 
5
5
  attr_reader :people
6
6
 
7
- def main(people, session, options, usecase)
7
+ def main(people, _session, options, _usecase)
8
8
  options[:end_get] = false
9
9
  @people = people
10
10
 
@@ -22,20 +22,19 @@ class Eco::API::UseCases::Default::People::SupersHierarchy < Eco::API::Common::L
22
22
  end
23
23
 
24
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
25
+ ext = File.extname(file).downcase.delete(".")
26
+
27
+ case ext
28
+ when "txt"
29
+ create_file(data, file: file, format: :txt)
30
+ when "html"
31
+ puts "html is still not supported"
32
+ exit(1)
33
+ # create_file(data, file: file, format: :html)
34
+ when "json"
35
+ puts "json is still not supported"
36
+ exit(1)
37
+ # create_file(data, file: file, format: :json)
39
38
  end
40
39
  end
41
40
 
@@ -50,7 +49,9 @@ class Eco::API::UseCases::Default::People::SupersHierarchy < Eco::API::Common::L
50
49
  raise "Required Hash tree structure. Given: #{tree.class}" unless tree.is_a?(Hash)
51
50
  "".tap do |str|
52
51
  tree.each do |entry, subtree|
53
- str << "#{" " * lev}#{(lev > 0)? "+-#{lev}- " : ""}#{entry.name} (#{entry.external_id}|#{entry.email}|#{entry.id})\n"
52
+ str << "#{" " * lev}#{lev.positive? ? "+-#{lev}- " : ""}"
53
+ str << entry.name
54
+ str << " (#{entry.external_id}|#{entry.email}|#{entry.id})\n"
54
55
  str << tree_to_str(subtree, lev: lev + 1, format: format) unless !subtree || subtree.empty?
55
56
  end
56
57
  end
@@ -0,0 +1,9 @@
1
+ module Eco::API::UseCases::Default::People
2
+ module Treat
3
+ end
4
+ end
5
+
6
+ require_relative 'treat/analyse_people_case'
7
+ require_relative 'treat/supers_hierarchy_case'
8
+ require_relative 'treat/supers_cyclic_identify_case'
9
+ require_relative 'treat/org_data_convert_case'
@@ -1,4 +1,4 @@
1
- class Eco::API::UseCases::Default::People::ChangeEMailCase < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::Default::People::Utils::ChangeEMailCase < Eco::API::Common::Loaders::UseCase
2
2
  name "change-email"
3
3
  type :sync
4
4
 
@@ -1,4 +1,4 @@
1
- class Eco::API::UseCases::Default::People::SetDefaultTagCase < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::Default::People::Utils::SetDefaultTagCase < Eco::API::Common::Loaders::UseCase
2
2
  name "set-default-tag"
3
3
  type :transform
4
4
 
@@ -1,4 +1,4 @@
1
- class Eco::API::UseCases::Default::People::SwitchSupervisorCase < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::Default::People::Utils::SwitchSupervisorCase < Eco::API::Common::Loaders::UseCase
2
2
  name "switch-supervisor"
3
3
  type :transform
4
4
 
@@ -1,4 +1,4 @@
1
- class Eco::API::UseCases::Default::People::TransferAccountCase < Eco::API::Common::Loaders::UseCase
1
+ class Eco::API::UseCases::Default::People::Utils::TransferAccountCase < Eco::API::Common::Loaders::UseCase
2
2
  name "transfer-account"
3
3
  type :sync
4
4
 
@@ -0,0 +1,9 @@
1
+ module Eco::API::UseCases::Default::People
2
+ module Utils
3
+ end
4
+ end
5
+
6
+ require_relative 'utils/change_email_case'
7
+ require_relative 'utils/set_default_tag_case'
8
+ require_relative 'utils/switch_supervisor_case'
9
+ require_relative 'utils/transfer_account_case'
@@ -9,17 +9,7 @@ module Eco
9
9
  end
10
10
  end
11
11
 
12
- require_relative 'people/analyse_people_case'
13
- require_relative 'people/change_email_case'
14
- require_relative 'people/clean_unknown_tags_case'
15
- require_relative 'people/clear_abilities_case'
16
- require_relative 'people/reinvite_trans_case'
17
- require_relative 'people/reinvite_sync_case'
18
- require_relative 'people/org_data_convert_case'
19
- require_relative 'people/refresh_case'
20
- require_relative 'people/restore_db_case'
21
- require_relative 'people/set_default_tag_case'
22
- require_relative 'people/supers_hierarchy_case'
23
- require_relative 'people/supers_cyclic_identify_case'
24
- require_relative 'people/switch_supervisor_case'
25
- require_relative 'people/transfer_account_case'
12
+ require_relative 'people/treat'
13
+ require_relative 'people/utils'
14
+ require_relative 'people/amend'
15
+ require_relative 'people/migrate'
@@ -0,0 +1,15 @@
1
+ class Eco::API::UseCases::Default::People::Utils::SplitCsv
2
+ class Cli < Eco::API::UseCases::Cli
3
+ desc "Splits an input file into multiple ones"
4
+
5
+ callback do |_sess, options, _case|
6
+ file = SCR.get_file(cli_name, required: true, should_exist: true)
7
+ options.deep_merge!(source: {file: file})
8
+ end
9
+
10
+ add_option("-max-rows", "The max count of rows of the output files") do |options|
11
+ count = SCR.get_arg("-max-rows", with_param: true)
12
+ options.deep_merge!(output: {file: {max_rows: count}})
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ class Eco::API::UseCases::Default::People::Utils::SplitCsv < Eco::API::Common::Loaders::UseCase
2
+ require_relative 'cli/split_csv_cli'
3
+
4
+ MAX_ROWS = 15_000
5
+
6
+ name "split-csv"
7
+ type :other
8
+
9
+ def main(*_args)
10
+ Eco::CSV.split(input_file, max_rows: max_rows).each do |file|
11
+ log(:info) {
12
+ "Generated file '#{file}'"
13
+ }
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def input_file
20
+ options.dig(:source, :file)
21
+ end
22
+
23
+ def max_rows
24
+ max_rows_options || self.class::MAX_ROWS
25
+ end
26
+
27
+ def max_rows_options
28
+ return nil unless (num = options.dig(:output, :file, :max_rows))
29
+
30
+ num = num.to_i
31
+ num = nil if num.zero?
32
+ num
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class Default
5
+ module Utils
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require_relative 'utils/split_csv_case'
@@ -14,3 +14,4 @@ end
14
14
 
15
15
  require_relative 'default/people'
16
16
  require_relative 'default/locations'
17
+ require_relative 'default/utils'
@@ -69,8 +69,7 @@ class Eco::API::UseCases::GraphQL::Samples::Location
69
69
  end
70
70
 
71
71
  # Generates the file and pushes to the SFTP folder
72
- # @note this method can only work if we can run cummulative dry-runs to the back-end.
73
- # This is only possible using a draft, which is not that desired.
72
+ # @note it also displays the mappings on screen
74
73
  # @note the SFTP push only happens if `remote_subfolder` is defined, via:
75
74
  # 1. `options.dig(:sftp, :remote_subfolder)`
76
75
  # 2. `REMOTE_FOLDER` const
@@ -25,10 +25,10 @@ class Eco::API::UseCases::GraphQL::Samples::Location
25
25
  end
26
26
 
27
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.
28
+ # @note this method used to only work if we could run cummulative dry-runs to the back-end.
29
+ # However, after RS P3, as mappings are one-to-one (not many-to-many per row),
30
+ # we can just display the mappings in dry-run as well.
30
31
  def close_handling_tags_remap_csv
31
- return false if simulate?
32
32
  if tags_remap_table.any?
33
33
  puts "REMAP LOC IDs CSV (content):"
34
34
  puts tags_remap_table
@@ -0,0 +1,114 @@
1
+ module Eco
2
+ class CSV
3
+ class Split
4
+ include Eco::Language::AuxiliarLogger
5
+
6
+ attr_reader :filename
7
+
8
+ def initialize(filename, max_rows:, **kargs)
9
+ raise ArgumentError, "File '#{filename}' does not exist" unless ::File.exist?(filename)
10
+ @filename = filename
11
+ @max_rows = max_rows
12
+ @params = kargs
13
+ init
14
+ end
15
+
16
+ # @yield [idx, file] a block to spot the filename
17
+ # @yieldparam idx [Integer] the number of the file
18
+ # @yieldparam file [String] the default name of the file
19
+ # @yieldreturn [String] the filename of the file `idx`.
20
+ # - If `nil` it will create its own filename convention
21
+ # @return [Array<String>] names of the generated files
22
+ def call(&block)
23
+ stream.for_each do |row, ridx|
24
+ copy_row(row, ridx, &block)
25
+ end
26
+ out_files
27
+ ensure
28
+ puts "Close at row #{row_idx}"
29
+ @csv&.close
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :params
35
+ attr_reader :idx, :max_rows
36
+ attr_reader :headers, :row_idx
37
+
38
+ attr_accessor :exception
39
+
40
+ def copy_row(row, ridx, &block)
41
+ @headers ||= row.headers
42
+ @row_idx = ridx
43
+ current_csv(ridx, &block) << row.fields
44
+ end
45
+
46
+ def current_csv(ridx)
47
+ if split?(ridx) || @csv.nil?
48
+ puts "Split at row #{row_idx}"
49
+ @csv&.close
50
+ out_filename = generate_name(nidx = next_idx)
51
+ out_filename = yield(nidx, out_filename) if block_given?
52
+ @csv = ::CSV.open(out_filename, "w")
53
+ @csv << headers
54
+ out_files << out_filename
55
+ end
56
+ @csv
57
+ end
58
+
59
+ def split?(ridx)
60
+ ((ridx + 1) % max_rows).zero?
61
+ end
62
+
63
+ def next_idx
64
+ idx.tap { @idx += 1 }
65
+ end
66
+
67
+ def init
68
+ @idx ||= 0 # rubocop:disable Naming/MemoizedInstanceVariableName
69
+ end
70
+
71
+ def stream
72
+ @stream ||= Eco::CSV::Stream.new(filename, **params)
73
+ end
74
+
75
+ def generate_name(fidx)
76
+ File.join(input_dir, "#{input_name}_#{file_number(fidx)}#{input_ext}")
77
+ end
78
+
79
+ def file_number(num)
80
+ "#{zeroed}#{num}"[-5..]
81
+ end
82
+
83
+ def zeroed
84
+ "0" * 5
85
+ end
86
+
87
+ def out_files
88
+ @out_files ||= []
89
+ end
90
+
91
+ def input_name
92
+ @input_name ||= File.basename(input_basename, input_ext)
93
+ end
94
+
95
+ def input_ext
96
+ @input_ext ||= input_basename.split('.')[1..].join('.').then do |name|
97
+ ".#{name}"
98
+ end
99
+ end
100
+
101
+ def input_basename
102
+ @input_basename ||= File.basename(input_full_filename)
103
+ end
104
+
105
+ def input_dir
106
+ @input_dir = File.dirname(input_full_filename)
107
+ end
108
+
109
+ def input_full_filename
110
+ @input_full_filename ||= File.expand_path(filename)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,66 @@
1
+ module Eco
2
+ class CSV
3
+ class Stream
4
+ include Eco::Language::AuxiliarLogger
5
+
6
+ attr_reader :filename
7
+
8
+ def initialize(filename, **kargs)
9
+ raise ArgumentError, "File '#{filename}' does not exist" unless ::File.exist?(filename)
10
+ @filename = filename
11
+ @params = {
12
+ headers: true,
13
+ skip_blanks: true
14
+ }.merge(kargs)
15
+ init
16
+ end
17
+
18
+ def for_each(start_at_idx: 0)
19
+ raise ArgumentError, 'Expecting block, but not given.' unless block_given?
20
+
21
+ move_to_idx(start_at_idx)
22
+
23
+ yield(row, next_idx) while (self.row = csv.shift)
24
+ rescue StandardError => err
25
+ self.exception = err
26
+ raise
27
+ ensure
28
+ (fd.close; @fd = nil) if fd.is_a?(::File) # rubocop:disable Style/Semicolon
29
+ if exception
30
+ # Give some feedback if it crashes
31
+ msg = []
32
+ msg << "Last row IDX: #{idx}"
33
+ msg << "Last row content: #{row.to_h.pretty_inspect}"
34
+ puts msg
35
+ log(:debug) { msg.join("\n") }
36
+ end
37
+ end
38
+
39
+ def move_to_idx(start_at_idx)
40
+ next_idx while (idx < start_at_idx) && (self.row = csv.shift)
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :params
46
+ attr_reader :idx, :fd
47
+
48
+ attr_accessor :row, :exception
49
+
50
+ def next_idx
51
+ idx.tap { @idx += 1 }
52
+ end
53
+
54
+ # see https://dalibornasevic.com/posts/68-processing-large-csv-files-with-ruby
55
+ def csv
56
+ return @csv if instance_variable_defined?(:@csv)
57
+ @fd = ::File.open(filename, 'r')
58
+ @csv = Eco::CSV.new(fd, **params)
59
+ end
60
+
61
+ def init
62
+ @idx ||= 0 # rubocop:disable Naming/MemoizedInstanceVariableName
63
+ end
64
+ end
65
+ end
66
+ end
data/lib/eco/csv.rb CHANGED
@@ -17,8 +17,22 @@ module Eco
17
17
  end
18
18
  parse(get_file_content(file, **params), **kargs)
19
19
  end
20
+
21
+ # @yield [idx, file] a block to spot the filename
22
+ # @yieldparam idx [Integer] the number of the file
23
+ # @yieldparam file [String] the default name of the file
24
+ # @yieldreturn [String] the filename of the file `idx`.
25
+ # - If `nil` it will create its own filename convention
26
+ # @param filename [String] the orignal file
27
+ # @param max_rows [Integer] number of rows per file
28
+ # @see Eco::CSV::Split#call
29
+ def split(filename, max_rows:, **kargs, &block)
30
+ Eco::CSV::Split.new(filename, max_rows: max_rows, **kargs).call(&block)
31
+ end
20
32
  end
21
33
  end
22
34
  end
23
35
 
24
36
  require_relative 'csv/table'
37
+ require_relative 'csv/stream'
38
+ require_relative 'csv/split'
@@ -19,12 +19,12 @@ module Eco
19
19
  attr_writer :timestamp
20
20
  attr_reader :level
21
21
 
22
- forward *LOG_LEVELS, *METHODS
22
+ forward(*LOG_LEVELS, *METHODS)
23
23
 
24
24
  def initialize(level: ::Logger::INFO, timestamp: false)
25
25
  @level = level
26
26
  self.timestamp = timestamp
27
- loggers[:console] = ::Logger.new(STDOUT).tap do |logger|
27
+ loggers[:console] = ::Logger.new($stdout).tap do |logger|
28
28
  logger.formatter = format_proc(console: true)
29
29
  logger.level = level
30
30
  end
@@ -41,7 +41,7 @@ module Eco
41
41
  private
42
42
 
43
43
  def forward(meth, *args, &block)
44
- loggers.each do |_key, logger|
44
+ loggers.each_value do |logger|
45
45
  logger.send(meth, *args, &block)
46
46
  end
47
47
  end
@@ -52,6 +52,7 @@ module Eco
52
52
 
53
53
  def console_timestamp(datetime)
54
54
  return nil unless timestamp?
55
+
55
56
  timestamp(datetime)
56
57
  end
57
58
 
@@ -62,10 +63,10 @@ module Eco
62
63
  end
63
64
 
64
65
  def format_proc(console: true, &block)
65
- proc do |severity, datetime, progname, msg|
66
- str_stamp = console ? console_timestamp(datetime) : timestamp(datetime)
66
+ proc do |severity, datetime, _progname, msg|
67
+ str_stamp = console ? console_timestamp(datetime) : timestamp(datetime)
67
68
  "#{severity.to_s[0]}: #{str_stamp}#{msg}\n".tap do |formatted_msg|
68
- block.call(severity, datetime, msg, formatted_msg) if block
69
+ block&.call(severity, datetime, msg, formatted_msg)
69
70
  end
70
71
  end
71
72
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '2.7.11'.freeze
2
+ VERSION = '2.7.13'.freeze
3
3
  end