eco-helpers 2.6.3 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +95 -0
- data/CHANGELOG.md +135 -2
- data/Rakefile +13 -7
- data/eco-helpers.gemspec +3 -3
- data/lib/eco/api/common/loaders/base.rb +2 -2
- data/lib/eco/api/common/loaders/case_base.rb +1 -1
- data/lib/eco/api/common/loaders/config/workflow/mailer.rb +5 -5
- data/lib/eco/api/common/loaders/error_handler.rb +8 -5
- data/lib/eco/api/common/loaders/parser.rb +44 -22
- data/lib/eco/api/common/loaders/policy.rb +6 -4
- data/lib/eco/api/common/loaders/use_case.rb +13 -7
- data/lib/eco/api/common/people/base_parser.rb +0 -2
- data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/csv_parser.rb +1 -1
- data/lib/eco/api/common/people/default_parsers/date_parser.rb +64 -12
- data/lib/eco/api/common/people/default_parsers/freemium_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +13 -5
- data/lib/eco/api/common/people/default_parsers/multi_parser.rb +0 -1
- data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +18 -5
- data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +8 -8
- data/lib/eco/api/common/people/default_parsers/select_parser.rb +50 -26
- data/lib/eco/api/common/people/default_parsers/send_invites_parser.rb +6 -6
- data/lib/eco/api/common/people/default_parsers/xls_parser.rb +9 -12
- data/lib/eco/api/common/people/default_parsers.rb +1 -12
- data/lib/eco/api/common/people/entries.rb +13 -13
- data/lib/eco/api/common/people/entry_factory.rb +76 -45
- data/lib/eco/api/common/people/person_attribute_parser.rb +8 -12
- data/lib/eco/api/common/people/person_entry.rb +86 -75
- data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +60 -44
- data/lib/eco/api/common/people/person_factory.rb +30 -22
- data/lib/eco/api/common/people/person_modifier.rb +11 -13
- data/lib/eco/api/common/people/person_parser.rb +101 -39
- data/lib/eco/api/common/people/supervisor_helpers.rb +25 -26
- data/lib/eco/api/common/session/base_session.rb +9 -9
- data/lib/eco/api/common/session/environment.rb +7 -5
- data/lib/eco/api/common/session/sftp.rb +59 -32
- data/lib/eco/api/common/version_patches/ecoportal_api/external_person.rb +10 -6
- data/lib/eco/api/common/version_patches/exception.rb +11 -13
- data/lib/eco/api/error.rb +32 -20
- data/lib/eco/api/microcases/set_supervisor.rb +0 -3
- data/lib/eco/api/organization/node_classifications.rb +82 -0
- data/lib/eco/api/organization/policy_groups.rb +4 -6
- data/lib/eco/api/organization/tag_tree.rb +169 -93
- data/lib/eco/api/organization.rb +1 -0
- data/lib/eco/api/session/batch/job.rb +1 -1
- data/lib/eco/api/session/config/tagtree.rb +41 -23
- data/lib/eco/api/session/config/workflow.rb +113 -88
- data/lib/eco/api/session/config.rb +6 -0
- data/lib/eco/api/session.rb +51 -29
- data/lib/eco/api/usecases/base_io.rb +28 -25
- data/lib/eco/api/usecases/default/locations/cli/tagtree_extract_cli.rb +7 -2
- data/lib/eco/api/usecases/default/locations/cli/tagtree_upload_cli.rb +21 -0
- data/lib/eco/api/usecases/default/locations/csv_to_tree_case.rb +3 -3
- data/lib/eco/api/usecases/default/locations/tagtree_extract_case.rb +54 -23
- data/lib/eco/api/usecases/default/locations/tagtree_upload_case.rb +87 -0
- data/lib/eco/api/usecases/default/locations.rb +1 -0
- data/lib/eco/api/usecases/default/people/analyse_people_case.rb +60 -56
- data/lib/eco/api/usecases/default/people/change_email_case.rb +8 -9
- data/lib/eco/api/usecases/default/people/clean_unknown_tags_case.rb +13 -11
- data/lib/eco/api/usecases/default/people/clear_abilities_case.rb +2 -2
- data/lib/eco/api/usecases/default/people/org_data_convert_case.rb +25 -27
- data/lib/eco/api/usecases/default/people/refresh_case.rb +2 -2
- data/lib/eco/api/usecases/default/people/reinvite_trans_case.rb +1 -1
- data/lib/eco/api/usecases/default/people/reinvite_trans_cli.rb +0 -1
- data/lib/eco/api/usecases/default/people/restore_db_case.rb +39 -34
- data/lib/eco/api/usecases/default/people/set_default_tag_case.rb +19 -15
- data/lib/eco/api/usecases/default/people/supers_cyclic_identify_case.rb +16 -12
- data/lib/eco/api/usecases/default_cases/hris_case.rb +17 -15
- data/lib/eco/api/usecases/default_cases/samples/sftp_case.rb +30 -16
- data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +0 -2
- data/lib/eco/api/usecases/graphql/base.rb +5 -3
- data/lib/eco/api/usecases/graphql/helpers/base/case_env.rb +4 -1
- data/lib/eco/api/usecases/graphql/helpers/base/graphql_env.rb +14 -0
- data/lib/eco/api/usecases/graphql/helpers/base.rb +5 -4
- data/lib/eco/api/usecases/graphql/helpers/location/base/classifications_parser.rb +60 -0
- data/lib/eco/api/usecases/graphql/helpers/location/base/tree_tracking.rb +72 -0
- data/lib/eco/api/usecases/graphql/helpers/location/base.rb +25 -59
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff/as_update.rb +59 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff/compare.rb +49 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diff.rb +11 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/commandable.rb +46 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_archive.rb +23 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable/for_unarchive.rb +65 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/diff_sortable.rb +49 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable/relation_safe_sort.rb +119 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/sortable.rb +59 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages.rb +82 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs.rb +20 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/optimizations.rb +84 -0
- data/lib/eco/api/usecases/graphql/helpers/location/command/result.rb +4 -4
- data/lib/eco/api/usecases/graphql/helpers/location/command/results.rb +24 -12
- data/lib/eco/api/usecases/graphql/helpers/location/command.rb +21 -24
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_map.rb +1 -1
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap/tags_set.rb +10 -11
- data/lib/eco/api/usecases/graphql/helpers/location/tags_remap.rb +8 -9
- data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +41 -12
- data/lib/eco/api/usecases/graphql/samples/location/command/results.rb +11 -80
- data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +89 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/service.rb +6 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/track_changed_ids.rb +89 -0
- data/lib/eco/api/usecases/graphql/samples/location/command.rb +3 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/base.rb +9 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/heading.rb +18 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/inputable.rb +53 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/classifications.rb +34 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing/helpers.rb +28 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing.rb +46 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible.rb +38 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +105 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/discarded.rb +16 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/input.rb +15 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/node_attr_maps.rb +22 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter/parser.rb +45 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/converter.rb +36 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list/output.rb +56 -0
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_to_list.rb +41 -0
- data/lib/eco/api/usecases/graphql/samples/location/service.rb +8 -0
- data/lib/eco/api/usecases/graphql/samples/location.rb +1 -0
- data/lib/eco/api/usecases/graphql/utils/sftp.rb +96 -36
- data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +8 -6
- data/lib/eco/api/usecases/ooze_samples/helpers/creatable.rb +4 -3
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +39 -25
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb +13 -15
- data/lib/eco/api/usecases/ooze_samples/helpers/filters.rb +50 -21
- data/lib/eco/api/usecases/ooze_samples/helpers/ooze_handlers.rb +21 -11
- data/lib/eco/api/usecases/ooze_samples/helpers/rescuable.rb +2 -0
- data/lib/eco/api/usecases/ooze_samples/helpers/shortcuts.rb +49 -43
- data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +17 -19
- data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +48 -43
- data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +34 -34
- data/lib/eco/api/usecases/ooze_samples/target_oozes_update_case.rb +8 -10
- data/lib/eco/api/usecases.rb +0 -1
- data/lib/eco/cli/config/use_cases.rb +31 -29
- data/lib/eco/cli_default/input_filters.rb +0 -5
- data/lib/eco/cli_default/people_filters.rb +4 -4
- data/lib/eco/cli_default/workflow.rb +13 -14
- data/lib/eco/csv/table.rb +34 -25
- data/lib/eco/data/hashes/array_diff.rb +24 -35
- data/lib/eco/data/hashes/diff_result/meta.rb +131 -0
- data/lib/eco/data/hashes/diff_result.rb +65 -57
- data/lib/eco/data/hashes/sanke_camel_indifferent_access.rb +278 -0
- data/lib/eco/data/hashes.rb +1 -1
- data/lib/eco/data/locations/convert.rb +1 -1
- data/lib/eco/data/locations/node_base/csv_convert.rb +19 -9
- data/lib/eco/data/locations/node_base/parsing.rb +4 -2
- data/lib/eco/data/locations/node_base/treeify.rb +149 -132
- data/lib/eco/data/locations/node_base.rb +15 -4
- data/lib/eco/data/locations/node_diff/accessors.rb +13 -5
- data/lib/eco/data/locations/node_diff/nodes_diff/clustered_treeify.rb +101 -0
- data/lib/eco/data/locations/node_diff/nodes_diff/diffs_tree.rb +99 -0
- data/lib/eco/data/locations/node_diff/{selectors.rb → nodes_diff/selectors.rb} +1 -1
- data/lib/eco/data/locations/node_diff/nodes_diff.rb +50 -35
- data/lib/eco/data/locations/node_diff.rb +45 -17
- data/lib/eco/data/locations/node_level/parsing.rb +15 -21
- data/lib/eco/data/locations/node_level.rb +66 -22
- data/lib/eco/data/locations/node_plain/parsing.rb +1 -1
- data/lib/eco/data/locations/node_plain.rb +60 -7
- data/lib/eco/data/strings/camel_case.rb +35 -0
- data/lib/eco/data/strings/snake_case.rb +18 -0
- data/lib/eco/data/strings.rb +8 -0
- data/lib/eco/data.rb +1 -0
- data/lib/eco/language/methods/call_detector.rb +11 -0
- data/lib/eco/language/methods/dsl_able.rb +7 -1
- data/lib/eco/language/methods.rb +2 -1
- data/lib/eco/language/models/collection.rb +23 -25
- data/lib/eco/language/models/parser_serializer.rb +24 -5
- data/lib/eco/version.rb +1 -1
- data/lib/eco-helpers.rb +0 -1
- metadata +54 -9
- data/lib/eco/data/hashes/diff_meta.rb +0 -52
@@ -2,21 +2,35 @@ module Eco
|
|
2
2
|
module API
|
3
3
|
module Common
|
4
4
|
module People
|
5
|
-
|
6
5
|
# Class to define/group a set of parsers/serializers.
|
7
6
|
#
|
8
|
-
# @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of
|
9
|
-
#
|
10
|
-
# @attr_reader
|
7
|
+
# @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of
|
8
|
+
# person details that this parser will be based upon.
|
9
|
+
# @attr_reader details_attrs [Array<String>] internal names of
|
10
|
+
# chema details attributes.
|
11
|
+
# @attr_reader all_model_attrs [Array<String>] all the internal
|
12
|
+
# name attributes, including _core_, _account_ and _details_.
|
11
13
|
class PersonParser
|
12
|
-
extend
|
14
|
+
extend Eco::API::Common::ClassAutoLoader
|
13
15
|
autoloads_children_of "Eco::API::Common::Loaders::Parser"
|
14
16
|
autoload_namespace_ignore "Eco::API"
|
15
17
|
|
16
|
-
CORE_ATTRS
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
CORE_ATTRS = %w[
|
19
|
+
id external_id email name
|
20
|
+
supervisor_id filter_tags
|
21
|
+
contractor_organization_id freemium
|
22
|
+
].freeze
|
23
|
+
ACCOUNT_ATTRS = %w[
|
24
|
+
policy_group_ids default_tag
|
25
|
+
send_invites landing_page_id
|
26
|
+
login_provider_ids
|
27
|
+
].freeze
|
28
|
+
TYPE = %i[
|
29
|
+
select text date
|
30
|
+
number phone_number
|
31
|
+
boolean multiple
|
32
|
+
].freeze
|
33
|
+
FORMAT = %i[csv xml json xls].freeze
|
20
34
|
|
21
35
|
attr_reader :schema
|
22
36
|
attr_reader :details_attrs, :all_model_attrs
|
@@ -33,16 +47,18 @@ module Eco
|
|
33
47
|
# value.to_s
|
34
48
|
# end
|
35
49
|
# end
|
36
|
-
# @param schema [Ecoportal::API::V1::PersonSchema, nil] schema of
|
50
|
+
# @param schema [Ecoportal::API::V1::PersonSchema, nil] schema of
|
51
|
+
# person details that this parser will be based upon.
|
37
52
|
def initialize(schema: nil)
|
38
|
-
|
53
|
+
msg = "Constructor needs a PersonSchema. Given: #{schema.class}"
|
54
|
+
raise msg if schema && !schema.is_a?(Ecoportal::API::V1::PersonSchema)
|
39
55
|
@details_attrs = []
|
40
56
|
@parsers = {}
|
41
57
|
@patch_version = 0
|
42
58
|
|
43
59
|
if schema
|
44
60
|
@schema = Ecoportal::API::Internal::PersonSchema.new(JSON.parse(schema.doc.to_json))
|
45
|
-
@details_attrs
|
61
|
+
@details_attrs = @schema&.fields&.map(&:alt_id)
|
46
62
|
end
|
47
63
|
|
48
64
|
@all_model_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
|
@@ -57,6 +73,25 @@ module Eco
|
|
57
73
|
self.class.new(schema: schema || self.schema).merge(self)
|
58
74
|
end
|
59
75
|
|
76
|
+
# @!group selection options of all select attributes
|
77
|
+
|
78
|
+
# Select Options
|
79
|
+
def select_tables
|
80
|
+
return nil unless @schema
|
81
|
+
|
82
|
+
@select_tables ||= @schema.fields.select do |fld|
|
83
|
+
fld.type == "select"
|
84
|
+
end.to_h do |fld|
|
85
|
+
msg = "The schema selection field '#{fld.name}' is missing selection options."
|
86
|
+
raise msg unless fld.options&.any?
|
87
|
+
|
88
|
+
options_hash = fld.options.to_h { |v| [v.downcase.strip, v] }
|
89
|
+
[fld.alt_id, options_hash]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!endgroup
|
94
|
+
|
60
95
|
# @!group Scopping attributes (identifying, presence & active)
|
61
96
|
|
62
97
|
# @return [Array<Eco::API::Common::Loaders::Parser::RequiredAttrs>]
|
@@ -71,29 +106,35 @@ module Eco
|
|
71
106
|
end
|
72
107
|
|
73
108
|
# Scopes `source_attrs` using the _**core** attributes_.
|
74
|
-
# @note use this helper to know which among your attributes are
|
109
|
+
# @note use this helper to know which among your attributes are
|
110
|
+
# **core** ones.
|
75
111
|
# @param source_attrs [Array<String>]
|
76
|
-
# @return [Array<String>] the scoped **core** attributes,
|
112
|
+
# @return [Array<String>] the scoped **core** attributes,
|
113
|
+
# if `source_attrs` is not `nil`. All the _core attributes_, otherwise.
|
77
114
|
def target_attrs_core(source_attrs = nil)
|
78
|
-
return CORE_ATTRS
|
115
|
+
return CORE_ATTRS unless source_attrs
|
79
116
|
scoped_attrs(source_attrs, CORE_ATTRS)
|
80
117
|
end
|
81
118
|
|
82
119
|
# Scopes `source_attrs` using the schema _**details** attributes_.
|
83
|
-
# @note use this helper to know which among your attributes
|
120
|
+
# @note use this helper to know which among your attributes
|
121
|
+
# are schema **details** ones.
|
84
122
|
# @param source_attrs [Array<String>]
|
85
|
-
# @return [Array<String>] the scoped **details** attributes,
|
123
|
+
# @return [Array<String>] the scoped **details** attributes,
|
124
|
+
# if `source_attrs` is not `nil`. All the _details attributes_, otherwise.
|
86
125
|
def target_attrs_details(source_attrs = nil)
|
87
|
-
return @details_attrs
|
126
|
+
return @details_attrs unless source_attrs
|
88
127
|
scoped_attrs(source_attrs, @details_attrs)
|
89
128
|
end
|
90
129
|
|
91
130
|
# Scopes `source_attrs` using the schema _**account** attributes_.
|
92
131
|
# @note use this helper to know which among your attributes are **account** ones.
|
93
132
|
# @param source_attrs [Array<String>]
|
94
|
-
# @return [Array<String>] the scoped **account** attributes,
|
133
|
+
# @return [Array<String>] the scoped **account** attributes,
|
134
|
+
# if `source_attrs` is not `nil`.
|
135
|
+
# All the _account attributes_, otherwise.
|
95
136
|
def target_attrs_account(source_attrs = nil)
|
96
|
-
return ACCOUNT_ATTRS
|
137
|
+
return ACCOUNT_ATTRS unless source_attrs
|
97
138
|
scoped_attrs(source_attrs, ACCOUNT_ATTRS)
|
98
139
|
end
|
99
140
|
|
@@ -128,12 +169,17 @@ module Eco
|
|
128
169
|
@parsers.keys.select {|k| k.is_a?(Symbol)}
|
129
170
|
end
|
130
171
|
|
131
|
-
# Returns a list of all the internal attributes of the model that have
|
132
|
-
#
|
133
|
-
# @param
|
172
|
+
# Returns a list of all the internal attributes of the model that have
|
173
|
+
# a parser defined & that should be active.
|
174
|
+
# @param source_data [Hash, Array<String>] the data that we scope for
|
175
|
+
# parsing
|
176
|
+
# @param phase [Symbol] the phase when the attr parser is expected
|
177
|
+
# to be called.
|
134
178
|
# Can be [:internal, :final, :person]
|
135
|
-
# @param process [Symbol] either `:parse` or `:serialize`, depending
|
136
|
-
#
|
179
|
+
# @param process [Symbol] either `:parse` or `:serialize`, depending
|
180
|
+
# if we want to parse or serialize the `attr`.
|
181
|
+
# @return [Array<String>] list of all attribute defined parsers that
|
182
|
+
# should be active for the given `source_data`.
|
137
183
|
def active_attrs(source_data, phase = :any, process: :parse)
|
138
184
|
defined_model_attrs.select do |attr|
|
139
185
|
if process == :serialize
|
@@ -165,8 +211,10 @@ module Eco
|
|
165
211
|
# @param parser [Eco::API::Common::People::PersonParser] a `PersonParser` containing defined parsers.
|
166
212
|
# @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig).
|
167
213
|
def merge(parser)
|
168
|
-
return self
|
169
|
-
|
214
|
+
return self unless parser
|
215
|
+
msg = "Expected a PersonParser object. Given #{parser.class}"
|
216
|
+
raise msg unless parser.is_a?(PersonParser)
|
217
|
+
|
170
218
|
to_h.merge!(parser.to_h)
|
171
219
|
patched!
|
172
220
|
self
|
@@ -183,7 +231,9 @@ module Eco
|
|
183
231
|
# @return [Eco::API::Common::People::PersonParser] the current object (to ease chainig).
|
184
232
|
def define_attribute(attr, dependencies: {}, &definition)
|
185
233
|
unless valid?(attr)
|
186
|
-
msg =
|
234
|
+
msg = "The attribute '#{attr_to_str(attr)}' is not part of "
|
235
|
+
msg << "core, account or target schema, or does "
|
236
|
+
msg << "not match any type: #{@details_attrs}"
|
187
237
|
raise msg
|
188
238
|
end
|
189
239
|
Eco::API::Common::People::PersonAttributeParser.new(attr, dependencies: dependencies).tap do |parser|
|
@@ -197,19 +247,27 @@ module Eco
|
|
197
247
|
|
198
248
|
# @!group Launching parser/serializer
|
199
249
|
|
200
|
-
# Call to parser `source` value of attribute or type `attr` into
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
250
|
+
# Call to parser `source` value of attribute or type `attr` into
|
251
|
+
# an internal valid value.
|
252
|
+
# @note dependencies introduced on `parse` call will be merged with
|
253
|
+
# those defined during the initialization of the parser `attr`.
|
254
|
+
# @raise [Exception] if there is **no** parser for attribute or
|
255
|
+
# type `attr`.
|
204
256
|
# @param attr [String] target attribute or type to **parse**.
|
205
257
|
# @param source [Any] source value to be parsed.
|
206
|
-
# @param phase [Symbol] the phase when the attr parser is expected
|
258
|
+
# @param phase [Symbol] the phase when the attr parser is expected
|
259
|
+
# to be called.
|
207
260
|
# Must be [:internal, :final]
|
208
261
|
# @param deps [Hash] key-value pairs of call dependencies.
|
209
262
|
# @return [Any] a valid internal value.
|
210
263
|
def parse(attr, source, phase = :internal, deps: {})
|
211
|
-
|
212
|
-
|
264
|
+
msg = "There is no parser for attribute '#{attr}'"
|
265
|
+
raise msg unless self.defined?(attr)
|
266
|
+
|
267
|
+
@parsers[attr].parse(source, phase, dependencies: deps) do |_dkey, dval|
|
268
|
+
next dval unless dval.is_a?(Proc)
|
269
|
+
dval.call(self)
|
270
|
+
end
|
213
271
|
end
|
214
272
|
|
215
273
|
# Call to serialise `object` value of attribute or type `attr` into an external valid value.
|
@@ -223,8 +281,13 @@ module Eco
|
|
223
281
|
# @param deps [Hash] key-value pairs of call dependencies.
|
224
282
|
# @return a valid external value.
|
225
283
|
def serialize(attr, object, phase = :person, deps: {})
|
226
|
-
|
227
|
-
|
284
|
+
msg = "There is no parser for attribute '#{attr}'"
|
285
|
+
raise msg unless self.defined?(attr)
|
286
|
+
|
287
|
+
@parsers[attr].serialize(object, phase, dependencies: deps) do |_dkey, dval|
|
288
|
+
next dval unless dval.is_a?(Proc)
|
289
|
+
dval.call(self)
|
290
|
+
end
|
228
291
|
end
|
229
292
|
# @!endgroup
|
230
293
|
|
@@ -247,7 +310,7 @@ module Eco
|
|
247
310
|
end
|
248
311
|
|
249
312
|
def attr_to_str(attr)
|
250
|
-
attr.is_a?(Symbol)? ":#{attr
|
313
|
+
attr.is_a?(Symbol)? ":#{attr}" : attr.to_s
|
251
314
|
end
|
252
315
|
|
253
316
|
def valid?(attr)
|
@@ -265,7 +328,6 @@ module Eco
|
|
265
328
|
def valid_format?(attr)
|
266
329
|
attr.is_a?(Symbol) && FORMAT.include?(attr)
|
267
330
|
end
|
268
|
-
|
269
331
|
end
|
270
332
|
end
|
271
333
|
end
|
@@ -18,12 +18,13 @@ module Eco
|
|
18
18
|
# @return [Array<PersonEntry>] `values` sorted by supervisors/subordinates
|
19
19
|
def sort_by_supervisors(values, supervisors_first: true)
|
20
20
|
raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
|
21
|
-
return [] unless values
|
22
|
-
roam =
|
21
|
+
return [] unless values.is_a?(Enumerable)
|
22
|
+
roam = proc do |tree|
|
23
23
|
[].tap do |out|
|
24
24
|
sub_outs = tree.empty?? [] : tree.map {|sup, subtree| roam.call(subtree)}
|
25
|
+
|
25
26
|
tree.each do |sup, subtree|
|
26
|
-
sout = subtree.empty?? [] :roam.call(subtree)
|
27
|
+
sout = subtree.empty?? [] : roam.call(subtree)
|
27
28
|
supervisors_first ? sout.unshift(sup) : sout.push(sup)
|
28
29
|
out.concat(sout)
|
29
30
|
end
|
@@ -34,13 +35,14 @@ module Eco
|
|
34
35
|
end
|
35
36
|
|
36
37
|
# Identifies all the cyclic supervisor chains
|
37
|
-
# @note as `supervisors_tree` will have any entry involved in a cycle at the top,
|
38
|
+
# @note as `supervisors_tree` will have any entry involved in a cycle at the top,
|
39
|
+
# it just checks all the top entries against their offspring
|
38
40
|
# @return [Array<Array>] the sets of entries that are cyclic
|
39
41
|
def identify_cyclic_chains(values)
|
40
42
|
raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
|
41
|
-
return [] unless values
|
43
|
+
return [] unless values.is_a?(Enumerable)
|
42
44
|
|
43
|
-
identify =
|
45
|
+
identify = proc do |top_sup, offspring, chain = [top_sup]|
|
44
46
|
next [] if offspring.empty?
|
45
47
|
offspring.each_with_object([]) do |(sup, subordinates), set|
|
46
48
|
break set unless set.empty?
|
@@ -80,15 +82,15 @@ module Eco
|
|
80
82
|
# @param values [Enumerable<Object>] of objects with methods:
|
81
83
|
# `id`, `external_id` and `supervisor_id`
|
82
84
|
# @return [Hash] the tree structure
|
83
|
-
def supervisors_tree(values)
|
85
|
+
def supervisors_tree(values) # rubocop:disable Metrics/AbcSize
|
84
86
|
raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
|
85
|
-
return {} unless values
|
87
|
+
return {} unless values.is_a?(Enumerable)
|
86
88
|
idx = get_super_indexes(values)
|
87
89
|
|
88
90
|
processed = []
|
89
|
-
subtree =
|
91
|
+
subtree = proc do |entry, level, toptree|
|
90
92
|
if processed.include?(entry)
|
91
|
-
next {} unless toptree.key?(entry) && level
|
93
|
+
next {} unless toptree.key?(entry) && level.positive?
|
92
94
|
# needs to be moved as a child
|
93
95
|
subnodes = toptree.delete(entry)
|
94
96
|
processed.delete(entry)
|
@@ -109,7 +111,7 @@ module Eco
|
|
109
111
|
|
110
112
|
{}.tap do |tree|
|
111
113
|
idx[:by_sup].keys.each do |sup_id|
|
112
|
-
if sup = idx[:supers][sup_id]
|
114
|
+
if (sup = idx[:supers][sup_id])
|
113
115
|
tree.merge!(subtree.call(sup, 0, tree))
|
114
116
|
else
|
115
117
|
idx[:by_sup][sup_id].each do |sub|
|
@@ -122,7 +124,7 @@ module Eco
|
|
122
124
|
|
123
125
|
private
|
124
126
|
|
125
|
-
def get_super_indexes(values)
|
127
|
+
def get_super_indexes(values) # rubocop:disable Metrics/AbcSize
|
126
128
|
raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
|
127
129
|
{}.tap do |indexes|
|
128
130
|
indexes[:by_id] = values.map do |e|
|
@@ -133,45 +135,42 @@ module Eco
|
|
133
135
|
end.compact.to_h
|
134
136
|
|
135
137
|
indexes[:by_sup] = {}.tap do |by_s|
|
136
|
-
values.group_by do |
|
137
|
-
e.supervisor_id
|
138
|
-
end.tap do |by_sup|
|
138
|
+
values.group_by(&:supervisor_id).tap do |by_sup|
|
139
139
|
by_s[nil] = by_sup.delete(nil) if by_sup.key?(nil)
|
140
140
|
by_s.merge!(by_sup)
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
144
|
indexes[:supers] = {}.tap do |sups|
|
145
|
-
indexes[:by_ext].select do |ext,
|
145
|
+
indexes[:by_ext].select do |ext, _e|
|
146
146
|
ext && indexes[:by_sup].key?(ext)
|
147
147
|
end.tap {|found| sups.merge!(found)}
|
148
|
-
indexes[:by_id].select do |id,
|
148
|
+
indexes[:by_id].select do |id, _e|
|
149
149
|
id && indexes[:by_sup].key?(id)
|
150
150
|
end.tap {|found| sups.merge!(found)}
|
151
151
|
end
|
152
152
|
|
153
|
-
indexes[:is_super]
|
154
|
-
|
153
|
+
indexes[:is_super] = proc do |entry|
|
154
|
+
is = indexes[:supers][entry.id] || indexes[:supers][entry.external_id]
|
155
|
+
!is.nil?
|
155
156
|
end
|
156
157
|
|
157
|
-
indexes[:subordinates] =
|
158
|
+
indexes[:subordinates] = proc do |entry|
|
158
159
|
subs = nil
|
159
|
-
|
160
|
-
|
161
|
-
subs ||= indexes[:by_sup][sup.
|
160
|
+
sup = indexes[:supers][entry.id] || indexes[:supers][entry.external_id]
|
161
|
+
if sup
|
162
|
+
subs ||= indexes[:by_sup][sup.id] if sup.id
|
163
|
+
subs ||= indexes[:by_sup][sup.external_id] if sup.external_id
|
162
164
|
end
|
163
165
|
subs
|
164
166
|
end
|
165
167
|
end
|
166
|
-
|
167
168
|
end
|
168
|
-
|
169
169
|
end
|
170
170
|
|
171
171
|
class << self
|
172
172
|
include SupervisorHelpers::ClassMethods
|
173
173
|
end
|
174
|
-
|
175
174
|
end
|
176
175
|
end
|
177
176
|
end
|
@@ -3,19 +3,17 @@ module Eco
|
|
3
3
|
module Common
|
4
4
|
module Session
|
5
5
|
class BaseSession
|
6
|
-
|
7
|
-
|
6
|
+
attr_writer :session, :config
|
7
|
+
attr_reader :environment
|
8
8
|
alias_method :enviro, :environment
|
9
|
-
alias_method :enviro=, :environment=
|
10
|
-
|
11
|
-
attr_reader :api, :file_manager, :logger
|
12
|
-
alias_method :fm, :file_manager
|
13
9
|
|
14
10
|
include Session::Helpers
|
15
11
|
|
16
|
-
def initialize(
|
17
|
-
|
18
|
-
|
12
|
+
def initialize(env)
|
13
|
+
msg = "Expected object Eco::API::Common::Session::Environment. Given: #{env.class}"
|
14
|
+
raise msg unless env.is_a?(Environment)
|
15
|
+
|
16
|
+
self.environment = env
|
19
17
|
end
|
20
18
|
|
21
19
|
def session
|
@@ -26,6 +24,7 @@ module Eco
|
|
26
24
|
@environment = nil
|
27
25
|
@environment = value if value.is_a?(Environment)
|
28
26
|
end
|
27
|
+
alias_method :enviro=, :environment=
|
29
28
|
|
30
29
|
def config
|
31
30
|
enviro.config
|
@@ -42,6 +41,7 @@ module Eco
|
|
42
41
|
def file_manager
|
43
42
|
enviro.file_manager
|
44
43
|
end
|
44
|
+
alias_method :fm, :file_manager
|
45
45
|
|
46
46
|
def mailer
|
47
47
|
enviro.mailer
|
@@ -5,7 +5,6 @@ module Eco
|
|
5
5
|
class Environment
|
6
6
|
attr_reader :config, :session
|
7
7
|
attr_reader :file_manager, :logger
|
8
|
-
attr_reader :mailer, :sftp, :s3uploader
|
9
8
|
|
10
9
|
alias_method :fm, :file_manager
|
11
10
|
|
@@ -13,12 +12,15 @@ module Eco
|
|
13
12
|
#@param session [Eco::API::Session, nil] the current session
|
14
13
|
def initialize(init = {}, session:)
|
15
14
|
init = init.conf if init.is_a?(Environment)
|
15
|
+
|
16
16
|
msg = "Expected object Eco::API::Session::Config or Environment. Given: #{init}"
|
17
17
|
raise msg unless init.is_a?(Eco::API::Session::Config)
|
18
|
-
raise "Expected an Eco::API::Session object. Given: #{session}" if session && !session.is_a?(Eco::API::Session)
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
invalid_session = session && !session.is_a?(Eco::API::Session)
|
20
|
+
raise "Expected an Eco::API::Session object. Given: #{session}" if invalid_session
|
21
|
+
|
22
|
+
@config = init
|
23
|
+
@session = session
|
22
24
|
@file_manager = Eco::API::Common::Session::FileManager.new(enviro: self)
|
23
25
|
@logger = Eco::API::Common::Session::Logger.new(enviro: self)
|
24
26
|
end
|
@@ -43,7 +45,7 @@ module Eco
|
|
43
45
|
|
44
46
|
def s3uploader
|
45
47
|
return nil unless s3uploader?
|
46
|
-
@s3uploader
|
48
|
+
@s3uploader ||= Eco::API::Common::Session::S3Uploader.new(enviro: self)
|
47
49
|
end
|
48
50
|
|
49
51
|
def s3uploader?
|
@@ -3,8 +3,11 @@ module Eco
|
|
3
3
|
module Common
|
4
4
|
module Session
|
5
5
|
class SFTP
|
6
|
-
|
7
|
-
|
6
|
+
include Eco::Language::AuxiliarLogger
|
7
|
+
|
8
|
+
def initialize(enviro:)
|
9
|
+
invalid_env = enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
|
10
|
+
raise "Required Environment object (enviro:). Given: #{enviro}" if invalid_env
|
8
11
|
@enviro = enviro
|
9
12
|
end
|
10
13
|
|
@@ -15,23 +18,22 @@ module Eco
|
|
15
18
|
# @see Net::SFTP::Session
|
16
19
|
def sftp_session
|
17
20
|
require "net/sftp"
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@sftp_session
|
21
|
+
|
22
|
+
@sftp_session ||= Net::SFTP.start(
|
23
|
+
host,
|
24
|
+
fetch_user,
|
25
|
+
**session_options
|
26
|
+
)
|
27
|
+
rescue StandardError => err
|
28
|
+
log(:error) {
|
29
|
+
"Could not open SFTP session. Possible misconfiguration: #{err}"
|
30
|
+
}
|
31
|
+
raise
|
30
32
|
end
|
31
33
|
|
32
34
|
# @see Net::SFTP::Operations::Dir#entries
|
33
35
|
def entries(path)
|
34
|
-
sftp_session.dir.entries(path).sort_by
|
36
|
+
sftp_session.dir.entries(path).sort_by(&:name)
|
35
37
|
end
|
36
38
|
|
37
39
|
# **Files** of the remote directory.
|
@@ -40,8 +42,9 @@ module Eco
|
|
40
42
|
# @param pattern [Regexp] if given, filters by using this pattern
|
41
43
|
# @return [Array<Net::SFTP::Protocol::V01::Name>]
|
42
44
|
def files(path, pattern: nil)
|
43
|
-
entries = entries(path).select
|
45
|
+
entries = entries(path).select(&:file?)
|
44
46
|
return entries unless pattern
|
47
|
+
|
45
48
|
entries.select {|remote_file| remote_file.name =~ pattern}
|
46
49
|
end
|
47
50
|
|
@@ -51,20 +54,20 @@ module Eco
|
|
51
54
|
# @param pattern [Regexp] if given, filters by using this pattern
|
52
55
|
# @return [Array<Net::SFTP::Protocol::V01::Name>]
|
53
56
|
def folders(path, pattern: nil)
|
54
|
-
entries = entries(path).select
|
57
|
+
entries = entries(path).select(&:directory?)
|
55
58
|
return entries unless pattern
|
59
|
+
|
56
60
|
entries.select {|remote_file| remote_file.name =~ pattern}
|
57
61
|
end
|
58
62
|
|
59
63
|
# @see Net::SFTP::Session#rename
|
60
|
-
def move(fullname_source, fullname_dest, flags=0x0001, override: true, &callback)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
end
|
64
|
+
def move(fullname_source, fullname_dest, flags = 0x0001, override: true, &callback)
|
65
|
+
sftp_session.rename!(fullname_source, fullname_dest, flags, &callback)
|
66
|
+
rescue Net::SFTP::StatusException => _err
|
67
|
+
raise unless override
|
68
|
+
|
69
|
+
sftp_session.remove(fullname_dest)
|
70
|
+
sftp_session.rename!(fullname_source, fullname_dest, flags, &callback)
|
68
71
|
end
|
69
72
|
|
70
73
|
# Downloads the files specified to a local folder
|
@@ -78,10 +81,29 @@ module Eco
|
|
78
81
|
dest_fullname = File.join(local_folder || ".", basename)
|
79
82
|
puts " • #{dest_fullname}"
|
80
83
|
sftp_session.download(fullname, dest_fullname)
|
81
|
-
end.each
|
82
|
-
|
83
|
-
|
84
|
+
end.each(&:wait)
|
85
|
+
# run SSH event loop while dw.active?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Upload a file to the specific `remote_folder`
|
89
|
+
def upload(local_file, remote_folder:, gid: nil)
|
90
|
+
return false unless local_file && File.exist?(local_file)
|
91
|
+
|
92
|
+
dest_file = "#{remote_folder}/#{File.basename(local_file)}"
|
93
|
+
res = sftp_session.upload!(local_file, dest_file)
|
94
|
+
|
95
|
+
unless gid.nil?
|
96
|
+
attrs = sftp_session.stat!(dest_file)
|
97
|
+
unless gid == attrs.gid
|
98
|
+
flags = {permissions: 0o660, uid: attrs.uid, gid: gid}
|
99
|
+
_stat_res = sftp_session.setstat!(dest_file, flags)
|
100
|
+
end
|
84
101
|
end
|
102
|
+
|
103
|
+
log(:info) {
|
104
|
+
"Uploaded '#{local_file}' (#{res})"
|
105
|
+
}
|
106
|
+
true
|
85
107
|
end
|
86
108
|
|
87
109
|
private
|
@@ -94,21 +116,26 @@ module Eco
|
|
94
116
|
opts.merge!({password: fetch_password})
|
95
117
|
else
|
96
118
|
opts.merge!({
|
97
|
-
keys:
|
98
|
-
keys_only:
|
119
|
+
keys: fetch_key_files,
|
120
|
+
keys_only: true
|
99
121
|
})
|
100
122
|
end
|
101
123
|
end
|
102
124
|
end
|
103
125
|
|
104
126
|
def windows_basename(remote_fullname)
|
105
|
-
|
127
|
+
dir_sep = /[\\\/]/
|
128
|
+
patr_re = /[<>:\\\/|?*]/
|
129
|
+
parts = remote_fullname.split(dir_sep).map do |node|
|
130
|
+
node.gsub(patr_re, '_')
|
131
|
+
end
|
106
132
|
local_fullname = File.join(*parts)
|
107
133
|
File.basename(local_fullname)
|
108
134
|
end
|
109
135
|
|
110
136
|
def logger
|
111
|
-
@enviro&.logger ||
|
137
|
+
@enviro&.logger ||
|
138
|
+
(defined?(super)? super : ::Logger.new(IO::NULL))
|
112
139
|
end
|
113
140
|
|
114
141
|
def config
|
@@ -6,12 +6,16 @@ module Eco
|
|
6
6
|
attr_accessor :entry
|
7
7
|
|
8
8
|
def identify(section = :person)
|
9
|
-
if entry && section == :entry
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
return entry.to_s(:identify) if entry && section == :entry
|
10
|
+
str_id = id ? "id: '#{id}'; " : ""
|
11
|
+
"'#{name}' (#{str_id}ext_id: '#{external_id}'; email: '#{email}')"
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_writer :subordinates
|
15
|
+
|
16
|
+
# 2024-03-04 patch for API property deletetion
|
17
|
+
def subordinates
|
18
|
+
@subordinates ||= 0
|
15
19
|
end
|
16
20
|
end
|
17
21
|
Ecoportal::API::V1::Person.include PersonPatch
|