eco-helpers 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +3 -0
  4. data/README.md +20 -0
  5. data/eco-helpers.gemspec +34 -0
  6. data/lib/eco-helpers.rb +15 -0
  7. data/lib/eco/api.rb +13 -0
  8. data/lib/eco/api/common.rb +10 -0
  9. data/lib/eco/api/common/people.rb +17 -0
  10. data/lib/eco/api/common/people/base_parser.rb +16 -0
  11. data/lib/eco/api/common/people/default_parsers.rb +40 -0
  12. data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +28 -0
  13. data/lib/eco/api/common/people/default_parsers/date_parser.rb +33 -0
  14. data/lib/eco/api/common/people/default_parsers/multi_parser.rb +33 -0
  15. data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +23 -0
  16. data/lib/eco/api/common/people/default_parsers/select_parser.rb +29 -0
  17. data/lib/eco/api/common/people/entries.rb +120 -0
  18. data/lib/eco/api/common/people/person_entry.rb +380 -0
  19. data/lib/eco/api/common/people/person_factory.rb +114 -0
  20. data/lib/eco/api/common/people/person_modifier.rb +62 -0
  21. data/lib/eco/api/common/people/person_parser.rb +140 -0
  22. data/lib/eco/api/common/people/types.rb +47 -0
  23. data/lib/eco/api/common/session.rb +15 -0
  24. data/lib/eco/api/common/session/base_session.rb +46 -0
  25. data/lib/eco/api/common/session/environment.rb +47 -0
  26. data/lib/eco/api/common/session/file_manager.rb +90 -0
  27. data/lib/eco/api/common/session/logger.rb +105 -0
  28. data/lib/eco/api/common/session/mailer.rb +92 -0
  29. data/lib/eco/api/common/session/s3_uploader.rb +110 -0
  30. data/lib/eco/api/common/version_patches.rb +11 -0
  31. data/lib/eco/api/common/version_patches/external_person.rb +11 -0
  32. data/lib/eco/api/eco_faker.rb +59 -0
  33. data/lib/eco/api/organization.rb +13 -0
  34. data/lib/eco/api/organization/account.rb +23 -0
  35. data/lib/eco/api/organization/people.rb +118 -0
  36. data/lib/eco/api/organization/policy_groups.rb +51 -0
  37. data/lib/eco/api/organization/preferences.rb +28 -0
  38. data/lib/eco/api/organization/preferences_reference.json +23 -0
  39. data/lib/eco/api/organization/presets.rb +138 -0
  40. data/lib/eco/api/organization/presets_backup.rb +220 -0
  41. data/lib/eco/api/organization/presets_values.json +10 -0
  42. data/lib/eco/api/organization/tag_tree.rb +134 -0
  43. data/lib/eco/api/organization_old.rb +73 -0
  44. data/lib/eco/api/session.rb +180 -0
  45. data/lib/eco/api/session/batch.rb +132 -0
  46. data/lib/eco/api/session/batch_job.rb +152 -0
  47. data/lib/eco/api/session/batch_jobs.rb +131 -0
  48. data/lib/eco/api/session/batch_status.rb +138 -0
  49. data/lib/eco/api/session/task.rb +92 -0
  50. data/lib/eco/api/session_config.rb +179 -0
  51. data/lib/eco/api/session_config/api.rb +47 -0
  52. data/lib/eco/api/session_config/apis.rb +78 -0
  53. data/lib/eco/api/session_config/files.rb +30 -0
  54. data/lib/eco/api/session_config/logger.rb +54 -0
  55. data/lib/eco/api/session_config/mailer.rb +65 -0
  56. data/lib/eco/api/session_config/people.rb +89 -0
  57. data/lib/eco/api/session_config/s3_bucket.rb +62 -0
  58. data/lib/eco/api/session_config/use_cases.rb +30 -0
  59. data/lib/eco/api/usecases.rb +12 -0
  60. data/lib/eco/api/usecases/base_case.rb +14 -0
  61. data/lib/eco/api/usecases/case_data.rb +13 -0
  62. data/lib/eco/api/usecases/default_cases.rb +53 -0
  63. data/lib/eco/api/usecases/default_cases/change_email_case.rb +47 -0
  64. data/lib/eco/api/usecases/default_cases/create_details_case.rb +29 -0
  65. data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +49 -0
  66. data/lib/eco/api/usecases/default_cases/delete_case.rb +20 -0
  67. data/lib/eco/api/usecases/default_cases/email_as_id_case.rb +24 -0
  68. data/lib/eco/api/usecases/default_cases/hris_case.rb +67 -0
  69. data/lib/eco/api/usecases/default_cases/new_email_case.rb +26 -0
  70. data/lib/eco/api/usecases/default_cases/new_id_case.rb +26 -0
  71. data/lib/eco/api/usecases/default_cases/refresh_presets.rb +25 -0
  72. data/lib/eco/api/usecases/default_cases/reinvite_case.rb +22 -0
  73. data/lib/eco/api/usecases/default_cases/remove_account_case.rb +36 -0
  74. data/lib/eco/api/usecases/default_cases/reset_landing_page_case.rb +24 -0
  75. data/lib/eco/api/usecases/default_cases/set_default_tag_case.rb +44 -0
  76. data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +39 -0
  77. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +36 -0
  78. data/lib/eco/api/usecases/default_cases/update_details_case.rb +30 -0
  79. data/lib/eco/api/usecases/default_cases/upsert_account_case.rb +35 -0
  80. data/lib/eco/api/usecases/use_case.rb +177 -0
  81. data/lib/eco/api/usecases/use_group.rb +104 -0
  82. data/lib/eco/cli.rb +9 -0
  83. data/lib/eco/cli/input.rb +109 -0
  84. data/lib/eco/cli/input_multi.rb +137 -0
  85. data/lib/eco/cli/root.rb +8 -0
  86. data/lib/eco/cli/session.rb +9 -0
  87. data/lib/eco/cli/session/batch.rb +9 -0
  88. data/lib/eco/common.rb +7 -0
  89. data/lib/eco/common/base_cli.rb +116 -0
  90. data/lib/eco/common/language.rb +9 -0
  91. data/lib/eco/data.rb +9 -0
  92. data/lib/eco/data/crypto.rb +7 -0
  93. data/lib/eco/data/crypto/encryption.rb +318 -0
  94. data/lib/eco/data/files.rb +10 -0
  95. data/lib/eco/data/files/directory.rb +93 -0
  96. data/lib/eco/data/files/file_pattern.rb +32 -0
  97. data/lib/eco/data/files/helpers.rb +90 -0
  98. data/lib/eco/data/mapper.rb +54 -0
  99. data/lib/eco/data/random.rb +10 -0
  100. data/lib/eco/data/random/distribution.rb +133 -0
  101. data/lib/eco/data/random/fake.rb +320 -0
  102. data/lib/eco/data/random/values.rb +80 -0
  103. data/lib/eco/language.rb +12 -0
  104. data/lib/eco/language/curry.rb +28 -0
  105. data/lib/eco/language/hash_transform.rb +68 -0
  106. data/lib/eco/language/hash_transform_modifier.rb +114 -0
  107. data/lib/eco/language/match.rb +30 -0
  108. data/lib/eco/language/match_modifier.rb +190 -0
  109. data/lib/eco/language/models.rb +11 -0
  110. data/lib/eco/language/models/attribute_parser.rb +38 -0
  111. data/lib/eco/language/models/collection.rb +181 -0
  112. data/lib/eco/language/models/modifier.rb +68 -0
  113. data/lib/eco/language/models/wrap.rb +114 -0
  114. data/lib/eco/language/values_at.rb +159 -0
  115. data/lib/eco/lexic/dictionary.rb +33 -0
  116. data/lib/eco/lexic/dictionary/dictionary.txt +355484 -0
  117. data/lib/eco/lexic/dictionary/tags.json +38 -0
  118. data/lib/eco/scripting.rb +30 -0
  119. data/lib/eco/scripting/README.md +11 -0
  120. data/lib/eco/scripting/arguments.rb +40 -0
  121. data/lib/eco/tester.rb +97 -0
  122. data/lib/eco/version.rb +3 -0
  123. metadata +325 -0
@@ -0,0 +1,105 @@
1
+ module Eco
2
+ module API
3
+ module Common
4
+ module Session
5
+ class Logger
6
+ DEFAULT_TIMESTAMP_PATTERN = '%Y-%m-%dT%H:%M:%S'
7
+
8
+ def initialize(console_level: nil, file_level: ::Logger::DEBUG, log_file: nil, timestamp_console: false, enviro: nil)
9
+ raise "Required Environment object (enviro:). Given: #{enviro}" if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
10
+ @enviro = enviro
11
+
12
+ timestamp_console = fetch_timestamp_console(timestamp_console)
13
+ @console_logger = ::Logger.new(STDOUT).tap do |_logger|
14
+ _logger.formatter = proc do |severity, datetime, progname, msg|
15
+ str_timestamp = timestamp_console ? "#{datetime.strftime(DEFAULT_TIMESTAMP_PATTERN)} >" : ""
16
+ "#{severity.to_s[0]}: #{str_timestamp} #{msg}\n"
17
+ end
18
+ _logger.level = fetch_console_level(console_level)
19
+ end
20
+
21
+ if log_file = fetch_log_file(log_file)
22
+ @file_logger = ::Logger.new(log_file).tap do |_logger|
23
+ _logger.formatter = proc do |severity, datetime, progname, msg|
24
+ "#{severity.to_s[0]}: #{datetime.strftime(DEFAULT_TIMESTAMP_PATTERN)} > #{msg}\n"
25
+ end
26
+ _logger.level = fetch_file_level(file_level)
27
+ end
28
+ end
29
+ end
30
+
31
+ def debug(*args, &block)
32
+ log(:debug, *args, &block)
33
+ end
34
+
35
+ def info(*args, &block)
36
+ log(:info, *args, &block)
37
+ end
38
+
39
+ def warn(*args, &block)
40
+ return log(:warn, *args, &block)
41
+ end
42
+
43
+ def error(*args, &block)
44
+ return log(:error, *args, &block)
45
+ end
46
+
47
+ def fatal(*args, &block)
48
+ return log(:fatal, *args, &block)
49
+ end
50
+
51
+ def unkown(msg, &block)
52
+ return log(:unkown, *args, &block)
53
+ end
54
+
55
+ def << (msg)
56
+ @console_logger << msg unless !@console_logger
57
+ @file_logger << msg unless !@file_logger
58
+ end
59
+
60
+ def close()
61
+ @console_logger.close unless !@console_logger
62
+ @file_logger.close unless !@file_logger
63
+ end
64
+
65
+ def add(*args)
66
+ @console_logger.add(*args) unless !@console_logger
67
+ @file_logger.add(*args) unless !@file_logger
68
+ end
69
+
70
+ private
71
+
72
+ def log(level, *args, &block)
73
+ @console_logger.send(level, *args, &block) unless !@console_logger
74
+ @file_logger.send(level, *args, &block) unless !@file_logger
75
+ end
76
+
77
+ def config
78
+ @enviro.config || {}
79
+ end
80
+
81
+ def fetch_timestamp_console(value)
82
+ value || config.logger.timestamp_console
83
+ end
84
+
85
+ def fetch_console_level(value)
86
+ value || config.logger.console_level || ::Logger::INFO
87
+ end
88
+
89
+ def fetch_file_level(value)
90
+ value || config.logger.file_level || ::Logger::DEBUG
91
+ end
92
+
93
+ def fetch_log_file(log_file)
94
+ if log_file ||= config.logger.file
95
+ log_file = @enviro.file_manager.dir.file(log_file) if @enviro
96
+ FileManager.create_directory(log_file, includes_file: true)
97
+ end
98
+ log_file
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,92 @@
1
+ require 'aws-sdk-ses'
2
+ require 'dotenv/load'
3
+
4
+ module Eco
5
+ module API
6
+ module Common
7
+ module Session
8
+ class Mailer
9
+
10
+ def initialize (enviro:)
11
+ raise "Required Environment object (enviro:). Given: #{enviro}" if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
12
+ @enviro = enviro
13
+ end
14
+
15
+ def mail(to:, subject:, body:)
16
+ ses.send_email(
17
+ destination: {
18
+ to_addresses: [to].flatten,
19
+ },
20
+ source: fetch_from,
21
+ message: {
22
+ subject: {
23
+ charset: "UTF-8",
24
+ data: subject,
25
+ },
26
+ body: {
27
+ # NOTE - html: will let you send html instead
28
+ # you can use both at once if you like
29
+ text: {
30
+ charset: "UTF-8",
31
+ data: body
32
+ }
33
+ }
34
+ }
35
+ ).tap do |response|
36
+ logger.debug("Sent email to #{to} (MessageId: #{response.message_id})")
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def ses
43
+ begin
44
+ @ses ||= Aws::SES::Client.new(
45
+ access_key_id: fetch_access_key_id,
46
+ secret_access_key: fetch_secret_access_key,
47
+ region: fetch_region
48
+ )
49
+ rescue Exception => e
50
+ logger.error("Trying to send an email with wrong email configuration: #{e}")
51
+ end
52
+ @ses
53
+ end
54
+
55
+ def logger
56
+ @enviro&.logger || ::Logger.new(IO::NULL)
57
+ end
58
+
59
+ def config
60
+ @enviro.config || {}
61
+ end
62
+
63
+ def fetch_from(value = nil)
64
+ value || config.mailer.from
65
+ end
66
+
67
+ def fetch_access_key_id
68
+ config.mailer.access_key_id || ENV['AWS_ACCESS_KEY_ID']
69
+ end
70
+
71
+ def fetch_secret_access_key
72
+ config.mailer.secret_access_key || ENV['AWS_SECRET_ACCESS_KEY']
73
+ end
74
+
75
+ def fetch_region
76
+ config.mailer.region || ENV['AWS_REGION']
77
+ end
78
+
79
+ def fetch_server
80
+ config.mailer.server
81
+ end
82
+
83
+ def fetch_message_id_domain
84
+ config.mailer.message_id_domain
85
+ end
86
+
87
+
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,110 @@
1
+ require 'aws-sdk-s3'
2
+ require 'dotenv/load'
3
+
4
+ module Eco
5
+ module API
6
+ module Common
7
+ module Session
8
+ class S3Uploader
9
+ attr_reader :prefix
10
+
11
+ def initialize (enviro:)
12
+ raise "Required Environment object (enviro:). Given: #{enviro}" if enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
13
+ @enviro = enviro
14
+ @prefix = fetch_prefix
15
+ @timestamp = Time.now.iso8601
16
+ end
17
+
18
+ def upload(filename, content)
19
+ if obj = new_s3_object(filename)
20
+ log_upload(obj) do
21
+ obj.put(body: content)
22
+ end
23
+ end
24
+ return full_path(obj)
25
+ end
26
+
27
+ def upload_file(path)
28
+ File.open(path, "rb") do |f|
29
+ upload(File.basename(path), f)
30
+ end
31
+ end
32
+
33
+ def upload_directory(path)
34
+ prefix = File.expand_path(File.join(path, ".."))
35
+ Dir.glob(File.join(path, "**/*")).sort.map do |file|
36
+ next unless File.file?(file) # Skip directories
37
+ key = file.sub(prefix,"").gsub(/\\/,"/").sub(/^\/+/,"")
38
+
39
+ File.open(file, "rb") do |f|
40
+ upload(key, f)
41
+ end
42
+ end.compact
43
+ end
44
+
45
+ private
46
+
47
+ def full_path(obj)
48
+ return "s3://#{bucket.name}/#{obj.key}" if obj
49
+ end
50
+
51
+ def bucket
52
+ begin
53
+ @bucket ||= Aws::S3::Resource.new(
54
+ access_key_id: fetch_access_key_id,
55
+ secret_access_key: fetch_secret_access_key,
56
+ region: fetch_region
57
+ ).bucket(fetch_bucket)
58
+ rescue Exception => e
59
+ logger.error("Trying to upload to S3 with wrong configuration: #{e}")
60
+ end
61
+ @bucket
62
+ end
63
+
64
+ def session_path
65
+ ["scripts", @prefix, @timestamp].join("/")
66
+ end
67
+
68
+ def new_s3_object(filename)
69
+ file_path = [session_path, filename].join("/")
70
+ bucket&.object(file_path)
71
+ end
72
+
73
+ def log_upload(obj)
74
+ yield
75
+ logger.debug("Uploaded #{full_path(obj)}")
76
+ end
77
+
78
+ def logger
79
+ @enviro&.logger || ::Logger.new(IO::NULL)
80
+ end
81
+
82
+ def config
83
+ @enviro.config || {}
84
+ end
85
+
86
+ def fetch_bucket
87
+ config.s3bucket.name
88
+ end
89
+
90
+ def fetch_prefix
91
+ config.s3bucket.prefix
92
+ end
93
+
94
+ def fetch_access_key_id
95
+ config.s3bucket.access_key_id || ENV['AWS_ACCESS_KEY_ID']
96
+ end
97
+
98
+ def fetch_secret_access_key
99
+ config.s3bucket.secret_access_key || ENV['AWS_SECRET_ACCESS_KEY']
100
+ end
101
+
102
+ def fetch_region
103
+ config.s3bucket.region || ENV['AWS_REGION']
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,11 @@
1
+ module Eco
2
+ module API
3
+ module Common
4
+ module VersionPatches
5
+ end
6
+ end
7
+ end
8
+ end
9
+
10
+ #require_relative 'version_patches/base_model.rb'
11
+ require_relative 'version_patches/external_person.rb'
@@ -0,0 +1,11 @@
1
+ module Ecoportal
2
+ module API
3
+ class V1
4
+ class Person < Common::BaseModel
5
+ def sync
6
+ @original_doc = JSON.parse(@doc.to_json)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,59 @@
1
+ module Eco
2
+ module API
3
+ # faker object
4
+ @@faker = nil
5
+ class EcoFaker
6
+ @@api = nil
7
+ @org = nil
8
+ # attr_accessor
9
+ attr_reader :org
10
+ def initialize(init = {})
11
+ set_settings(init)
12
+ end
13
+ # allows to change certain configuration settings on an existing Faker instance object
14
+ def set_settings (init = {})
15
+ @today = (aux = init['today'])? aux : Time.now
16
+ api = init.fetch('api', nil)
17
+ @@api = api.instance_of?(Ecoportal::API::Internal) && api
18
+ # this will initialize org basics (i.e. people_schemas, policy_groups, login_providers)
19
+ @org = Organization.new(init)
20
+ end
21
+ def newPerson ()
22
+
23
+ end
24
+ def modifyPerson(person)
25
+
26
+ end
27
+ private
28
+ end
29
+
30
+ def self.new(init = {})
31
+ @@faker = EcoFaker.new(init)
32
+ end
33
+
34
+ class FakePerson < Ecoportal::API::Internal::Person
35
+ @@faker
36
+ def initialize(faker, *args)
37
+ raise "You must initialize the faker first" unless faker && faker.instance_of(Faker)
38
+ @@faker = faker
39
+ super(*args)
40
+ @@faker.set_details
41
+ end
42
+ end
43
+
44
+ class FakeField
45
+ @@types = ["boolean", "number", "text", "select", "date", "phone_number"]
46
+ @@multiple = false
47
+ attr_accessor :type, :multiple
48
+ #attr_reader
49
+ def initialize (init = {})
50
+ init_values_generator(init)
51
+ end
52
+ private
53
+ def init_values_faker (init = {})
54
+ include
55
+ @fake_values = API::Data::Random::ValuesGenerator.new(init)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ module Eco
2
+ module API
3
+ module Organization
4
+ end
5
+ end
6
+ end
7
+
8
+ require_relative 'organization/tag_tree'
9
+ require_relative 'organization/presets'
10
+ require_relative 'organization/preferences'
11
+ require_relative 'organization/account'
12
+ require_relative 'organization/people'
13
+ require_relative 'organization/policy_groups'
@@ -0,0 +1,23 @@
1
+ module Eco
2
+ module API
3
+ module Account
4
+ class Account
5
+
6
+ attr_accessor :policy_group_ids, :filter_tags
7
+ attr_accessor :permissions_preset, :permissions_custom
8
+ attr_accessor :login_provider_ids
9
+ attr_accessor :landing_page_id, :preferences, :starred_ids
10
+ attr_reader :prefilter
11
+ #attr_reader :presets
12
+
13
+ def initialize(init = {})
14
+ #@presets = AccountPresets.new
15
+ end
16
+ def set_details(person)
17
+
18
+ end
19
+ private
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,118 @@
1
+ module Eco
2
+ module API
3
+ module Organization
4
+ class People < Eco::Language::Models::Collection
5
+
6
+ # build the shortcuts of Collection
7
+ attr_collection :id, :external_id, :email, :name, :supervisor_id
8
+ attr_presence :account, :details
9
+
10
+ alias_method :people, :to_a
11
+
12
+ include Common::People
13
+
14
+ def initialize(people = [], klass: INTERNAL::Person, factory: nil)
15
+ @klass = INTERNAL::Person unless klass == EXTERNAL::Person
16
+ super(people, klass: @klass)
17
+ @caches_init = false
18
+ end
19
+
20
+ def [](id_or_ext)
21
+ self.id(id_or_ext) || self.external_id(id_or_ext)
22
+ end
23
+
24
+ def id(*args)
25
+ attr('id', *args).first
26
+ end
27
+
28
+ def external_id(*args)
29
+ attr('external_id', *args).first
30
+ end
31
+
32
+ def users
33
+ self.account_present(true)
34
+ end
35
+
36
+ def contacts
37
+ self.details_present(true)
38
+ end
39
+
40
+ def non_users
41
+ self.account_present(false)
42
+ end
43
+
44
+ def person(id: nil, external_id: nil, email: nil)
45
+ init_caches
46
+ pers = @by_id[id]&.first if id
47
+ pers = @by_external_id[external_id&.strip]&.first if !pers && !external_id.to_s.strip.empty?
48
+ pers = @by_users_email[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
49
+ pers = @by_non_users_email[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
50
+ pers = @by_external_id[email&.downcase.strip]&.first if !pers && !email.to_s.strip.empty?
51
+ pers
52
+ end
53
+
54
+ def find(object)
55
+ id = object.respond_to?("id")? object.send("id") : nil
56
+ external_id = object.respond_to?("external_id")? object.send("external_id") : nil
57
+ email = object.respond_to?("email")? object.send("email") : nil
58
+ person(id: id, external_id: external_id, email: email)
59
+ end
60
+
61
+ def exclude(object)
62
+ exclude_people(into_a(object))
63
+ end
64
+
65
+ def exclude_people(list)
66
+ discarded = list.map do |person|
67
+ find(person)
68
+ end.compact
69
+ newFrom self.to_a - discarded
70
+ end
71
+
72
+ def email_id_maps
73
+ self.users.group_by(:email).transform_values { |person| person.id }
74
+ end
75
+
76
+ def group_by_supervisor
77
+ self.to_h(:supervisor_id)
78
+ end
79
+
80
+ # only those that are present
81
+ def supervisors
82
+ h_all = self.to_h
83
+ sup_ids = h_all.keys & self.supervisor_ids
84
+ newFrom h_all.select do |id, person|
85
+ sup_ids.include?(id)
86
+ end.values
87
+ end
88
+
89
+ def missing_supervisors_ids
90
+ sup_ids = self.supervisor_ids
91
+ sup_ids - (sup_ids & self.ids)
92
+ end
93
+
94
+ def to_h(attr)
95
+ super(attr || "id")
96
+ end
97
+
98
+ protected
99
+
100
+ def on_change
101
+ @caches_init = false
102
+ end
103
+
104
+ private
105
+
106
+ def init_caches
107
+ return if @caches_init
108
+ @by_id = self.to_h('id')
109
+ @by_external_id = self.to_h('external_id')
110
+ @by_users_email = self.users.to_h('email')
111
+ @by_non_users_email = self.non_users.to_h('email')
112
+ @caches_init = true
113
+ end
114
+
115
+ end
116
+ end
117
+ end
118
+ end