eco-helpers 2.0.9 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|