eco-helpers 2.0.59 → 2.0.62
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -2
- data/eco-helpers.gemspec +1 -1
- data/lib/eco/api/common/people/default_parsers/csv_parser.rb +5 -1
- data/lib/eco/api/common/people/entries.rb +4 -3
- data/lib/eco/api/common/session/sftp.rb +24 -3
- data/lib/eco/api/common/version_patches/ecoportal_api/client.rb +9 -0
- data/lib/eco/api/common/version_patches/ecoportal_api/external_details.rb +15 -0
- data/lib/eco/api/common/version_patches/ecoportal_api.rb +2 -0
- data/lib/eco/api/session/config/sftp.rb +9 -1
- data/lib/eco/api/usecases/default_cases/create_case.rb +1 -1
- data/lib/eco/api/usecases/default_cases.rb +1 -0
- data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +99 -0
- data/lib/eco/api/usecases/ooze_cases.rb +10 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +169 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb +72 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/filters.rb +72 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/ooze_handlers.rb +85 -0
- data/lib/eco/api/usecases/ooze_samples/helpers.rb +7 -1
- data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +21 -17
- data/lib/eco/api/usecases.rb +1 -0
- data/lib/eco/cli/config/default/options.rb +5 -0
- data/lib/eco/cli/config/default/usecases.rb +49 -1
- data/lib/eco/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a20dea65d12f12a2f98885339f146445b0286456389114514a174ca43cc5e8b6
|
4
|
+
data.tar.gz: 3eed3dab1682206b9b4c54ce62033f5de6c6136558863eff86904cb5d5104744
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e14376e092ede7eabec60cc804bad014bdcacaf424f32475b391111992552a9ebcffb644690db8ef232ddd3e1280ffa700bdec6dae54bc39c50d9718ee29938
|
7
|
+
data.tar.gz: 7174c43b7c13c6b9b83c054e6b187947ec91160a1149451b988f8fdc0ac50d1b75a982ea105f7d21f64a4cc2ec02ef4655cd178e366a9543456dc1ff1bf0d995
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,50 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
## [2.0.
|
4
|
+
## [2.0.62] - 2022-07-15
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- SFTP **password** option
|
8
|
+
- `Eco::API::Common::Session::Sftp` fetches from config
|
9
|
+
- `Eco::API::Session::Config::Sftp#password`
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
### Fixed
|
13
|
+
- `Eco::API::UseCases::DefaultCases::CreateCase` had a typo
|
14
|
+
|
15
|
+
## [2.0.61] - 2022-07-11
|
16
|
+
|
17
|
+
### Added
|
18
|
+
- patch for `Ecoportal::API::Common::Client#host` exposed `host` property
|
19
|
+
- `skip-header-checks` option
|
20
|
+
- It prevents checks done in the `Eco::API::Common::People::DefaultParsers::CSVParser`
|
21
|
+
- **Export Helpers** to be able to automate exports via `APIv2`
|
22
|
+
- `Eco::API::UseCases::OozeSamples::Helpers::ExportableRegister`
|
23
|
+
- `Eco::API::UseCases::OozeSamples::Helpers::ExportableOoze`
|
24
|
+
- `Eco::API::UseCases::OozeCases::ExportRegisterCase` to export registers
|
25
|
+
- First ooze native use case (besides the samples)
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
- upgraded `ecoportal-api-v2` to version `0.8.30`
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
- `-entries-to-csv` case; option `-out` was not being used
|
32
|
+
- `Eco::API::Common::People::Entries#export` made it so it creates one column per key
|
33
|
+
- It was wrongly merging the entries assuming all of them had the same keys
|
34
|
+
- 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
|
35
|
+
- `Eco::API::UseCases::OozeSamples::RegisterExportCase`
|
36
|
+
- On prompt to launch, it answers `Yes`
|
37
|
+
- It correctly captures the `state` based on the stages `state`
|
38
|
+
- It was not building the model
|
39
|
+
- Optimized
|
40
|
+
- It returns a `PageStage` (rather than `Page`), to ensure all supported properties are accessible (i.e. `uid`)
|
41
|
+
|
42
|
+
## [2.0.60] - 2022-07-01
|
43
|
+
|
44
|
+
### Fixed
|
45
|
+
- `Ecoportal::API::V1::PersonDetails.key?` patched
|
46
|
+
|
47
|
+
## [2.0.59] - 2022-06-07
|
5
48
|
|
6
49
|
### Added
|
7
50
|
- `Eco::API::Organization::TagTree#leafs` new method to spot tags with no children.
|
@@ -13,7 +56,7 @@ All notable changes to this project will be documented in this file.
|
|
13
56
|
### Fixed
|
14
57
|
- `Eco::API::Policies::DefaultPolicies::UserAccess`
|
15
58
|
- `-exclude-account` should leave it untouched
|
16
|
-
|
59
|
+
|
17
60
|
## [2.0.58] - 2022-05-31
|
18
61
|
|
19
62
|
### 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.
|
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.
|
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
|
-
|
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,15 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
class V1
|
4
|
+
class PersonDetails
|
5
|
+
# Checks if an `id` or `alt_id` exists
|
6
|
+
# @param id [String] the `id` or the `alt_id` of the target field.
|
7
|
+
# @return [Boolean] `true` if it exists, `false` otherwise
|
8
|
+
def key?(id)
|
9
|
+
@fields_by_id or index_fields
|
10
|
+
@fields_by_id.key?(id) || @fields_by_alt_id.key?(id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -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
|
@@ -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
|
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)
|
@@ -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,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
|
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
|
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
|
-
|
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
|
70
|
-
|
71
|
-
|
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
|
-
|
76
|
-
unless
|
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::
|
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:
|
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
|
data/lib/eco/api/usecases.rb
CHANGED
@@ -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
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.
|
4
|
+
version: 2.0.62
|
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.
|
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.
|
149
|
+
version: 0.8.30
|
150
150
|
- - "<"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0.9'
|
@@ -437,6 +437,8 @@ 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
|
441
|
+
- lib/eco/api/common/version_patches/ecoportal_api/external_details.rb
|
440
442
|
- lib/eco/api/common/version_patches/ecoportal_api/external_person.rb
|
441
443
|
- lib/eco/api/common/version_patches/ecoportal_api/internal_person.rb
|
442
444
|
- lib/eco/api/common/version_patches/exception.rb
|
@@ -563,8 +565,14 @@ files:
|
|
563
565
|
- lib/eco/api/usecases/default_cases/update_case.rb
|
564
566
|
- lib/eco/api/usecases/default_cases/update_details_case.rb
|
565
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
|
566
570
|
- lib/eco/api/usecases/ooze_samples.rb
|
567
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
|
568
576
|
- lib/eco/api/usecases/ooze_samples/helpers/shortcuts.rb
|
569
577
|
- lib/eco/api/usecases/ooze_samples/ooze_base_case.rb
|
570
578
|
- lib/eco/api/usecases/ooze_samples/ooze_from_doc_case.rb
|