eco-helpers 2.0.9 → 2.0.14
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 -66
- data/lib/eco/api/common/loaders/use_case.rb +1 -1
- data/lib/eco/api/common/people/person_entry.rb +6 -1
- data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +8 -8
- data/lib/eco/api/common/people/person_parser.rb +22 -11
- data/lib/eco/api/error.rb +5 -3
- data/lib/eco/api/organization/presets_factory.rb +145 -82
- data/lib/eco/api/organization/presets_integrity.json +52 -0
- data/lib/eco/api/organization/tag_tree.rb +20 -3
- data/lib/eco/api/session/batch.rb +19 -3
- data/lib/eco/api/session/batch/errors.rb +1 -1
- data/lib/eco/api/session/batch/feedback.rb +6 -9
- data/lib/eco/api/session/batch/job.rb +6 -2
- data/lib/eco/api/usecases.rb +2 -0
- data/lib/eco/api/usecases/default_cases/hris_case.rb +14 -8
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +41 -21
- data/lib/eco/cli.rb +11 -10
- data/lib/eco/cli/config/default/usecases.rb +2 -2
- data/lib/eco/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 697d71754e809691a39f62a86d5fc46e2988578c19c965945e1c06ea73b290b6
|
4
|
+
data.tar.gz: 01ef5ca1a9bcf941d44b5f7088f54dd9c2cba950cc562ed0516400811df60f12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b24db6ddf741e3f0dcc3f080dba19132d7926c85cf211ae0f98c090c7a3cd93f513b6e977ac21ca24d5c2092d524cc1e7ef3d04250bb29ae672400623c823964
|
7
|
+
data.tar.gz: 9585e95676aab71322af2f174d06aed7d6226502bed1e2560cfd0915643e682c02fb857c33310f7c5f1b6d083b83267d14194f0f1e315c940048ef1c3c43faff
|
data/CHANGELOG.md
CHANGED
@@ -1,32 +1,71 @@
|
|
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.14] - 2021-03-xx
|
5
5
|
|
6
6
|
### Added
|
7
|
+
- `Eco::API::UseCases::DefaultCases::ToCsvCase` added option `-internal-names` to avoid overriding data on export
|
8
|
+
- `Eco::API::Common::People::PersonEntry#mapped_entry` exposed method for raw `csv` generation
|
9
|
+
- `Eco::API::Organization::PresetsFactory` added integrity validation for `person_*` abilities
|
10
|
+
- `Eco::API::Session::Batch::Job` more debug info on erron handlers
|
11
|
+
|
7
12
|
### Changed
|
8
|
-
|
13
|
+
### Fixed
|
14
|
+
- `Eco::API::Error.get_type` was almost always matching `Eco::API::Error::Unclassified` -> fixed
|
15
|
+
|
16
|
+
## [2.0.13] - 2021-03-31
|
17
|
+
|
18
|
+
### Added
|
19
|
+
- Stats on the `Eco::API::Session::Batch`
|
20
|
+
- Allow to inherit and re-use the `Eco::API::UseCases::DefaultCase::HrisCase`
|
9
21
|
|
10
22
|
### Fixed
|
23
|
+
- Ensure auto-loading for `Eco::API::UseCases`
|
11
24
|
|
12
|
-
## [2.0.
|
25
|
+
## [2.0.12] - 2021-03-29
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
- `Eco::CLI#run` it does include any defined states on the workflow
|
29
|
+
|
30
|
+
|
31
|
+
## [2.0.11] - 2021-03-29
|
32
|
+
|
33
|
+
### Fixed
|
34
|
+
- `Eco::API::Session::Batch:Errors#errors` changed `Array#filter` call to `Array#select` call
|
35
|
+
|
36
|
+
## [2.0.10] - 2021-03-26
|
13
37
|
|
14
38
|
### Added
|
39
|
+
- `Eco::API::Common::People::PersonParser`
|
40
|
+
- `#defined_attrs`: list of all attribute defined parsers (regardless they belong to the model)
|
41
|
+
- `Eco::API::Organization::TagTree` methods
|
42
|
+
- `#total_depth` to know the total depth of a tree
|
43
|
+
- `#flat?` to know if the tagtree has only 1 level
|
44
|
+
|
15
45
|
### Changed
|
46
|
+
- `Eco::API::Common::People::PersonParser`
|
47
|
+
- Renamed `#all_attrs` to `#all_model_attrs`
|
48
|
+
- Ranamed `#defined_attrs` to `#defined_model_attrs`
|
49
|
+
- Ranamed `#undefined_attrs` to `#undefined_model_attrs`
|
50
|
+
|
51
|
+
## [2.0.9] - 2021-03-19
|
52
|
+
|
53
|
+
### Changed
|
54
|
+
- `Eco::API::Session::Batch:Errors#person_ref` moved to the public method
|
55
|
+
|
56
|
+
## [2.0.8] - 2021-03-09
|
57
|
+
|
16
58
|
### Fixed
|
17
59
|
- `Ecoportal::API::V1::Person#identity` adjust behavior
|
18
60
|
|
19
61
|
## [2.0.7] - 2021-03-09
|
20
62
|
|
21
|
-
### Added
|
22
|
-
### Changed
|
23
63
|
### Fixed
|
24
64
|
- `Eco::API::Session::Batch::JobsGroups` and `Eco::API::Session::Batch::Jobs`: when new `Batch::Job`s are creating during launch, they remained unlaunched
|
25
65
|
- this fix makes `#launch` method to iterate until there are no pending
|
26
66
|
|
27
67
|
## [2.0.6] - 2021-03-08
|
28
68
|
|
29
|
-
### Added
|
30
69
|
### Changed
|
31
70
|
- `Eco::API::Session::Batch:Errors` moved some methods to be private
|
32
71
|
### Fixed
|
@@ -34,46 +73,33 @@ All notable changes to this project will be documented in this file.
|
|
34
73
|
|
35
74
|
## [2.0.5] - 2021-02-24
|
36
75
|
|
37
|
-
### Added
|
38
|
-
### Changed
|
39
76
|
### Fixed
|
40
77
|
- `Eco::API::Common::People::PersonParser#symbol_keys` to use `Array#select`
|
41
78
|
- as `Array#filter` was introduced in ruby `2.5.5`
|
42
79
|
|
43
80
|
## [2.0.4] - 2021-02-23
|
44
81
|
|
45
|
-
### Added
|
46
82
|
### Changed
|
47
83
|
- `Eco::API::Common::People::PersonParser#defined_attrs` to include virtual attributes
|
48
84
|
|
49
|
-
### Fixed
|
50
|
-
|
51
85
|
## [2.0.3] - 2021-02-23
|
52
86
|
|
53
87
|
### Added
|
54
88
|
- `Eco::API::UseCases::OozeSamples::OozeUpdateCase`: added integration to update page instances (non-templates)
|
55
89
|
|
56
|
-
### Changed
|
57
90
|
### Fixed
|
58
91
|
- `Eco::API::Policies::DefaultPolicies::UserAccess` complete default policy code.
|
59
92
|
|
60
93
|
## [2.0.2] - 2021-02-22
|
61
94
|
|
62
|
-
### Added
|
63
95
|
### Changed
|
64
96
|
- upgraded dependencies with `ecoportal-api`
|
65
97
|
|
66
|
-
### Fixed
|
67
|
-
|
68
|
-
|
69
98
|
## [2.0.1] - 2021-02-22
|
70
99
|
|
71
|
-
### Added
|
72
100
|
### Changed
|
73
101
|
- upgraded dependencies with `ecoportal-api-oozes` to `ecoportal-api-v2`
|
74
102
|
|
75
|
-
### Fixed
|
76
|
-
|
77
103
|
## [1.5.15] - 2021-02-17
|
78
104
|
|
79
105
|
### Added
|
@@ -87,7 +113,6 @@ All notable changes to this project will be documented in this file.
|
|
87
113
|
- `Eco::API::MicroCases#people_search`
|
88
114
|
- `Eco::API::MicroCases#refresh`
|
89
115
|
|
90
|
-
### Changed
|
91
116
|
### Fixed
|
92
117
|
- `Eco::API::Policies::DefaultPolicies::UserAccess` typos in default api policy
|
93
118
|
|
@@ -109,11 +134,8 @@ All notable changes to this project will be documented in this file.
|
|
109
134
|
- `Eco::API::Common::People::PersonEntry` add error log when wrong email error is detected
|
110
135
|
- previously it would have crashed
|
111
136
|
|
112
|
-
### Fixed
|
113
|
-
|
114
137
|
## [1.5.13] - 2021-02-01
|
115
138
|
|
116
|
-
### Added
|
117
139
|
### Changed
|
118
140
|
- upgraded dependency with `ecoportal-api-oozes`
|
119
141
|
|
@@ -129,23 +151,16 @@ All notable changes to this project will be documented in this file.
|
|
129
151
|
### Changed
|
130
152
|
- upgraded `ecoportal-api` dependency
|
131
153
|
|
132
|
-
### Fixed
|
133
|
-
|
134
|
-
|
135
154
|
## [1.5.11] - 2021-01-25
|
136
155
|
|
137
156
|
### Added
|
138
157
|
- `Eco::API::Organization::TagTree#subtag?` to check if the tag is in any subtree.
|
139
158
|
|
140
|
-
### Changed
|
141
|
-
|
142
159
|
### Fixed
|
143
160
|
- `Eco::API::MicroCases#set_supervisor` shouldn't set it if the entry does not have it.
|
144
161
|
|
145
162
|
## [1.5.10] - 2021-01-19
|
146
163
|
|
147
|
-
### Added
|
148
|
-
### Changed
|
149
164
|
### Fixed
|
150
165
|
- `Eco::API::Session::Batch::Errors#print` show the row number of the input data.
|
151
166
|
|
@@ -154,14 +169,8 @@ All notable changes to this project will be documented in this file.
|
|
154
169
|
### Added
|
155
170
|
- `Eco::API::Organization::TagTree#subtags` to get all the tags but those of the highest level.
|
156
171
|
|
157
|
-
### Changed
|
158
|
-
### Fixed
|
159
|
-
|
160
|
-
|
161
172
|
## [1.5.8] - 2021-01-05
|
162
173
|
|
163
|
-
### Added
|
164
|
-
### Changed
|
165
174
|
### Fixed
|
166
175
|
- `Eco::API::Session::Batch::Jobs#job` shouldn't be calling the post-launch callback function on creation.
|
167
176
|
- `Eco::API::Session#new_job` should include a `&block` parameter.
|
@@ -169,15 +178,11 @@ All notable changes to this project will be documented in this file.
|
|
169
178
|
|
170
179
|
## [1.5.7] - 2020-12-17
|
171
180
|
|
172
|
-
### Added
|
173
|
-
### Changed
|
174
181
|
### Fixed
|
175
182
|
- `Eco::API::Sesssion#parse_attribute` was not using phase argument
|
176
183
|
|
177
184
|
## [1.5.6] - 2020-12-04
|
178
185
|
|
179
|
-
### Added
|
180
|
-
### Changed
|
181
186
|
### Fixed
|
182
187
|
- `Eco::API::UseCases::DefaultCases::RestoreDBCase` fixed typo and slightly improved
|
183
188
|
- fixed some back-end errors when chaining usecases
|
@@ -185,8 +190,6 @@ All notable changes to this project will be documented in this file.
|
|
185
190
|
|
186
191
|
## [1.5.5] - 2020-12-03
|
187
192
|
|
188
|
-
### Added
|
189
|
-
### Changed
|
190
193
|
### Fixed
|
191
194
|
- rubies previous to `2.5` do not have `yield_self`
|
192
195
|
|
@@ -194,14 +197,11 @@ All notable changes to this project will be documented in this file.
|
|
194
197
|
|
195
198
|
### Added
|
196
199
|
- update `ecoportal-api` dependency
|
197
|
-
### Changed
|
198
200
|
### Fixed
|
199
201
|
- `Eco::API::MicroCases#people_refresh` typo
|
200
202
|
|
201
203
|
## [1.5.3] - 2020-11-30
|
202
204
|
|
203
|
-
### Added
|
204
|
-
### Changed
|
205
205
|
### Fixed
|
206
206
|
- `Eco::API::Session::Batch::RequestStats#blanked_value?` better blank detection
|
207
207
|
- `Eco::API::MicroCases#with_each_starter` rectified typo
|
@@ -342,14 +342,11 @@ All notable changes to this project will be documented in this file.
|
|
342
342
|
|
343
343
|
## [1.4.2] - 2020-07-23
|
344
344
|
|
345
|
-
### Added
|
346
|
-
### Changed
|
347
345
|
### Fixed
|
348
346
|
- preserve backtrace on logging
|
349
347
|
|
350
348
|
## [1.4.0] - 2020-07-14
|
351
349
|
|
352
|
-
### Added
|
353
350
|
### Changed
|
354
351
|
- change abilities to align with ecoPortal release `1.5.0`
|
355
352
|
- remove some patches on `ecoportal-api`
|
@@ -359,22 +356,17 @@ All notable changes to this project will be documented in this file.
|
|
359
356
|
|
360
357
|
## [1.3.19] - 2020-07-23
|
361
358
|
|
362
|
-
### Added
|
363
|
-
### Changed
|
364
359
|
### Fixed
|
365
360
|
- preserve backtrace on logging
|
366
361
|
|
367
362
|
## [1.3.18] - 2020-07-08
|
368
363
|
|
369
|
-
### Added
|
370
|
-
### Changed
|
371
364
|
### Fixed
|
372
365
|
- the `update` case was missing the code to use the `default_usergroup`
|
373
366
|
|
374
367
|
|
375
368
|
## [1.3.17] - 2020-07-06
|
376
369
|
|
377
|
-
### Added
|
378
370
|
### Changed
|
379
371
|
- the `hris` case should not only include as `leavers` those that have account, but anyone that leaves
|
380
372
|
* as we could have active people with no account
|
@@ -397,7 +389,6 @@ All notable changes to this project will be documented in this file.
|
|
397
389
|
### Added
|
398
390
|
- default usecase to export to `csv` (`-detailed`) now includes `"Supervisor Name"` column
|
399
391
|
### Changed
|
400
|
-
### Fixed
|
401
392
|
|
402
393
|
## [1.3.14] - 2020-06-10
|
403
394
|
|
@@ -405,33 +396,24 @@ All notable changes to this project will be documented in this file.
|
|
405
396
|
- `Eco::API::Common::People::SupervisorHelpers` now has its methods as class methods
|
406
397
|
### Changed
|
407
398
|
- upgraded `ecoportal-api` gem dependency to minimum version `0.5.6`
|
408
|
-
### Fixed
|
409
399
|
|
410
400
|
|
411
401
|
## [1.3.13] - 2020-05-29
|
412
402
|
|
413
|
-
### Added
|
414
|
-
### Changed
|
415
403
|
### Fixed
|
416
404
|
- `Eco::API::Organization::TagTree#tag?` to accept `nil` by returning `false`
|
417
405
|
- `Eco::API::Common::People::DefaultParsers::DateParser` will parse to `Date` class
|
418
406
|
* it was parsing to `Time` class, while the native gem `ecoportal-api` parses as `Date` ([reference](https://gitlab.com/ecoPortal/ecoportal-api/-/blob/master/lib/ecoportal/api/v1/schema_field.rb))
|
419
407
|
## [1.3.12] - 2020-05-19
|
420
408
|
|
421
|
-
### Added
|
422
409
|
### Changed
|
423
410
|
- stop using `email` as `external_id` on `People#person` & `People#find`
|
424
411
|
* this should result in more accurate searches when using `:strict` options
|
425
|
-
### Fixed
|
426
|
-
|
427
412
|
|
428
413
|
## [1.3.11] - 2020-05-12
|
429
414
|
|
430
|
-
### Added
|
431
415
|
### Changed
|
432
416
|
- remove popping up comments on `Eco::API::Organization::PolicyGroups#`
|
433
|
-
### Fixed
|
434
|
-
|
435
417
|
|
436
418
|
## [1.3.10] - 2020-05-12
|
437
419
|
|
@@ -440,14 +422,11 @@ All notable changes to this project will be documented in this file.
|
|
440
422
|
- `config.people.default_usergroup`, when defined, will have effect on usecases: `update` (this case was missing the change)
|
441
423
|
* on account creation, if the input file did not specify `policy_group_ids`
|
442
424
|
|
443
|
-
### Changed
|
444
425
|
### Fixed
|
445
426
|
- `upsert`, `hris` and `create` usecases: fixed condition for use of default_usergroup
|
446
427
|
|
447
428
|
## [1.3.9] - 2020-05-12
|
448
429
|
|
449
|
-
### Added
|
450
|
-
### Changed
|
451
430
|
### Fixed
|
452
431
|
|
453
432
|
- `usecase` callback was not receiving `usecase` paramater
|
@@ -8,7 +8,7 @@ module Eco
|
|
8
8
|
# @return [Symbol] the `type` of usecase (i.e. `:sync`, `:transform`, `:import`, `:other`)
|
9
9
|
def type(value = nil)
|
10
10
|
unless value
|
11
|
-
return @type || raise("You should specify a type of case [:sync, :transform, :import, :other] for #{self
|
11
|
+
return @type || raise("You should specify a type of case [:sync, :transform, :import, :other] for #{self}")
|
12
12
|
end
|
13
13
|
@type = value
|
14
14
|
end
|
@@ -57,6 +57,11 @@ module Eco
|
|
57
57
|
@internal_entry
|
58
58
|
end
|
59
59
|
|
60
|
+
# @return [Hash] entry `Hash` with **internal** attribute names, but **external** types and values.
|
61
|
+
def mapped_entry
|
62
|
+
@mapped_entry
|
63
|
+
end
|
64
|
+
|
60
65
|
# @note values ready to be set to a person.
|
61
66
|
# @return [Hash] entry `Hash` with **internal** attribute names, values and types.
|
62
67
|
def final_entry
|
@@ -256,7 +261,7 @@ module Eco
|
|
256
261
|
# @param mapped_entry [Hash] that with **internal** names but **external** values and types.
|
257
262
|
# @return [Hash] with **external** names, values and types.
|
258
263
|
def _external_serializing(mapped_entry)
|
259
|
-
target_attrs = @emap.
|
264
|
+
target_attrs = @emap.all_model_attrs | @emap.aliased_attrs
|
260
265
|
rest_keys = mapped_entry.keys - target_attrs
|
261
266
|
target_attrs -= ["send_invites"]
|
262
267
|
external_entry = target_attrs.each_with_object({}) do |attr, hash|
|
@@ -6,14 +6,14 @@ module Eco
|
|
6
6
|
# @attr_reader core_attrs [Array<String>] core attributes that are present in the person entry.
|
7
7
|
# @attr_reader details_attrs [Array<String>] schema details attributes that are present in the person entry.
|
8
8
|
# @attr_reader account_attrs [Array<String>] account attributes that are present in the person entry.
|
9
|
-
# @attr_reader
|
9
|
+
# @attr_reader all_model_attrs [Array<String>] all the attrs that are present in the person entry.
|
10
10
|
# @attr_reader internal_attrs [Array<String>] all the internally named attributes that the person entry has.
|
11
11
|
# @attr_reader aliased_attrs [Array<String>] only those internal attributes present in the person entry that have an internal/external name mapping.
|
12
12
|
# @attr_reader direct_attrs [Array<String>] only those internal attributes present in the person entry that do **not** have an internal/external name mapping.
|
13
13
|
class PersonEntryAttributeMapper
|
14
14
|
@@cached_warnings = {}
|
15
15
|
|
16
|
-
attr_reader :core_attrs, :details_attrs, :account_attrs, :
|
16
|
+
attr_reader :core_attrs, :details_attrs, :account_attrs, :all_model_attrs
|
17
17
|
attr_reader :internal_attrs, :aliased_attrs, :direct_attrs
|
18
18
|
|
19
19
|
# Helper class tied to `PersonEntry` that allows to track which attributes of a person entry are present
|
@@ -41,14 +41,14 @@ module Eco
|
|
41
41
|
init_attr_trackers
|
42
42
|
else # SERIALIZING
|
43
43
|
@person = data
|
44
|
-
@internal_attrs = @person_parser.
|
44
|
+
@internal_attrs = @person_parser.all_model_attrs
|
45
45
|
@aliased_attrs = @attr_map.list(:internal)
|
46
46
|
end
|
47
47
|
|
48
48
|
@core_attrs = @person_parser.target_attrs_core(@internal_attrs)
|
49
49
|
@details_attrs = @person_parser.target_attrs_details(@internal_attrs)
|
50
50
|
@account_attrs = @person_parser.target_attrs_account(@internal_attrs)
|
51
|
-
@
|
51
|
+
@all_model_attrs = @core_attrs | @account_attrs | @details_attrs
|
52
52
|
end
|
53
53
|
|
54
54
|
# To know if currently the object is in parse or serialize mode.
|
@@ -98,7 +98,7 @@ module Eco
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
return nil unless @person_parser.
|
101
|
+
return nil unless @person_parser.all_model_attrs.include?(attr)
|
102
102
|
end
|
103
103
|
|
104
104
|
# Serializing helper also used to do a reverse mapping when parsing:
|
@@ -146,9 +146,9 @@ module Eco
|
|
146
146
|
# when parsing:
|
147
147
|
def init_attr_trackers
|
148
148
|
# (def) all internal attributes we can expect
|
149
|
-
def_all_attrs = @person_parser.
|
149
|
+
def_all_attrs = @person_parser.all_model_attrs
|
150
150
|
# (def) internal attrs with no aliasing nor parser definition (expected to be direct)
|
151
|
-
def_unlinked = @person_parser.
|
151
|
+
def_unlinked = @person_parser.undefined_model_attrs.select { |attr| !to_external(attr) }
|
152
152
|
# (def) those with parser or alias:
|
153
153
|
def_linked = def_all_attrs - def_unlinked
|
154
154
|
|
@@ -168,7 +168,7 @@ module Eco
|
|
168
168
|
# (data) virtual internal attrs (the internal names of those virtual attrs)
|
169
169
|
data_vi_int_aliased = data_vi_ext_alias.map do |attr|
|
170
170
|
# to_internal(attr) can't be used here, becauase virtual fields would get filtered out,
|
171
|
-
# as they are not recognized by @parser.
|
171
|
+
# as they are not recognized by @parser.all_model_attrs.include?(attr)
|
172
172
|
@attr_map.to_internal(attr)
|
173
173
|
end.compact
|
174
174
|
|
@@ -7,7 +7,7 @@ module Eco
|
|
7
7
|
#
|
8
8
|
# @attr_reader schema [Ecoportal::API::V1::PersonSchema, nil] schema of person details that this parser will be based upon.
|
9
9
|
# @attr_reader details_attrs [Array<String>] internal names of schema details attributes.
|
10
|
-
# @attr_reader
|
10
|
+
# @attr_reader all_model_attrs [Array<String>] all the internal name attributes, including _core_, _account_ and _details_.
|
11
11
|
class PersonParser
|
12
12
|
extend Eco::API::Common::ClassAutoLoader
|
13
13
|
autoloads_children_of "Eco::API::Common::Loaders::Parser"
|
@@ -19,8 +19,7 @@ module Eco
|
|
19
19
|
FORMAT = [:csv, :xml, :json]
|
20
20
|
|
21
21
|
attr_reader :schema
|
22
|
-
attr_reader :details_attrs, :
|
23
|
-
attr_reader :defined_attrs
|
22
|
+
attr_reader :details_attrs, :all_model_attrs
|
24
23
|
attr_reader :patch_version
|
25
24
|
|
26
25
|
# @example Example of usage:
|
@@ -46,7 +45,7 @@ module Eco
|
|
46
45
|
@details_attrs = @schema&.fields.map { |fld| fld.alt_id }
|
47
46
|
end
|
48
47
|
|
49
|
-
@
|
48
|
+
@all_model_attrs = CORE_ATTRS + ACCOUNT_ATTRS + @details_attrs
|
50
49
|
self.class.autoload_children(self)
|
51
50
|
end
|
52
51
|
|
@@ -60,6 +59,11 @@ module Eco
|
|
60
59
|
|
61
60
|
# @!group Scopping attributes (identifying, presence & active)
|
62
61
|
|
62
|
+
# All the internal name attributes, including _core_, _account_ and _details_.
|
63
|
+
def all_attrs(include_defined_parsers: false)
|
64
|
+
all_model_attrs | defined_model_attrs
|
65
|
+
end
|
66
|
+
|
63
67
|
# Scopes `source_attrs` using the _**core** attributes_.
|
64
68
|
# @note use this helper to know which among your attributes are **core** ones.
|
65
69
|
# @param source_attrs [Array<String>]
|
@@ -93,14 +97,21 @@ module Eco
|
|
93
97
|
@parsers.keys
|
94
98
|
end
|
95
99
|
|
100
|
+
# Returns a list of all the internal attributes that have a parser defined.
|
101
|
+
# @note These attributes do not necessarily belong to the model. They could be virtual attributes
|
102
|
+
# @return [Array<String>] list of all attribute defined parsers.
|
103
|
+
def defined_attrs
|
104
|
+
defined_list - symbol_keys
|
105
|
+
end
|
106
|
+
|
96
107
|
# Returns a list of all the internal attributes of the model that have a parser defined.
|
97
108
|
# @note
|
98
109
|
# - it excludes any parser that is not in the model, such as type parsers (i.e. `:boolean`, `:multiple`)
|
99
110
|
# - the list is sorted according `CORE_ATTRS` + `ACCOUNT_ATTRS` + schema attrs
|
100
|
-
# @return [Array<String>] list of all attribute defined parsers.
|
101
|
-
def
|
111
|
+
# @return [Array<String>] list of all attribute defined parsers in the model.
|
112
|
+
def defined_model_attrs
|
102
113
|
defined = @parsers.keys
|
103
|
-
defined = (
|
114
|
+
defined = (all_model_attrs | defined) & defined
|
104
115
|
defined - symbol_keys
|
105
116
|
end
|
106
117
|
|
@@ -118,7 +129,7 @@ module Eco
|
|
118
129
|
# @param process [Symbol] either `:parse` or `:serialize`, depending if we want to parse or serialize the `attr`.
|
119
130
|
# @return [Array<String>] list of all attribute defined parsers that should be active for the given `source_data`.
|
120
131
|
def active_attrs(source_data, phase = :any, process: :parse)
|
121
|
-
|
132
|
+
defined_model_attrs.select do |attr|
|
122
133
|
if process == :serialize
|
123
134
|
@parsers[attr].serializer_active?(phase)
|
124
135
|
else
|
@@ -130,8 +141,8 @@ module Eco
|
|
130
141
|
# Returns a list of all the internal attributes of the model that do **not** have a parser defined.
|
131
142
|
# @note it excludes any parser that is **not** in the model, such as type parsers (i.e. :boolean, :multiple)
|
132
143
|
# @return [Array<String>] list of all attributes without a defined parser.
|
133
|
-
def
|
134
|
-
|
144
|
+
def undefined_model_attrs
|
145
|
+
all_model_attrs - defined_model_attrs
|
135
146
|
end
|
136
147
|
|
137
148
|
# @param attr [String] internal name of an attribute.
|
@@ -238,7 +249,7 @@ module Eco
|
|
238
249
|
end
|
239
250
|
|
240
251
|
def valid_attr?(attr)
|
241
|
-
attr.is_a?(String) && (!@schema || @
|
252
|
+
attr.is_a?(String) && (!@schema || @all_model_attrs.include?(attr))
|
242
253
|
end
|
243
254
|
|
244
255
|
def valid_type?(attr)
|
data/lib/eco/api/error.rb
CHANGED
@@ -80,6 +80,7 @@ module Eco
|
|
80
80
|
next 1 if k1 < k2
|
81
81
|
0
|
82
82
|
end.tap do |siblings|
|
83
|
+
siblings.delete(Unclassified)
|
83
84
|
if direct
|
84
85
|
siblings.reject! do |si|
|
85
86
|
siblings.any? {|s| si < s}
|
@@ -96,17 +97,18 @@ module Eco
|
|
96
97
|
err_msg =~ @match
|
97
98
|
end
|
98
99
|
|
99
|
-
def get_type(err_msg)
|
100
|
+
def get_type(err_msg, first: true)
|
100
101
|
type = nil
|
101
102
|
descendants(direct: true).reverse.each do |klass|
|
102
103
|
if klass.err_match?(err_msg)
|
103
104
|
type = klass
|
104
105
|
if klass.descendants?(direct: true)
|
105
|
-
type = klass.get_type(err_msg) || type
|
106
|
+
type = klass.get_type(err_msg, first: false) || type
|
106
107
|
end
|
107
108
|
end
|
108
109
|
end
|
109
|
-
type
|
110
|
+
return type unless first
|
111
|
+
type || Unclassified
|
110
112
|
end
|
111
113
|
|
112
114
|
def known_err_class?(klass)
|
@@ -4,38 +4,27 @@ module Eco
|
|
4
4
|
|
5
5
|
class PresetsFactory
|
6
6
|
ABILITIES = File.join(__dir__, 'presets_values.json')
|
7
|
+
INTEGRITY = File.join(__dir__, 'presets_integrity.json')
|
7
8
|
DEFAULT_CUSTOM = 'presets_custom.json'
|
8
9
|
DEFAULT_MAP = 'presets_map.json'
|
9
10
|
|
10
11
|
def initialize(presets_custom: DEFAULT_CUSTOM, presets_map: DEFAULT_MAP, enviro: nil, policy_groups: nil)
|
11
|
-
@abilities = JSON.load(File.open(ABILITIES))
|
12
|
-
@habilities = @abilities.map do |key, values|
|
13
|
-
h_values = values.map { |v| [v, true] }.to_h
|
14
|
-
[key, h_values]
|
15
|
-
end.to_h
|
16
|
-
|
17
12
|
fatal("Expecting Environment object. Given: #{enviro}") if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
|
18
|
-
@enviro
|
19
|
-
|
20
|
-
policy_groups = policy_groups || @enviro&.api&.policy_groups.to_a
|
21
|
-
if policy_groups.is_a?(Eco::API::Organization::PolicyGroups)
|
22
|
-
@policy_groups = policy_groups
|
23
|
-
else
|
24
|
-
@policy_groups = Eco::API::Organization::PolicyGroups.new(policy_groups)
|
25
|
-
end
|
13
|
+
@enviro = enviro
|
26
14
|
|
27
|
-
|
28
|
-
|
15
|
+
@policy_groups = policy_groups
|
16
|
+
@presets_custom_file = presets_custom || DEFAULT_CUSTOM
|
17
|
+
@presets_map_file = presets_map || DEFAULT_MAP
|
29
18
|
end
|
30
19
|
|
31
20
|
def new(*policy_group_ids_or_names)
|
32
21
|
|
33
22
|
names = policy_group_ids_or_names.map do |id_name|
|
34
|
-
|
23
|
+
policy_groups.to_name(id_name)&.downcase
|
35
24
|
end.compact
|
36
25
|
|
37
|
-
if
|
38
|
-
preset_names = names.map { |name|
|
26
|
+
if presets_map
|
27
|
+
preset_names = names.map { |name| presets_map.fetch(name, nil) }
|
39
28
|
else # option to do not use preset mapping (so just the policy group name)
|
40
29
|
preset_names = names
|
41
30
|
end
|
@@ -44,69 +33,11 @@ module Eco
|
|
44
33
|
|
45
34
|
# @return [Array<String>] all the abilities
|
46
35
|
def keys
|
47
|
-
|
36
|
+
abilities_model.keys
|
48
37
|
end
|
49
38
|
|
50
39
|
private
|
51
40
|
|
52
|
-
def init_custom(file = DEFAULT_CUSTOM)
|
53
|
-
@presets_custom = nil
|
54
|
-
|
55
|
-
return if !file
|
56
|
-
file = File.expand_path(file)
|
57
|
-
|
58
|
-
if File.exists?(file)
|
59
|
-
@presets_custom = JSON.load(File.open(file))
|
60
|
-
|
61
|
-
errors = @presets_custom.map do |key, preset|
|
62
|
-
(err = preset_errors(preset)) ? "{ '#{key}' preset -> #{err}}": nil
|
63
|
-
end.compact
|
64
|
-
|
65
|
-
fatal("File '#{file}' contains invalid presets:\n #{errors.join("\n ")}") if errors.length > 0
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def init_map(file = DEFAULT_MAP)
|
71
|
-
@presets_map = nil
|
72
|
-
|
73
|
-
return if !file
|
74
|
-
file = File.expand_path(file)
|
75
|
-
|
76
|
-
if File.exists?(file)
|
77
|
-
fatal("Maps file specified without custom presets file. Aborting!") if !@presets_custom
|
78
|
-
@presets_map = JSON.load(File.open(file))
|
79
|
-
|
80
|
-
errors = []
|
81
|
-
if @policy_groups.length > 0
|
82
|
-
errors = @policy_groups.map do |pg|
|
83
|
-
exists = @presets_map[pg.name.downcase] || @presets_custom[pg.name.downcase]
|
84
|
-
exists ? nil : "'#{pg.name}'"
|
85
|
-
end.compact
|
86
|
-
|
87
|
-
warn("No maps or no preset for policy group(s): #{errors.join(", ")}") if errors.length > 0
|
88
|
-
end
|
89
|
-
|
90
|
-
errors = @presets_map.map do |source, dest|
|
91
|
-
@presets_custom[dest] ? nil : "'#{dest}'"
|
92
|
-
end.compact
|
93
|
-
|
94
|
-
warn("Unexisting mapped preset(s): #{errors.uniq.join(", ")}") if errors.length > 0
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
def fatal(msg)
|
100
|
-
raise msg if !@enviro
|
101
|
-
@enviro.logger.fatal(msg)
|
102
|
-
raise msg
|
103
|
-
end
|
104
|
-
|
105
|
-
def warn(msg)
|
106
|
-
raise msg if !@enviro
|
107
|
-
@enviro.logger.warn(msg)
|
108
|
-
end
|
109
|
-
|
110
41
|
def compile(*preset_names)
|
111
42
|
fatal("You need to specify an existing file for the custom presets.") if !@presets_custom
|
112
43
|
@presets_custom.values_at(*preset_names).compact.reduce({}) do |p1, p2|
|
@@ -117,7 +48,7 @@ module Eco
|
|
117
48
|
def merge(preset1, preset2)
|
118
49
|
keys = preset1.keys | preset2.keys
|
119
50
|
|
120
|
-
|
51
|
+
abilities_model.each_with_object({}) do |(key, values), result|
|
121
52
|
next unless keys.include?(key)
|
122
53
|
idx = [
|
123
54
|
values.index(preset1[key]),
|
@@ -129,17 +60,149 @@ module Eco
|
|
129
60
|
|
130
61
|
# unsused: only play with the given abilities
|
131
62
|
def empty_model
|
132
|
-
JSON.parse(
|
63
|
+
JSON.parse(abilities_model.to_json).transform_values {|v| nil }
|
133
64
|
end
|
134
65
|
|
135
66
|
def preset_errors(preset)
|
136
67
|
return "No preset given" if !preset
|
137
68
|
errors = preset.map do |k, v|
|
138
|
-
|
69
|
+
value_exists?(k, v) ? nil : "#{k}:#{v}"
|
139
70
|
end.compact
|
140
|
-
return "
|
71
|
+
return " Unknown: {#{errors.join(", ")}}" if errors.length > 0
|
141
72
|
nil
|
142
73
|
end
|
74
|
+
|
75
|
+
def preset_integrity(preset)
|
76
|
+
preset.each_with_object([]) do |(ability, value), errors|
|
77
|
+
next unless checks = integrity_model[ability]
|
78
|
+
|
79
|
+
suberrors = []
|
80
|
+
|
81
|
+
checks.each do |check|
|
82
|
+
next unless check["value"] == value
|
83
|
+
check["conditions"].each do |cond, targets|
|
84
|
+
case cond
|
85
|
+
when "at_least"
|
86
|
+
targets.each do |other, minimum|
|
87
|
+
unless (ability_value_idx(other, minimum) <= ability_value_idx(other, preset[other]))
|
88
|
+
suberrors << "'#{other}' should be at least '#{minimum}'"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
when "one_of"
|
92
|
+
unless targets.any? {|other, expected| preset[other] == expected}
|
93
|
+
suberrors << targets.each_with_object([]) do |(other, expected), out|
|
94
|
+
out << "'#{other}': '#{expected}'"
|
95
|
+
end.join(", ").yield_self do |msg|
|
96
|
+
"there should be at least one of: {#{msg}}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
else
|
100
|
+
warn("Unsuported integrity condition statement '#{cond}' in '#{ability}' with level '#{value}'")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if suberrors.length > 0
|
106
|
+
errors << "Incorrect value '#{value}' for '#{ability}' - reasons: {#{suberrors.join(", ")}}"
|
107
|
+
end
|
108
|
+
end.yield_self do |errors|
|
109
|
+
" Integrity errors: { #{errors.join(", ")} }" if errors.length > 0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def integrity_model
|
114
|
+
@integrity_model ||= JSON.load(File.open(INTEGRITY))
|
115
|
+
end
|
116
|
+
|
117
|
+
def value_exists?(ability, value)
|
118
|
+
abilities_model_inverted.dig(ability, value)
|
119
|
+
end
|
120
|
+
|
121
|
+
def abilities_model_inverted
|
122
|
+
@abilities_model_inverted ||= abilities_model.each_with_object({}) do |(key, values), out|
|
123
|
+
out[key] = values.each_with_object({}) {|v, h| h[v] = true }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def ability_value_idx(ability, value)
|
128
|
+
abilities_model[ability].index(value)
|
129
|
+
end
|
130
|
+
|
131
|
+
def abilities_model
|
132
|
+
@abilities_model ||= JSON.load(File.open(ABILITIES))
|
133
|
+
end
|
134
|
+
|
135
|
+
def policy_groups
|
136
|
+
return @policy_groups if @policy_groups.is_a?(Eco::API::Organization::PolicyGroups)
|
137
|
+
@policy_groups ||= @enviro&.api&.policy_groups.to_a
|
138
|
+
|
139
|
+
unless @policy_groups.is_a?(Eco::API::Organization::PolicyGroups)
|
140
|
+
@policy_groups = Eco::API::Organization::PolicyGroups.new(@policy_groups)
|
141
|
+
end
|
142
|
+
@policy_groups
|
143
|
+
end
|
144
|
+
|
145
|
+
def presets_custom
|
146
|
+
return @presets_custom if instance_variable_defined?(:@presets_custom)
|
147
|
+
@presets_custom = nil
|
148
|
+
if @presets_custom_file
|
149
|
+
if (file = File.expand_path(@presets_custom_file)) && File.exists?(file)
|
150
|
+
@presets_custom = JSON.load(File.open(file)).tap do |custom_presets|
|
151
|
+
errors = custom_presets.each_with_object([]) do |(key, preset), errors|
|
152
|
+
if err = preset_errors(preset)
|
153
|
+
errors << "{ '#{key}' preset -> #{err}}"
|
154
|
+
end
|
155
|
+
if err = preset_integrity(preset)
|
156
|
+
errors << "{ '#{key}' preset -> #{err}}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
fatal("File '#{file}' contains invalid presets:\n #{errors.join("\n ")}") if errors.length > 0
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def presets_map
|
167
|
+
return @presets_map if instance_variable_defined?(:@presets_map)
|
168
|
+
@presets_map = nil
|
169
|
+
if @presets_map_file
|
170
|
+
if (file = File.expand_path(@presets_map_file)) && File.exists?(file)
|
171
|
+
fatal("Maps file specified without 'presets_custom.json' file. Aborting!") if !presets_custom
|
172
|
+
@presets_map = JSON.load(File.open(file)).tap do |map_presets|
|
173
|
+
|
174
|
+
errors = []
|
175
|
+
if policy_groups.length > 0
|
176
|
+
errors = policy_groups.map do |pg|
|
177
|
+
exists = map_presets[pg.name.downcase] || presets_custom[pg.name.downcase]
|
178
|
+
exists ? nil : "'#{pg.name}'"
|
179
|
+
end.compact
|
180
|
+
|
181
|
+
warn("No maps or no preset for policy group(s): #{errors.join(", ")}") if errors.length > 0
|
182
|
+
end
|
183
|
+
|
184
|
+
errors = map_presets.map do |source, dest|
|
185
|
+
presets_custom[dest] ? nil : "'#{dest}'"
|
186
|
+
end.compact
|
187
|
+
|
188
|
+
warn("Unexisting mapped preset(s): #{errors.uniq.join(", ")}") if errors.length > 0
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def fatal(msg)
|
196
|
+
raise msg if !@enviro
|
197
|
+
@enviro.logger.fatal(msg)
|
198
|
+
raise msg
|
199
|
+
end
|
200
|
+
|
201
|
+
def warn(msg)
|
202
|
+
raise msg if !@enviro
|
203
|
+
@enviro.logger.warn(msg)
|
204
|
+
end
|
205
|
+
|
143
206
|
end
|
144
207
|
|
145
208
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
{
|
2
|
+
"person_core_create": [
|
3
|
+
{ "value": "create", "conditions": {
|
4
|
+
"at_least": {"person_core": "view_people_manager"}
|
5
|
+
}
|
6
|
+
}
|
7
|
+
],
|
8
|
+
"person_core_edit": [
|
9
|
+
{ "value": "edit", "conditions": {
|
10
|
+
"at_least": {"person_core": "view_people_manager"}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
],
|
14
|
+
"person_details": [
|
15
|
+
{ "value": "view", "conditions": {
|
16
|
+
"at_least": {"person_core": "attach"}
|
17
|
+
}
|
18
|
+
},
|
19
|
+
{ "value": "edit_public", "conditions": {
|
20
|
+
"one_of": {
|
21
|
+
"person_core_edit": "edit",
|
22
|
+
"person_core_create": "create"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
},
|
26
|
+
{ "value": "view_private", "conditions": {
|
27
|
+
"at_least": {"person_core": "attach" }
|
28
|
+
}
|
29
|
+
},
|
30
|
+
{ "value": "edit_private", "conditions": {
|
31
|
+
"one_of": {
|
32
|
+
"person_core_edit": "edit",
|
33
|
+
"person_core_create": "create"
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
],
|
38
|
+
"person_account": [
|
39
|
+
{ "value": "view", "conditions": {
|
40
|
+
"at_least": {"person_core": "attach" }
|
41
|
+
}
|
42
|
+
},
|
43
|
+
{ "value": "create", "conditions": {
|
44
|
+
"at_least": {"person_core_create": "create"}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
{ "value": "edit", "conditions": {
|
48
|
+
"at_least": {"person_core_edit": "edit"}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
]
|
52
|
+
}
|
@@ -4,7 +4,7 @@ module Eco
|
|
4
4
|
|
5
5
|
# Provides helpers to deal with tagtrees.
|
6
6
|
class TagTree
|
7
|
-
attr_reader :tag, :nodes
|
7
|
+
attr_reader :tag, :nodes, :children_count
|
8
8
|
attr_reader :depth, :path
|
9
9
|
attr_reader :enviro
|
10
10
|
|
@@ -37,6 +37,7 @@ module Eco
|
|
37
37
|
|
38
38
|
nodes = @source.is_a?(Array) ? @source : @source.dig('nodes') || []
|
39
39
|
@nodes = nodes.map {|cnode| TagTree.new(cnode, depth: @depth + 1, path: @path.dup, enviro: @enviro)}
|
40
|
+
@children_count = @nodes.count
|
40
41
|
|
41
42
|
init_hashes
|
42
43
|
end
|
@@ -46,6 +47,21 @@ module Eco
|
|
46
47
|
@has_tags.empty?
|
47
48
|
end
|
48
49
|
|
50
|
+
# @return [Integer] the highest `depth` of all the children.
|
51
|
+
def total_depth
|
52
|
+
@total_depth ||= if children_count > 0
|
53
|
+
deepest_node = nodes.max_by {|node| node.total_depth}
|
54
|
+
deepest_node.depth
|
55
|
+
else
|
56
|
+
depth
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Integer] if there's only top level.
|
61
|
+
def flat?
|
62
|
+
self.total_depth <= 0
|
63
|
+
end
|
64
|
+
|
49
65
|
# Gets all the tags of the current node tree.
|
50
66
|
# @note
|
51
67
|
# - this will include the upper level tag(s) as well
|
@@ -147,7 +163,8 @@ module Eco
|
|
147
163
|
# * take the deepest tag (the one that is further down in the tree)
|
148
164
|
# * if there are different options (several nodes at the same depth):
|
149
165
|
# * take the common node between them (i.e. you have Hamilton and Auckland -> take New Zealand)
|
150
|
-
# * if there's no common node between them, take the `first
|
166
|
+
# * if there's no common node between them, take the `first`, unless they are at top level of the tree
|
167
|
+
# * to the above, take the `first` also on top level, but only if there's 1 level for the entire tree
|
151
168
|
# @param [Array<String>] values list of tags.
|
152
169
|
# @return [String] default tag.
|
153
170
|
def default_tag(*values)
|
@@ -169,7 +186,7 @@ module Eco
|
|
169
186
|
common = nodes.reduce(self.tags.reverse) {|com, cnode| com & cnode.path.reverse}
|
170
187
|
default_tag = common.first if common.length > 0 && depth > 0
|
171
188
|
end
|
172
|
-
default_tag = nodes.first&.tag
|
189
|
+
default_tag = nodes.first&.tag if !default_tag && ( (depth > 0) || flat?)
|
173
190
|
default_tag
|
174
191
|
end
|
175
192
|
|
@@ -105,10 +105,15 @@ module Eco
|
|
105
105
|
iterations = (data.length.to_f / per_page).ceil
|
106
106
|
|
107
107
|
Eco::API::Session::Batch::Status.new(enviro, queue: data, method: method).tap do |status|
|
108
|
+
start_time = Time.now
|
109
|
+
start_slice = Time.now; slice = []
|
108
110
|
data.each_slice(per_page) do |slice|
|
109
|
-
msg
|
111
|
+
msg = "starting batch '#{method}' iteration #{iteration}/#{iterations},"
|
112
|
+
msg += " with #{slice.length} entries of #{data.length} -- #{done} done"
|
113
|
+
msg += " (last: #{str_stats(start_slice, slice.length)}; total: #{str_stats(start_time, done)})"
|
110
114
|
logger.info(msg) unless silent
|
111
115
|
|
116
|
+
start_slice = Time.now
|
112
117
|
people_api.batch do |batch|
|
113
118
|
slice.each do |person|
|
114
119
|
batch.public_send(method, person) do |response|
|
@@ -118,12 +123,23 @@ module Eco
|
|
118
123
|
end
|
119
124
|
end # next batch
|
120
125
|
|
121
|
-
iteration
|
122
|
-
done
|
126
|
+
iteration += 1
|
127
|
+
done += slice.length
|
123
128
|
end # next slice
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
132
|
+
def str_stats(start, count)
|
133
|
+
now = Time.now
|
134
|
+
secs = (now - start).round(3)
|
135
|
+
if secs > 0.0
|
136
|
+
per_sec = (count.to_f / secs).round(2)
|
137
|
+
"#{secs}s -> #{per_sec} people/s"
|
138
|
+
else
|
139
|
+
" -- "
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
127
143
|
end
|
128
144
|
end
|
129
145
|
end
|
@@ -124,7 +124,7 @@ module Eco
|
|
124
124
|
# - please, observe that this can only happen if there were repeated entries in the `source_queue`
|
125
125
|
# @return [Array<Hash>, Array<Ecoportal::API::V1::Person>, Array<Ecoportal::API::Internal::Person>]
|
126
126
|
def entries
|
127
|
-
queue.
|
127
|
+
queue.select.with_index do |query, i|
|
128
128
|
unless response = status[i]
|
129
129
|
msg = "Error: query with no response. You might have duplicated entries in your queue.\n"
|
130
130
|
msg += "Queue length: #{queue.length}; Queue elements class: #{queue.first.class}\n"
|
@@ -45,25 +45,22 @@ module Eco
|
|
45
45
|
# @!group Pure feedback methods
|
46
46
|
|
47
47
|
# Slightly modifies the behaviour of `Ecoportal::API::Common::BaseModel#as_update`, so schema details fields show the `alt_id`
|
48
|
+
# It also fixes possible patch updates that are incomplete or unnecessary.
|
48
49
|
# @note for better feedback
|
49
50
|
# @param entry [Hash, Ecoportal::API::V1::Person, Ecoportal::API::Internal::Person]
|
50
|
-
|
51
|
+
# @param add_feedback [Boolean] if `true` it tweak the hash update with additional data.
|
52
|
+
def as_update(entry, add_feedback: true)
|
51
53
|
case
|
52
54
|
when entry.is_a?(Hash)
|
53
55
|
hash = entry
|
54
56
|
else #entry.is_a?(Ecoportal::API::V1::Person)
|
55
57
|
if only_ids?
|
56
|
-
hash = {
|
57
|
-
"id" => entry.id,
|
58
|
-
"external_id" => entry.external_id,
|
59
|
-
"email" => entry.email
|
60
|
-
}
|
61
58
|
hash = entry.as_json.slice("id", "external_id", "email")
|
62
59
|
else
|
63
60
|
hash = entry.as_update
|
64
|
-
|
65
|
-
if hash["details"]
|
66
|
-
if hfields =
|
61
|
+
|
62
|
+
if add_feedback && details = hash["details"]
|
63
|
+
if hfields = details["fields"]
|
67
64
|
hfields.each do |fld|
|
68
65
|
fld.merge!("alt_id" => entry.details.get_field(fld["id"]).alt_id)
|
69
66
|
end
|
@@ -169,7 +169,8 @@ module Eco
|
|
169
169
|
|
170
170
|
unless simulate
|
171
171
|
if pqueue.length > 0
|
172
|
-
|
172
|
+
req_backup = pqueue.map {|e| as_update(e, add_feedback: false)}
|
173
|
+
backup_update(req_backup)
|
173
174
|
session.batch.launch(pqueue, method: type).tap do |job_status|
|
174
175
|
@status = job_status
|
175
176
|
status.root = self
|
@@ -217,7 +218,7 @@ module Eco
|
|
217
218
|
[].tap do |msg|
|
218
219
|
subjobs.map {|subjob| msg << subjob.summary}
|
219
220
|
end.join("\n")
|
220
|
-
end
|
221
|
+
end
|
221
222
|
|
222
223
|
def as_update(*args)
|
223
224
|
feedback.as_update(*args)
|
@@ -287,10 +288,13 @@ module Eco
|
|
287
288
|
handlers = session.config.error_handlers
|
288
289
|
if status.errors.any? && !handlers.empty? && !error_handler?
|
289
290
|
err_types = status.errors.by_type
|
291
|
+
logger.debug("(#{self.name}) got these error types: #{err_types.keys}")
|
290
292
|
handlers.each do |handler|
|
291
293
|
if entries = err_types[handler.name]
|
292
294
|
handler_job = subjobs_add("#{self.name} => #{handler.name}", usecase: handler)
|
295
|
+
logger.debug("Running error handler #{handler.name}")
|
293
296
|
handler.launch(people: people(entries), session: session, options: options, job: handler_job)
|
297
|
+
logger.debug("Launching job of error handler: #{handler_job.name}")
|
294
298
|
handler_job.launch(simulate: simulate)
|
295
299
|
end
|
296
300
|
end
|
data/lib/eco/api/usecases.rb
CHANGED
@@ -30,6 +30,7 @@ module Eco
|
|
30
30
|
@usecases = {}
|
31
31
|
@cache_init = false
|
32
32
|
@cases_by_name = {}
|
33
|
+
init_caches
|
33
34
|
end
|
34
35
|
|
35
36
|
def length
|
@@ -79,6 +80,7 @@ module Eco
|
|
79
80
|
|
80
81
|
# @return [Eco::API::UseCases] a copy of instance object of `self`.
|
81
82
|
def dup
|
83
|
+
init_caches
|
82
84
|
self.class.new.merge(self)
|
83
85
|
end
|
84
86
|
|
@@ -2,18 +2,17 @@ class Eco::API::UseCases::DefaultCases::HrisCase < Eco::API::Common::Loaders::Us
|
|
2
2
|
name "hris"
|
3
3
|
type :sync
|
4
4
|
|
5
|
+
attr_reader :creation, :update, :supers, :leavers
|
6
|
+
|
5
7
|
def main(entries, people, session, options, usecase)
|
6
8
|
micro = session.micro
|
7
|
-
creation = session.new_job("main", "create", :create, usecase)
|
8
|
-
update = session.new_job("main", "update", :update, usecase)
|
9
|
-
supers = session.new_job("post", "supers", :update, usecase, :core)
|
10
|
-
leavers = session.new_job("post", "leavers", :update, usecase, :account)
|
9
|
+
@creation = session.new_job("main", "create", :create, usecase)
|
10
|
+
@update = session.new_job("main", "update", :update, usecase)
|
11
|
+
@supers = session.new_job("post", "supers", :update, usecase, :core)
|
12
|
+
@leavers = session.new_job("post", "leavers", :update, usecase, :account)
|
11
13
|
|
12
14
|
micro.with_each_leaver(entries, people, options) do |person|
|
13
|
-
leavers.add(person)
|
14
|
-
person.supervisor_id = nil
|
15
|
-
person.account = nil if person.account
|
16
|
-
end
|
15
|
+
leavers.add(person, &method(:leavers_callback))
|
17
16
|
end
|
18
17
|
|
19
18
|
micro.with_each(entries, people, options) do |entry, person|
|
@@ -24,4 +23,11 @@ class Eco::API::UseCases::DefaultCases::HrisCase < Eco::API::Common::Loaders::Us
|
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
26
|
+
private
|
27
|
+
|
28
|
+
def leavers_callback(person)
|
29
|
+
person.supervisor_id = nil
|
30
|
+
person.account = nil if person.account
|
31
|
+
end
|
32
|
+
|
27
33
|
end
|
@@ -2,7 +2,11 @@ class Eco::API::UseCases::DefaultCases::ToCsvCase < Eco::API::Common::Loaders::U
|
|
2
2
|
name "to-csv"
|
3
3
|
type :export
|
4
4
|
|
5
|
+
attr_reader :session, :options, :people
|
6
|
+
|
5
7
|
def main(people, session, options, usecase)
|
8
|
+
@session = session; @options = options; @people = people
|
9
|
+
|
6
10
|
unless people && !people.empty?
|
7
11
|
session.logger.warn("No source people to create the file... aborting!")
|
8
12
|
return false
|
@@ -14,32 +18,48 @@ class Eco::API::UseCases::DefaultCases::ToCsvCase < Eco::API::Common::Loaders::U
|
|
14
18
|
end
|
15
19
|
|
16
20
|
session.logger.info("going to create file: #{file}")
|
17
|
-
CSV.open(file, "w") do |csv|
|
18
|
-
deps = {"supervisor_id" => {people: people}}
|
19
|
-
entry = session.new_entry(people.first, dependencies: deps)
|
20
|
-
header = entry.external_entry.keys
|
21
|
-
|
22
|
-
if options.dig(:nice_header) || options.dig(:export, :options, :nice_header)
|
23
|
-
name_maps = session.schema.fields_by_alt_id.transform_values do |fld|
|
24
|
-
fld.name
|
25
|
-
end.merge({
|
26
|
-
"policy_group_ids" => "User Group(s)",
|
27
|
-
"email" => "Email",
|
28
|
-
"name" => "Name",
|
29
|
-
"supervisor_id" => "Manager ID",
|
30
|
-
"filter_tags" => "Locations",
|
31
|
-
"default_tag" => "Default Location",
|
32
|
-
"id" => "ecoPortal ID"
|
33
|
-
})
|
34
|
-
header = header.map {|name| name_maps[name] ? name_maps[name] : name}
|
35
|
-
end
|
36
21
|
|
37
|
-
|
22
|
+
CSV.open(file, "w") do |csv|
|
23
|
+
csv << spot_header
|
38
24
|
people.each do |person|
|
39
|
-
csv <<
|
25
|
+
csv << target_entry_type(person).values
|
40
26
|
end
|
41
27
|
end
|
42
28
|
exit(0)
|
43
29
|
end
|
44
30
|
|
31
|
+
private
|
32
|
+
|
33
|
+
def target_entry_type(person)
|
34
|
+
session.new_entry(person, dependencies: deps).yield_self do |person_entry|
|
35
|
+
options.dig(:export, :options, :internal_names) ? person_entry.mapped_entry : person_entry.external_entry
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def deps
|
40
|
+
@deps ||= {"supervisor_id" => {people: people}}
|
41
|
+
end
|
42
|
+
|
43
|
+
def spot_header
|
44
|
+
entry = target_entry_type(people.first)
|
45
|
+
header = entry.keys
|
46
|
+
|
47
|
+
if options.dig(:nice_header) || options.dig(:export, :options, :nice_header)
|
48
|
+
name_maps = session.schema.fields_by_alt_id.transform_values do |fld|
|
49
|
+
fld.name
|
50
|
+
end.merge({
|
51
|
+
"policy_group_ids" => "User Group(s)",
|
52
|
+
"email" => "Email",
|
53
|
+
"name" => "Name",
|
54
|
+
"supervisor_id" => "Manager ID",
|
55
|
+
"filter_tags" => "Locations",
|
56
|
+
"default_tag" => "Default Location",
|
57
|
+
"id" => "ecoPortal ID"
|
58
|
+
})
|
59
|
+
header = header.map {|name| name_maps[name] ? name_maps[name] : name}
|
60
|
+
end
|
61
|
+
header
|
62
|
+
end
|
63
|
+
|
64
|
+
|
45
65
|
end
|
data/lib/eco/cli.rb
CHANGED
@@ -22,16 +22,17 @@ module Eco
|
|
22
22
|
|
23
23
|
def run(session:)
|
24
24
|
io = Eco::API::UseCases::BaseIO.new(session: session, options: options)
|
25
|
-
|
26
|
-
session.workflow(io: io) do |wf, io|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
session.workflow(io: io).run(io: io)
|
26
|
+
#session.workflow(io: io) do |wf, io|
|
27
|
+
# io = wf.run(:options, io: io)
|
28
|
+
# io = wf.run(:load, io: io)
|
29
|
+
# io = wf.run(:usecases, io: io)
|
30
|
+
# io = wf.run(:launch_jobs, io: io)
|
31
|
+
# io = wf.run(:post_launch, io: io)
|
32
|
+
# io = wf.run(:report, io: io)
|
33
|
+
# io = wf.run(:end, io: io)
|
34
|
+
# io = wf.run(:close, io: io)
|
35
|
+
#end
|
35
36
|
end
|
36
37
|
|
37
38
|
end
|
@@ -6,7 +6,7 @@ ASSETS.cli.config do |cnf|
|
|
6
6
|
file = SCR.get_file("-people-to-csv", required: true, should_exist: false)
|
7
7
|
options.deep_merge!(export: {file: {name: file, format: :csv}})
|
8
8
|
options.deep_merge!(export: {options: {nice_header: true}}) if SCR.get_arg("-nice-header")
|
9
|
-
|
9
|
+
options.deep_merge!(export: {options: {internal_names: true}}) if SCR.get_arg("-internal-names")
|
10
10
|
case_name = SCR.get_arg("-detailed")? "to-csv-detailed" : "to-csv"
|
11
11
|
session.usecases.case(case_name)
|
12
12
|
end
|
@@ -73,7 +73,7 @@ ASSETS.cli.config do |cnf|
|
|
73
73
|
end
|
74
74
|
|
75
75
|
options.deep_merge!(ignore: {missing: {policy_groups: true}}) if SCR.get_arg("-ignore-missing-policy-groups")
|
76
|
-
|
76
|
+
|
77
77
|
end
|
78
78
|
|
79
79
|
desc = "Restores the people manager by using a backup.json file"
|
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.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oscar Segura
|
@@ -340,6 +340,7 @@ files:
|
|
340
340
|
- lib/eco/api/organization/preferences.rb
|
341
341
|
- lib/eco/api/organization/preferences_reference.json
|
342
342
|
- lib/eco/api/organization/presets_factory.rb
|
343
|
+
- lib/eco/api/organization/presets_integrity.json
|
343
344
|
- lib/eco/api/organization/presets_reference.json
|
344
345
|
- lib/eco/api/organization/presets_values.json
|
345
346
|
- lib/eco/api/organization/tag_tree.rb
|