eco-helpers 2.0.60 → 2.0.63

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 182922a2146b1fa50b0372253a5279eb7d801c4fabd8fcd5303dd6322091c91c
4
- data.tar.gz: 5f807f72bc3b6fc7a376bbd43d7a10b99cb5144a606ded5f9eb6817b82740788
3
+ metadata.gz: 142581f236e114a66fe53146914b208185f0ea1e0cdca545d26980030a6eaa22
4
+ data.tar.gz: 104ad101a197a54a142578eb7aecc7197606eb4ab84fe68735f870a74d1e3fb0
5
5
  SHA512:
6
- metadata.gz: 40cb65992b4c9524e025b7f7073f699062cd22008202491c593089b662c9b72ac611eb9cfcccfe14a2f62e1d519eb5dad14fef9389b6e2cbee1798ced0baa54f
7
- data.tar.gz: 3e3154fcf629162a1445acbafd96f2d00f8d2a84f77bfb9b2cb68ce6c7f36ed4e8f5fea3cee43e897ac1b50b0210fd14bf9489b0a6708a6bc954093a7b1af3f8
6
+ metadata.gz: 5f8efed96ef4891dbee99fa5edae77bf9afb88d3813cc45f3f6c82adefea70e22dfc384228c88f6c35d66509ef8b4f8a566a54dcb653ef113d38df92dee1bf3e
7
+ data.tar.gz: 1c30c6fba995bdd05a45ae911f655bd8d129d6f2810f09108c1eaad34166183bee23e1c3ad16148ad0c0c3961016cffd6b877e3d5b76718aaa01acc4f84ad874
data/CHANGELOG.md CHANGED
@@ -1,13 +1,57 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [2.0.60] - 2022-06-xx
4
+ ## [2.0.63] - 2022-07-xx
5
5
 
6
6
  ### Added
7
7
  ### Changed
8
+ - `Eco::API::Session::Config::SFTP#remote_folder` to use native path builder
9
+
10
+ ### Fixed
11
+
12
+ ## [2.0.62] - 2022-07-15
13
+
14
+ ### Added
15
+ - SFTP **password** option
16
+ - `Eco::API::Common::Session::Sftp` fetches from config
17
+ - `Eco::API::Session::Config::Sftp#password`
18
+
19
+ ### Changed
20
+ ### Fixed
21
+ - `Eco::API::UseCases::DefaultCases::CreateCase` had a typo
22
+
23
+ ## [2.0.61] - 2022-07-11
24
+
25
+ ### Added
26
+ - patch for `Ecoportal::API::Common::Client#host` exposed `host` property
27
+ - `skip-header-checks` option
28
+ - It prevents checks done in the `Eco::API::Common::People::DefaultParsers::CSVParser`
29
+ - **Export Helpers** to be able to automate exports via `APIv2`
30
+ - `Eco::API::UseCases::OozeSamples::Helpers::ExportableRegister`
31
+ - `Eco::API::UseCases::OozeSamples::Helpers::ExportableOoze`
32
+ - `Eco::API::UseCases::OozeCases::ExportRegisterCase` to export registers
33
+ - First ooze native use case (besides the samples)
34
+
35
+ ### Changed
36
+ - upgraded `ecoportal-api-v2` to version `0.8.30`
37
+
38
+ ### Fixed
39
+ - `-entries-to-csv` case; option `-out` was not being used
40
+ - `Eco::API::Common::People::Entries#export` made it so it creates one column per key
41
+ - It was wrongly merging the entries assuming all of them had the same keys
42
+ - This also fixes the `-entries-to-csv` case, which can be used with `entries-from` option to correctly merge multiple input files with no data loss
43
+ - `Eco::API::UseCases::OozeSamples::RegisterExportCase`
44
+ - On prompt to launch, it answers `Yes`
45
+ - It correctly captures the `state` based on the stages `state`
46
+ - It was not building the model
47
+ - Optimized
48
+ - It returns a `PageStage` (rather than `Page`), to ensure all supported properties are accessible (i.e. `uid`)
49
+
50
+ ## [2.0.60] - 2022-07-01
51
+
8
52
  ### Fixed
9
53
  - `Ecoportal::API::V1::PersonDetails.key?` patched
10
-
54
+
11
55
  ## [2.0.59] - 2022-06-07
12
56
 
13
57
  ### Added
data/eco-helpers.gemspec CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
32
32
 
33
33
  spec.add_dependency 'ecoportal-api', '>= 0.8.5', '< 0.9'
34
- spec.add_dependency 'ecoportal-api-v2', '>= 0.8.28', '< 0.9'
34
+ spec.add_dependency 'ecoportal-api-v2', '>= 0.8.30', '< 0.9'
35
35
  spec.add_dependency 'aws-sdk-s3', '>= 1.83.0', '< 2'
36
36
  spec.add_dependency 'aws-sdk-ses', '>= 1.36.0', '< 2'
37
37
  spec.add_dependency 'dotenv', '>= 2.7.6', '< 2.8'
@@ -3,7 +3,7 @@ class Eco::API::Common::People::DefaultParsers::CSVParser < Eco::API::Common::Lo
3
3
 
4
4
  def parser(data, deps)
5
5
  Eco::CSV.parse(data, headers: true, skip_blanks: true).tap do |table|
6
- check_headers(table) if deps[:check_headers]
6
+ check_headers(table) if deps[:check_headers] && !options.dig(:input, :skip_header_check)
7
7
  end.each_with_object([]) do |row, arr_hash|
8
8
  row_hash = row.headers.uniq.each_with_object({}) do |attr, hash|
9
9
  next if attr.to_s.strip.empty?
@@ -26,6 +26,10 @@ class Eco::API::Common::People::DefaultParsers::CSVParser < Eco::API::Common::Lo
26
26
 
27
27
  private
28
28
 
29
+ def options
30
+ ASSETS.cli.options
31
+ end
32
+
29
33
  def parse_string(value)
30
34
  return nil if value.to_s.empty?
31
35
  return nil if null?(value)
@@ -154,12 +154,13 @@ module Eco
154
154
  # Helper to dump the entries into a CSV
155
155
  # @param filename [String] the destination file
156
156
  def export(filename)
157
+ header = each_with_object([]) do |entry, header|
158
+ header.push(*entry.internal_entry.keys).uniq!
159
+ end
157
160
  CSV.open(filename, "w") do |csv|
158
- entry = self.first
159
- header = entry.internal_entry.keys
160
161
  csv << header
161
162
  self.each do |entry|
162
- csv << entry.internal_entry.values
163
+ csv << entry.internal_entry.values_at(*header)
163
164
  end
164
165
  end
165
166
  end
@@ -16,9 +16,7 @@ module Eco
16
16
  @sftp_session ||= Net::SFTP.start(
17
17
  fetch_host,
18
18
  fetch_user,
19
- keys: fetch_key_files,
20
- keys_only: true,
21
- non_interactive: true
19
+ **session_options
22
20
  )
23
21
  rescue Exception => e
24
22
  msg = "Could not open SFTP session. Possible misconfiguration: #{e}"
@@ -85,6 +83,21 @@ module Eco
85
83
 
86
84
  private
87
85
 
86
+ def session_options
87
+ {
88
+ non_interactive: true
89
+ }.tap do |opts|
90
+ if password?
91
+ opts.merge!({password: fetch_password})
92
+ else
93
+ opts.merge!({
94
+ keys: fetch_key_files,
95
+ keys_only: true
96
+ })
97
+ end
98
+ end
99
+ end
100
+
88
101
  def windows_basename(remote_fullname)
89
102
  parts = remote_fullname.split(/[\\\/]/).map {|node| node.gsub(/[<>:\\\/\|?*]/, '_')}
90
103
  local_fullname = File.join(*parts)
@@ -107,6 +120,14 @@ module Eco
107
120
  config.sftp.user || ENV['SFTP_USERNAME']
108
121
  end
109
122
 
123
+ def password?
124
+ !!fetch_password
125
+ end
126
+
127
+ def fetch_password
128
+ config.sftp.password || ENV['SFTP_PASSWORD']
129
+ end
130
+
110
131
  def fetch_key_files
111
132
  [config.sftp.key_file || ENV['SFTP_KEY_FILE']]
112
133
  end
@@ -0,0 +1,9 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ class Client
5
+ attr_reader :host
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,4 @@
1
+ require_relative 'ecoportal_api/client'
1
2
  require_relative 'ecoportal_api/external_person'
2
3
  require_relative 'ecoportal_api/external_details'
3
4
  require_relative 'ecoportal_api/internal_person'
@@ -5,7 +5,7 @@ module Eco
5
5
  class SFTP < BaseConfig
6
6
 
7
7
  def configured?
8
- required = host && user && key_file
8
+ required = host && user && (key_file || password)
9
9
  !!required
10
10
  end
11
11
 
@@ -25,6 +25,14 @@ module Eco
25
25
  self["user"]
26
26
  end
27
27
 
28
+ def password=(var)
29
+ self["password"] = var
30
+ end
31
+
32
+ def password
33
+ self["password"]
34
+ end
35
+
28
36
  def key_file=(key)
29
37
  self["key_file"] = key
30
38
  end
@@ -54,9 +62,8 @@ module Eco
54
62
  end
55
63
 
56
64
  def remote_folder
57
- base_path + "/" + enviro_subpath
65
+ File.join(*[base_path, enviro_supath].compact)
58
66
  end
59
-
60
67
  end
61
68
  end
62
69
  end
@@ -5,7 +5,7 @@ class Eco::API::UseCases::DefaultCases::CreateCase < Eco::API::Common::Loaders::
5
5
  attr_reader :options
6
6
 
7
7
  def main(entries, people, session, options, usecase)
8
- options = @options
8
+ @options = options
9
9
  micro = session.micro
10
10
  creation = session.new_job("main", "create", :create, usecase)
11
11
  supers = session.new_job("post", "supers", :update, usecase, :core)
@@ -4,6 +4,7 @@ module Eco
4
4
  class DefaultCases < Eco::API::UseCases
5
5
  autoloads_children_of "Eco::API::Common::Loaders::UseCase"
6
6
  autoload_namespace "Eco::API::UseCases::DefaultCases"
7
+ autoload_namespace "Eco::API::UseCases::OozeCases"
7
8
  end
8
9
  end
9
10
  end
@@ -0,0 +1,99 @@
1
+ # Use case to export a register into a CSV
2
+ class Eco::API::UseCases::OozeCases::ExportRegisterCase < Eco::API::UseCases::OozeSamples::RegisterExportCase
3
+ name "export-register"
4
+ type :other
5
+ batch_size 5
6
+
7
+ def main(session, options, usecase)
8
+
9
+ super(session, options, usecase) do
10
+ # Save the File
11
+ CSV.open(filename, "w") do |csv|
12
+ csv << exportable_register.header(refresh: true)
13
+ exportable_register.each(as_values: true) do |values|
14
+ csv << values
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ def process_ooze(ooz)
21
+ exportable_register.add_ooze(ooz)
22
+ exportable_register.header
23
+ end
24
+
25
+ def filters
26
+ [].tap do |fltrs|
27
+ [:any, :all].each {|mode| fltrs << build_tags_filter(mode)}
28
+ [:created_at, :updated_at].each {|key| fltrs << build_range_filter(key)}
29
+ end.compact
30
+ end
31
+
32
+ private
33
+
34
+ def exportable_register
35
+ @exportable_register ||= exportable_register_class.new(**export_options)
36
+ end
37
+
38
+ def exportable_register_class
39
+ Eco::API::UseCases::OozeSamples::Helpers::ExportableRegister
40
+ end
41
+
42
+ def build_tags_filter(mode = :any)
43
+ tags = option_tags(mode)
44
+ return nil if !tags || tags.empty?
45
+ tags_filter(tags, any: mode == :any)
46
+ end
47
+
48
+ def build_range_filter(key = :update_at)
49
+ from = from_date(key); to = to_date(key)
50
+ return nil unless from || to
51
+ date_range_filter(from: from, to: to, key: key)
52
+ end
53
+
54
+ def from_date(key)
55
+ options.dig(:export, :options, :filters, key, :from)
56
+ end
57
+
58
+ def to_date(key)
59
+ options.dig(:export, :options, :filters, key, :to)
60
+ end
61
+
62
+ def option_tags(mode = :any)
63
+ options.dig(:export, :options, :filters, :tags, mode)
64
+ end
65
+
66
+ def export_options
67
+ @export_options ||= {
68
+ delimiter: options_delimiter,
69
+ only_indexed: include_deindexed?,
70
+ only_labeled: include_unnamed?,
71
+ only_with_ref: include_unhashed?
72
+ }
73
+ end
74
+
75
+ def include_unnamed?
76
+ options.dig(:export, :options, :include, :unnamed)
77
+ end
78
+
79
+ def options_delimiter
80
+ options.dig(:export, :options, :delimiter) || "|"
81
+ end
82
+
83
+ def include_deindexed?
84
+ options.dig(:export, :options, :include, :deindexed)
85
+ end
86
+
87
+ def include_unhashed?
88
+ options.dig(:export, :options, :include, :unhashed)
89
+ end
90
+
91
+ def filename
92
+ @filename ||= (options[:file] || options.dig(:export, :file, :name)).tap do |filename|
93
+ unless filename
94
+ session.logger.error("Destination file not specified")
95
+ return false
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,10 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeCases
5
+ end
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative 'ooze_cases/export_register_case'
@@ -0,0 +1,169 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeSamples
5
+ module Helpers
6
+ # Class to ease the export process
7
+ class ExportableOoze
8
+ MERGE_DELIMITER = "#:#"
9
+
10
+ META_FIELDS = {
11
+ "id" => "Internal ID",
12
+ "uid" => "Unique ID",
13
+ "name" => "Name of Page",
14
+ "state" => "State of Page",
15
+ "time_zone" => "Time Zone",
16
+ "created_at" => "Page Created",
17
+ "updated_at" => "Last updated",
18
+ "tags" => "Location Tags"
19
+ }
20
+
21
+ class << self
22
+ def label?(field)
23
+ !label(field).to_s.strip.empty?
24
+ end
25
+
26
+ def label(field, default: nil)
27
+ value = nil
28
+ value ||= field.label.to_s.strip if field.respond_to?(:label)
29
+ value = (!value || value.empty?) ? nil : value
30
+ return value if value || !default
31
+ default || "Unnamed field:"
32
+ end
33
+
34
+ def key_ref_label(field, default: nil)
35
+ "#{field_ref(field)}#{MERGE_DELIMITER}#{label(field, default: default)}"
36
+ end
37
+
38
+ def key_to_label(str)
39
+ return str unless str.include?(MERGE_DELIMITER)
40
+ str.split(MERGE_DELIMITER).last
41
+ end
42
+
43
+ def key_to_ref(str)
44
+ return str unless str.include?(MERGE_DELIMITER)
45
+ ref = str.split(MERGE_DELIMITER).first
46
+ ref.to_s.strip.empty?? nil : ref
47
+ end
48
+
49
+ def indexed?(field)
50
+ !field.deindex
51
+ end
52
+
53
+ def with_ref?(field)
54
+ !field.ref_backend.to_s.strip.empty?
55
+ end
56
+
57
+ def field_ref(field)
58
+ field.ref_backend || field.ref(any_length: true)
59
+ end
60
+ end
61
+
62
+ include Eco::API::UseCases::OozeSamples::Helpers::OozeHandlers
63
+
64
+ attr_reader :ooze
65
+ attr_reader :options
66
+
67
+ def initialize(ooze, **options)
68
+ raise "Expecting Ecoportal::API::V2::Page. Given: #{ooze.class}" unless ooze.is_a?(Ecoportal::API::V2::Page)
69
+ @ooze = ooze
70
+ @options = options.merge({
71
+ delimiter: "\n",
72
+ only_indexed: true,
73
+ only_labeled: true,
74
+ only_with_ref: true
75
+ })
76
+ end
77
+
78
+ def delimiter
79
+ options[:delimiter] || "\n"
80
+ end
81
+
82
+ # It offers an intermediate structure that can be aligned with other oozes
83
+ # @note
84
+ # - This method merges indexed values
85
+ # - It overrides even between fields of different type
86
+ # @param only_indexed: [Boolean]
87
+ # @param only_labeled: [Boolean]
88
+ # @param only_with_ref: [Boolean]
89
+ # @return [Array[Hash]]
90
+ def key_typed_data(**options)
91
+ options.merge!(options)
92
+ meta_fields.tap do |data|
93
+ with_field_section_pairs do |field, section|
94
+ next unless export?(field)
95
+ key = self.class.key_ref_label(field, default: alternative_label(field, section))
96
+ data[key] = merge_values(data[key], to_value(field), klass: field.class, delimiter: delimiter)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Helper to go through fields and sections in the order they appear.
102
+ # @note
103
+ # 1. It prevents duplicated sections
104
+ # @yield [field, section] once per field and section.
105
+ # @yieldparam field [Component] a field.
106
+ # @yieldparam section [Section] the section that holds the field.
107
+ # @return [Array<Array] Ordered `Array` of pairs of field and section thereof.
108
+ def with_field_section_pairs
109
+ sections = []
110
+ ordered_sections.each_with_object([]) do |section, out|
111
+ next if sections.include?(section)
112
+ sections << section
113
+ section.components.each do |field|
114
+ out << [field, section]
115
+ yield(field, section) if block_given?
116
+ end
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def meta_fields
123
+ META_FIELDS.each_with_object({}) do |(attr, name), data|
124
+ data[name] = ooze.respond_to?(attr)? ooze.send(attr).to_s : nil
125
+ end
126
+ end
127
+
128
+ def ordered_sections
129
+ if ooze.stages?
130
+ ooze.stages.ordered.each_with_object([]) do |stage, sections|
131
+ sections.push(*stage.sections).uniq!
132
+ end
133
+ else
134
+ ooze.sections.sort_by.with_index do |sec, index|
135
+ [sec.weight, index]
136
+ end
137
+ end
138
+ end
139
+
140
+ def export?(field, **opts)
141
+ opts = options.merge(opts)
142
+ return false unless field.respond_to?(:to_s)
143
+ return false if opts[:only_indexed] && !self.class.indexed?(field)
144
+ return false if opts[:only_labeled] && !self.class.label?(field)
145
+ return false if opts[:only_with_ref] && !self.class.with_ref?(field)
146
+ true
147
+ end
148
+
149
+ def alternative_label(field, section)
150
+ "#{field.type.upcase}::#{section.heading}"
151
+ end
152
+
153
+ def to_value(field, delimiter: self.delimiter)
154
+ return nil unless field.respond_to?(:to_s)
155
+ return field.to_s unless offers_delimiter?(field.method(:to_s))
156
+ field.to_s(delimiter: delimiter)
157
+ end
158
+
159
+ def offers_delimiter?(method)
160
+ method.parameters.any? do |(type, name)|
161
+ (type == :key) && name == :delimiter
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,72 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeSamples
5
+ module Helpers
6
+ # Class to ease the export process
7
+ class ExportableRegister
8
+
9
+ attr_reader :options
10
+
11
+ include Eco::API::UseCases::OozeSamples::Helpers::OozeHandlers
12
+ include Enumerable
13
+
14
+ def initialize(**options)
15
+ @options = options.merge({
16
+ delimiter: "\n",
17
+ only_indexed: true,
18
+ only_labeled: true,
19
+ only_with_ref: true
20
+ })
21
+ end
22
+
23
+ def add_ooze(ooze)
24
+ ooz = ExportableOoze.new(ooze, **options)
25
+ data = ooz.key_typed_data
26
+ @typed_header = merge_arrays(data.keys, typed_header)
27
+ key_typed_data << data
28
+ end
29
+
30
+ def empty?
31
+ count < 1
32
+ end
33
+
34
+ def each(as_values: true, as_row: false, &block)
35
+ return to_enum(:each, as_row: as_row) unless block
36
+ key_typed_data.each do |ooze_data|
37
+ values = ooze_data.values_at(*typed_header)
38
+ case
39
+ when as_values
40
+ values
41
+ when as_row
42
+ ::CSV::Row.new(values, header)
43
+ else
44
+ header.zip(values)
45
+ end.tap do |out|
46
+ yield(out)
47
+ end
48
+ end
49
+ end
50
+
51
+ def header(refresh: false)
52
+ return @header if instance_variable_defined?(:@header) && !refresh
53
+ @header = typed_header.map do |name|
54
+ ExportableOoze.key_to_label(name)
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def typed_header
61
+ @typed_header ||= []
62
+ end
63
+
64
+ def key_typed_data
65
+ @typed_keyed_data ||= []
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeSamples
5
+ module Helpers
6
+ module Filters
7
+ FILTER_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
8
+
9
+ def tags_filter(tags, any: true, negate: false)
10
+ tags = [tags].flatten.compact
11
+ return nil if tags.empty?
12
+ key, name = field_key_name(:tags)
13
+ {
14
+ "tags": tags,
15
+ "mode": any ? "any" : "all",
16
+ "negate": negate,
17
+ "key": key,
18
+ "name": name,
19
+ "type": "tag_filter"
20
+ }
21
+ end
22
+
23
+ def date_range_filter(from: nil, to: nil, key: :updated_at)
24
+ return nil unless from || to
25
+ key, name = field_key_name(key)
26
+ {
27
+ "relstart": "today",
28
+ "time_zone": "Pacific/Auckland",
29
+ "relative": false,
30
+ "key": key,
31
+ "name": name,
32
+ "type": "date_filter"
33
+ }.tap do |out|
34
+ out.merge!("lbound": to_date_filter(from)) if from
35
+ out.merge!("ubound": to_date_filter(to)) if to
36
+ end
37
+ end
38
+
39
+ def to_date_filter(date)
40
+ daystart(date).utc.strftime(FILTER_TIME_FORMAT)
41
+ end
42
+
43
+ def set_time(date, h, m, s); Time.new(date.year, date.month, date.day, h, m, s); end
44
+ def weeks(num); num * days(7); end
45
+ def days(num); num * 60 * 60 * 24; end
46
+ def today; Date.today.to_time; end
47
+ def sunday(date); date + days(7 - weekday(date)); end
48
+ def midnight(date); set_time(date, 23, 59, 59); end
49
+ def daystart(date); set_time(date, 0, 0, 0); end
50
+ def previous_sunday(date); midnight(sunday(date - weeks(1))); end
51
+ def this_monday(date); set_time(previous_sunday(as_at_date) + days(1), 0, 0, 0); end
52
+
53
+ def field_key_name(value)
54
+ case value
55
+ when :updated_at
56
+ ["updated_at", "Last updated"]
57
+ when :created_at
58
+ ["created_at", "Page created"]
59
+ when Ecoportal::API::V2::Page::Component
60
+ [value.ref_backend, value.label]
61
+ when :tags
62
+ ["tags", "Location Tags"]
63
+ else
64
+ [nil , nil]
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,85 @@
1
+ module Eco
2
+ module API
3
+ class UseCases
4
+ class OozeSamples
5
+ module Helpers
6
+ module OozeHandlers
7
+ def merge_values(origin, append, klass: nil, delimiter: "\n")
8
+ return origin if !append || append.to_s.strip.empty?
9
+ return append if !origin || origin.to_s.strip.empty?
10
+ case klass
11
+ when Ecoportal::API::V2::Page::Component::RichTextField
12
+ merge_values(origin, append, delimiter: "\n")
13
+ when Ecoportal::API::V2::Page::Component::PlainTextField
14
+ merge_values(origin, append, delimiter: "\n")
15
+ when Ecoportal::API::V2::Page::Component::SelectionField
16
+ merge_values(origin, append, delimiter: delimiter)
17
+ when Ecoportal::API::V2::Page::Component::ReferenceField
18
+ merge_values(origin, append, delimiter: delimiter)
19
+ when Ecoportal::API::V2::Page::Component::PeopleField
20
+ merge_values(origin, append, delimiter: delimiter)
21
+ when Ecoportal::API::V2::Page::Component::DateField
22
+ origin
23
+ when Ecoportal::API::V2::Page::Component::NumberField
24
+ origin
25
+ when Ecoportal::API::V2::Page::Component::GaugeField
26
+ origin
27
+ when Ecoportal::API::V2::Page::Component::ChecklistField
28
+ merge_values(origin, append, delimiter: delimiter)
29
+ when Ecoportal::API::V2::Page::Component::ActionField
30
+ merge_values(origin, append, delimiter: delimiter)
31
+ when Ecoportal::API::V2::Page::Component::FilesField
32
+ merge_values(origin, append, delimiter: delimiter)
33
+ when Ecoportal::API::V2::Page::Component::ImagesField
34
+ merge_values(origin, append, delimiter: delimiter)
35
+ when Ecoportal::API::V2::Page::Component::GeoField
36
+ merge_values(origin, append, delimiter: delimiter)
37
+ when Ecoportal::API::V2::Page::Component::LawField
38
+ merge_values(origin, append, delimiter: delimiter)
39
+ else
40
+ [origin, append].join(delimiter)
41
+ end
42
+ end
43
+
44
+ def merge_arrays(ref, plus)
45
+ return ref if ref == plus
46
+ href_idx = array_indexes(ref)
47
+ hplus_idx = array_indexes(plus)
48
+
49
+ shared = ref & plus
50
+ hshared_ref_idx = href_idx.slice(*shared)
51
+
52
+ # hidx_plus_shared = hplus_idx.slice(*shared).each_with_object({}) do |(e, idx), reversed|
53
+ # reversed[idx] = e
54
+ # end
55
+ # shared_plus_idxs = hidx_plus_shared.keys.reverse
56
+ shared_plus_idxs = hplus_idx.values_at(*shared).sort.reverse
57
+
58
+ only_plus = plus - ref
59
+ honly_plus_idx = hplus_idx.slice(*only_plus)
60
+
61
+ hplus_ref_idx = honly_plus_idx.each_with_object({}) do |(e, idx), hplus_ref_idx|
62
+ ps_idx = shared_plus_idxs.bsearch {|i| idx >= i}
63
+ rs_idx = ps_idx ? hshared_ref_idx[plus[ps_idx]] : -1
64
+ hplus_ref_idx[e] = rs_idx
65
+ end.group_by do |e, idx|
66
+ idx
67
+ end.to_a.sort_by do |(idx, pairs)|
68
+ idx
69
+ end.reverse.to_h.transform_values do |pairs|
70
+ pairs.map(&:first)
71
+ end
72
+ hplus_ref_idx.each_with_object(ref.dup) do |(idx, elements), ref|
73
+ ref.insert(idx+1, *elements)
74
+ end
75
+ end
76
+
77
+ def array_indexes(ary)
78
+ ary.each_with_index.to_h
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -1,4 +1,5 @@
1
- require_relative 'helpers/shortcuts.rb'
1
+ require_relative 'helpers/shortcuts'
2
+ require_relative 'helpers/filters'
2
3
 
3
4
  module Eco
4
5
  module API
@@ -6,8 +7,13 @@ module Eco
6
7
  class OozeSamples
7
8
  module Helpers
8
9
  include OozeSamples::Helpers::Shortcuts
10
+ include OozeSamples::Helpers::Filters
9
11
  end
10
12
  end
11
13
  end
12
14
  end
13
15
  end
16
+
17
+ require_relative 'helpers/ooze_handlers'
18
+ require_relative 'helpers/exportable_ooze'
19
+ require_relative 'helpers/exportable_register'
@@ -1,4 +1,4 @@
1
- # Use case to update a register
1
+ # Use case to offer the basics to export a register
2
2
  # @note
3
3
  # - You can define methods `filters` and `search` to change the target entries of the register
4
4
  # - You need to define the `process_ooze` method
@@ -62,34 +62,35 @@ class Eco::API::UseCases::OozeSamples::RegisterExportCase < Eco::API::Common::Lo
62
62
  def build_full_ooze(ooze_id)
63
63
  if page = ooze(ooze_id)
64
64
  return page unless page.is_a?(Ecoportal::API::V2::Pages::PageStage)
65
+ pending_stage_ids = page.stages.ordered.map(&:id) - [page.current_stage_id]
66
+ state = page.state
65
67
  secs_doc = page.sections.doc
66
68
  flds_doc = page.components.doc
67
- pending_stage_ids = page.stages.map(&:id) - [page.current_stage_id]
69
+ hsecs = secs_doc.each_with_object({}) {|sec, h| h[sec["id"]] = sec}
70
+ hflds = flds_doc.each_with_object({}) {|fld, h| h[fld["id"]] = fld}
68
71
  pending_stage_ids.each do |id|
69
- if page = stage(id, ooze: page)
70
- page.sections.doc.each do |sec_doc|
71
- unless secs_doc.find {|sec| sec["id"] == sec_doc["id"]}
72
+ if other_stage = stage(id, ooze: page)
73
+ state = "inprogress" unless other_stage.state == "complete"
74
+ other_stage.sections.doc.each do |sec_doc|
75
+ unless hsecs.key?(id = sec_doc["id"])
76
+ hsecs[id] = sec_doc
72
77
  secs_doc << sec_doc
73
78
  end
74
79
  end
75
- page.components.doc.each do |comp_doc|
76
- unless flds_doc.find {|fld| fld["id"] == comp_doc["id"]}
80
+ other_stage.components.doc.each do |comp_doc|
81
+ unless hflds.key?(id = comp_doc["id"])
82
+ hflds[id] = comp_doc
77
83
  flds_doc << comp_doc
78
84
  end
79
85
  end
80
86
  end
81
87
  end
82
- Ecoportal::API::V2::Page.new(page.doc)
88
+ Ecoportal::API::V2::Pages::PageStage.new(page.doc).tap do |ozz|
89
+ ozz.state = state
90
+ end
83
91
  end
84
92
  end
85
93
 
86
- #def update_oozes(batched_oozes = batch_queue)
87
- # batched_oozes.each do |ooze|
88
- # update_ooze(ooze)
89
- # end
90
- # batched_oozes.clear
91
- #end
92
-
93
94
  def batched_search_results
94
95
  raise "Missing block. It yields in slices of #{self.class.batch_size} results" unless block_given?
95
96
  results_preview
@@ -137,10 +138,14 @@ class Eco::API::UseCases::OozeSamples::RegisterExportCase < Eco::API::Common::Lo
137
138
  exit_error "Stage '#{id_name}' doesn't exist in ooze '#{ooze_id}'"
138
139
  end
139
140
 
141
+ def default_proceed
142
+ "Y"
143
+ end
144
+
140
145
  def results_preview
141
146
  apiv2.registers.search(register_id, search_options.merge(only_first: true)).tap do |search_results|
142
147
  str_results = "Total target entries: #{search_results.total} (out of #{search_results.total_before_filtering})"
143
- session.prompt_user("Do you want to proceed (y/N):", explanation: str_results, default: "N", timeout: 10) do |res|
148
+ session.prompt_user("Do you want to proceed (y/N):", explanation: str_results, default: default_proceed, timeout: 10) do |res|
144
149
  unless res.upcase.start_with?("Y")
145
150
  puts "..."
146
151
  logger.info "Aborting script..."
@@ -180,5 +185,4 @@ class Eco::API::UseCases::OozeSamples::RegisterExportCase < Eco::API::Common::Lo
180
185
  logger.error(msg)
181
186
  exit(1)
182
187
  end
183
-
184
188
  end
@@ -163,3 +163,4 @@ require_relative 'usecases/base_io'
163
163
  require_relative 'usecases/use_case_io'
164
164
  require_relative 'usecases/default_cases'
165
165
  require_relative 'usecases/ooze_samples'
166
+ require_relative 'usecases/ooze_cases'
@@ -40,6 +40,11 @@ ASSETS.cli.config do |cnf|
40
40
  STDOUT.reopen(file, "w+")
41
41
  end
42
42
 
43
+ desc = "Skips the check of the headers"
44
+ options_set.add("-skip-header-check", desc) do |options, session|
45
+ options.deep_merge!(input: {skip_header_check: true})
46
+ end
47
+
43
48
  desc = "Fix the current session to work with this schema"
44
49
  options_set.add("-schema-id", desc) do |options, session|
45
50
  sch_name = SCR.get_arg("-schema-id", with_param: true)
@@ -147,7 +147,7 @@ ASSETS.cli.config do |cnf|
147
147
  cases.add("-entries-to-csv", :import, desc, case_name: "entries-to-csv")
148
148
  .add_option("-out") do |options|
149
149
  file = SCR.get_file("-out")
150
- options.deep_merge(export: {file: file})
150
+ options.deep_merge!(export: {file: file})
151
151
  end
152
152
 
153
153
  desc = "Usage '-org-data-convert backup.json -restore-db-from'."
@@ -254,5 +254,53 @@ ASSETS.cli.config do |cnf|
254
254
  .add_option("-append-starters", as1) do |options|
255
255
  options.deep_merge!(people: {append_created: true})
256
256
  end
257
+
258
+ # Ooze cases
259
+ desc = "APIv2 Case: Exports the target register into a CSV"
260
+ cases.add("-export-register", :other, desc, case_name: "export-register") do |session, options, usecase|
261
+ file = SCR.get_file("-export-register", required: false, should_exist: false)
262
+ options.deep_merge!(export: {file: {name: file || "RegisterExport.csv", format: :csv}})
263
+
264
+ unless options.dig(:source, :register_id)
265
+ session.logger.error "You should specify the target register id"
266
+ exit(1)
267
+ end
268
+ end.add_option("-register-id", "Target register id") do |options|
269
+ reg_id = SCR.get_arg("-register-id", with_param: true)
270
+ options.deep_merge!(source: {register_id: reg_id})
271
+ end.add_option("-include-deindexed", "Tells if deindexed fields should be included") do |options|
272
+ options.deep_merge!(export: {options: {include: {deindexed: true}}})
273
+ end.add_option("-include-unnamed", "Tells if unnamed fields should be included") do |options|
274
+ options.deep_merge!(export: {options: {include: {unnamed: true}}})
275
+ end.add_option("-include-unhashed", "Tells if fields with no hash reference (very short label) should be included") do |options|
276
+ options.deep_merge!(export: {options: {include: {unhashed: true}}})
277
+ end.add_option("-delimiter", "Sets the delimiter to be used in fields multi value") do |options|
278
+ str = SCR.get_arg("-delimiter", with_param: true)
279
+ options.deep_merge!(export: {options: {delimiter: str}})
280
+ end.add_option("-created-from", "Filters the register to the entries created FROM the specified date") do |options|
281
+ str = SCR.get_arg("-created-from", with_param: true)
282
+ date = Time.parse(str)
283
+ options.deep_merge!(export: {options: {filters: {created_at: {from: date}}}})
284
+ end.add_option("-created-to", "Filters the register to the entries created up TO the specified date") do |options|
285
+ str = SCR.get_arg("-created-to", with_param: true)
286
+ date = Time.parse(str)
287
+ options.deep_merge!(export: {options: {filters: {created_at: {to: date}}}})
288
+ end.add_option("-updated-from", "Filters the register by entries updated FROM the specified date") do |options|
289
+ str = SCR.get_arg("-updated-from", with_param: true)
290
+ date = Time.parse(str)
291
+ options.deep_merge!(export: {options: {filters: {updated_at: {from: date}}}})
292
+ end.add_option("-updated-to", "Filters the register by entries updated up TO the specified date") do |options|
293
+ str = SCR.get_arg("-updated-to", with_param: true)
294
+ date = Time.parse(str)
295
+ options.deep_merge!(export: {options: {filters: {updated_at: {to: date}}}})
296
+ end.add_option("-all-tags", "Filters the register to entries with ALL specified tags (| separator)") do |options|
297
+ str = SCR.get_arg("-all-tags", with_param: true)
298
+ tags = str.split("|")
299
+ options.deep_merge!(export: {options: {filters: {tags: {all: tags}}}})
300
+ end.add_option("-any-tags", "Filters the register to entries with ANY specified tags (| separator)") do |options|
301
+ str = SCR.get_arg("-all-tags", with_param: true)
302
+ tags = str.split("|")
303
+ options.deep_merge!(export: {options: {filters: {tags: {any: tags}}}})
304
+ end
257
305
  end
258
306
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = "2.0.60"
2
+ VERSION = "2.0.63"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eco-helpers
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.60
4
+ version: 2.0.63
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oscar Segura
@@ -136,7 +136,7 @@ dependencies:
136
136
  requirements:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
- version: 0.8.28
139
+ version: 0.8.30
140
140
  - - "<"
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0.9'
@@ -146,7 +146,7 @@ dependencies:
146
146
  requirements:
147
147
  - - ">="
148
148
  - !ruby/object:Gem::Version
149
- version: 0.8.28
149
+ version: 0.8.30
150
150
  - - "<"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0.9'
@@ -437,6 +437,7 @@ files:
437
437
  - lib/eco/api/common/session/sftp.rb
438
438
  - lib/eco/api/common/version_patches.rb
439
439
  - lib/eco/api/common/version_patches/ecoportal_api.rb
440
+ - lib/eco/api/common/version_patches/ecoportal_api/client.rb
440
441
  - lib/eco/api/common/version_patches/ecoportal_api/external_details.rb
441
442
  - lib/eco/api/common/version_patches/ecoportal_api/external_person.rb
442
443
  - lib/eco/api/common/version_patches/ecoportal_api/internal_person.rb
@@ -564,8 +565,14 @@ files:
564
565
  - lib/eco/api/usecases/default_cases/update_case.rb
565
566
  - lib/eco/api/usecases/default_cases/update_details_case.rb
566
567
  - lib/eco/api/usecases/default_cases/upsert_case.rb
568
+ - lib/eco/api/usecases/ooze_cases.rb
569
+ - lib/eco/api/usecases/ooze_cases/export_register_case.rb
567
570
  - lib/eco/api/usecases/ooze_samples.rb
568
571
  - lib/eco/api/usecases/ooze_samples/helpers.rb
572
+ - lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb
573
+ - lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb
574
+ - lib/eco/api/usecases/ooze_samples/helpers/filters.rb
575
+ - lib/eco/api/usecases/ooze_samples/helpers/ooze_handlers.rb
569
576
  - lib/eco/api/usecases/ooze_samples/helpers/shortcuts.rb
570
577
  - lib/eco/api/usecases/ooze_samples/ooze_base_case.rb
571
578
  - lib/eco/api/usecases/ooze_samples/ooze_from_doc_case.rb