cognito_rails 0.1.0 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48fe70f5578d90db88e1a7546f12a16a3b24941bf20a2e8bb4a37b24b3678adc
4
- data.tar.gz: 5463df9f063b8b986ca1ef49d0f9a8efce22862854e7e74cb4aee77a8f101fea
3
+ metadata.gz: f8bbd85c82670198044b07ac6bd693920201e3911166f1432365bd834e54fafd
4
+ data.tar.gz: 1c435514395d116f142fb22121bb0bdb7cdb91b46897b48566453e3748ae184d
5
5
  SHA512:
6
- metadata.gz: '058bb0a9820ee032ca2d56f7c3954c5acb434543d599ddf3aedb029e2c8b6e06b9d93445a9989248c0a9223cc5038a91cd680313d7d1735837c18826a3008999'
7
- data.tar.gz: 5fa75f4e6109b4144a33759340672eee19253d33ba8e9c167b0c4187b85f7b736d8129cfd22221188119c793f8250d550b36ba49b55742d47133ec9fd7d4ec14
6
+ metadata.gz: 11bea4faacf98021ee61a6ae2280e4da743fd1e62e68c4dc88681c98f735973ccabc5806261df3e1d22243da42eef7fb3ddc2fc02f5c06677e6291f1e3d9f780
7
+ data.tar.gz: 26ba725b881ab2333e8ea5823ac199fc4fd430426b85f1f50832d2e9b1985db692615d2543ef7cea6d6a21aa8cddfdc9358194bf0ce30655acb35b0a971a1d90
@@ -5,26 +5,21 @@ require 'logger'
5
5
  module CognitoRails
6
6
  class Config
7
7
  class << self
8
- # @raise [RuntimeError] if not set
9
8
  # @return [String] AWS access key id
10
- def aws_access_key_id
11
- # @type [String,nil]
12
- @aws_access_key_id || (raise 'Missing config aws_access_key_id')
9
+ def aws_client_credentials
10
+ @aws_client_credentials || {}
13
11
  end
14
12
 
15
- # @!attribute aws_access_key_id [w]
16
- # @return [String]
13
+ # @!attribute aws_client_credentials [w]
14
+ # @return [Hash]
17
15
  # @!attribute aws_region [w]
18
16
  # @return [String]
19
- # @!attribute aws_secret_access_key [w]
20
- # @return [String]
21
17
  # @!attribute aws_user_pool_id [w]
22
18
  # @return [String]
23
19
  # @!attribute default_user_class [w]
24
20
  # @return [String,nil]
25
- attr_writer :aws_access_key_id, :skip_model_hooks, :aws_region,
26
- :aws_secret_access_key, :aws_user_pool_id,
27
- :default_user_class
21
+ attr_writer :aws_client_credentials, :skip_model_hooks, :aws_region,
22
+ :aws_user_pool_id, :default_user_class
28
23
 
29
24
  # @return [Boolean] skip model hooks
30
25
  def skip_model_hooks
@@ -43,12 +38,6 @@ module CognitoRails
43
38
  @aws_region || (raise 'Missing config aws_region')
44
39
  end
45
40
 
46
- # @return [String] AWS secret access key
47
- # @raise [RuntimeError] if not set
48
- def aws_secret_access_key
49
- @aws_secret_access_key || (raise 'Missing config aws_secret_access_key')
50
- end
51
-
52
41
  # @return [String] AWS user pool id
53
42
  # @raise [RuntimeError] if not set
54
43
  def aws_user_pool_id
@@ -23,6 +23,55 @@ module CognitoRails
23
23
  end
24
24
  end
25
25
 
26
+ # rubocop:disable Metrics/BlockLength
27
+ class_methods do
28
+ # @return [Array<ActiveRecord::Base>] all users
29
+ # @raise [CognitoRails::Error] if failed to fetch users
30
+ # @raise [ActiveRecord::RecordInvalid] if failed to save user
31
+ def sync_from_cognito!
32
+ response = User.all
33
+ response.users.map do |user_data|
34
+ sync_user!(user_data)
35
+ end
36
+ end
37
+
38
+ # @return [Array<ActiveRecord::Base>] all users
39
+ # @raise [CognitoRails::Error] if failed to fetch users
40
+ # @raise [ActiveRecord::RecordInvalid] if failed to save user
41
+ def sync_to_cognito!
42
+ find_each.map do |user|
43
+ user.init_cognito_user
44
+ user.save!
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def sync_user!(user_data)
51
+ external_id = user_data.username
52
+ return if external_id.blank?
53
+
54
+ user = find_or_initialize_by(_cognito_attribute_name => external_id)
55
+ user.email = User.extract_cognito_attribute(user_data.attributes, :email)
56
+ user.phone = User.extract_cognito_attribute(user_data.attributes, :phone_number) if user.respond_to?(:phone)
57
+ _cognito_resolve_custom_attribute(user, user_data)
58
+
59
+ user.save!
60
+ user
61
+ end
62
+
63
+ def _cognito_resolve_custom_attribute(user, user_data)
64
+ _cognito_custom_attributes.each do |attribute|
65
+ next if attribute[:value].is_a?(String)
66
+
67
+ value = User.extract_cognito_attribute(user_data.attributes, attribute[:name])
68
+ next unless value
69
+
70
+ user[attribute[:name].gsub('custom:', '')] = value
71
+ end
72
+ end
73
+ end
74
+
26
75
  # @return [String]
27
76
  def cognito_external_id
28
77
  self[self.class._cognito_attribute_name]
@@ -57,11 +57,15 @@ module CognitoRails
57
57
  )
58
58
  user = new(user_class: user_class)
59
59
  user.id = result.username
60
- user.email = result.user_attributes.find { |attribute| attribute[:name] == 'email' }[:value]
61
- user.phone = result.user_attributes.find { |attribute| attribute[:name] == 'phone_number' }&.dig(:value)
60
+ user.email = extract_cognito_attribute(result.user_attributes, :email)
61
+ user.phone = extract_cognito_attribute(result.user_attributes, :phone_number)
62
62
  user
63
63
  end
64
64
 
65
+ def self.all
66
+ cognito_client.list_users(user_pool_id: CognitoRails::Config.aws_user_pool_id)
67
+ end
68
+
65
69
  # @param attributes [Hash]
66
70
  # @option attributes [String] :email
67
71
  # @option attributes [String] :password
@@ -138,6 +142,18 @@ module CognitoRails
138
142
  destroy || (raise ActiveRecord::RecordInvalid, self)
139
143
  end
140
144
 
145
+ # @return [Aws::CognitoIdentityProvider::Client]
146
+ # @raise [RuntimeError]
147
+ def self.cognito_client
148
+ @cognito_client ||= Aws::CognitoIdentityProvider::Client.new(
149
+ { region: CognitoRails::Config.aws_region }.merge(CognitoRails::Config.aws_client_credentials)
150
+ )
151
+ end
152
+
153
+ def self.extract_cognito_attribute(attributes, column)
154
+ attributes.find { |attribute| attribute[:name] == column.to_s }&.dig(:value)
155
+ end
156
+
141
157
  private
142
158
 
143
159
  # @return [Aws::CognitoIdentityProvider::Client]
@@ -155,18 +171,6 @@ module CognitoRails
155
171
  user_class._cognito_verify_phone
156
172
  end
157
173
 
158
- # @return [Aws::CognitoIdentityProvider::Client]
159
- # @raise [RuntimeError]
160
- def self.cognito_client
161
- raise 'Can\'t create user in test mode' if Rails.env.test?
162
-
163
- @cognito_client ||= Aws::CognitoIdentityProvider::Client.new(
164
- access_key_id: CognitoRails::Config.aws_access_key_id,
165
- secret_access_key: CognitoRails::Config.aws_secret_access_key,
166
- region: CognitoRails::Config.aws_region
167
- )
168
- end
169
-
170
174
  # @return [Array<Hash>]
171
175
  def general_user_attributes
172
176
  [
@@ -2,5 +2,5 @@
2
2
 
3
3
  module CognitoRails
4
4
  # @return [String] gem version
5
- VERSION = '0.1.0'
5
+ VERSION = '1.0.0'
6
6
  end
@@ -111,6 +111,42 @@ RSpec.describe CognitoRails::User, type: :model do
111
111
  end
112
112
  end
113
113
 
114
+ context 'class methods' do
115
+ before do
116
+ expect(CognitoRails::User).to receive(:cognito_client).at_least(:once).and_return(fake_cognito_client)
117
+ end
118
+
119
+ it '#sync_from_cognito!' do
120
+ expect(fake_cognito_client).to receive(:list_users).and_return(
121
+ OpenStruct.new(
122
+ users: [
123
+ build_cognito_user_data('some@example.com'),
124
+ build_cognito_user_data('some2@example.com')
125
+ ],
126
+ pagination_token: nil
127
+ )
128
+ )
129
+
130
+ expect do
131
+ users = User.sync_from_cognito!
132
+
133
+ expect(users).to be_a(Array)
134
+ expect(users.size).to eq(2)
135
+ expect(users.first).to be_a(User)
136
+ end.to change { User.count }.by(2)
137
+
138
+ expect(User.pluck(:email)).to match_array(['some@example.com', 'some2@example.com'])
139
+ expect(User.pluck(:name)).to match_array(['Giovanni', 'Giovanni'])
140
+ end
141
+
142
+ it '#sync_to_cognito!' do
143
+ User.create!(email: sample_cognito_email)
144
+
145
+ expect_any_instance_of(User).to receive(:init_cognito_user).exactly(1).times
146
+ User.sync_to_cognito!
147
+ end
148
+ end
149
+
114
150
  context 'admin' do
115
151
  before do
116
152
  expect(CognitoRails::User).to receive(:cognito_client).at_least(:once).and_return(fake_cognito_client)
data/spec/spec_helper.rb CHANGED
@@ -11,16 +11,17 @@ require 'factories/user'
11
11
  I18n.enforce_available_locales = false
12
12
  RSpec::Expectations.configuration.warn_about_potential_false_positives = false
13
13
 
14
- Dir[File.expand_path('../support/*.rb', __FILE__)].each { |f| require f }
14
+ Dir[File.expand_path('../support/*.rb', __FILE__)].sort.each { |f| require f }
15
15
 
16
- CognitoRails::Config.aws_access_key_id = 'access_key_id'
16
+ CognitoRails::Config.aws_client_credentials = {
17
+ access_key_id: 'access_key_id',
18
+ secret_access_key: 'secret_access_key'
19
+ }
17
20
  CognitoRails::Config.aws_region = 'region'
18
- CognitoRails::Config.aws_secret_access_key = 'secret_access_key'
19
21
  CognitoRails::Config.aws_user_pool_id = 'user_pool_id'
20
22
  CognitoRails::Config.default_user_class = 'User'
21
23
 
22
24
  RSpec.configure do |config|
23
-
24
25
  config.include FactoryBot::Syntax::Methods
25
26
 
26
27
  config.before(:suite) do
@@ -40,4 +40,24 @@ module CognitoRails::Helpers
40
40
  client
41
41
  end
42
42
  end
43
+
44
+ def build_cognito_user_data(email)
45
+ OpenStruct.new(
46
+ username: SecureRandom.uuid,
47
+ user_status: 'CONFIRMED',
48
+ enabled: true,
49
+ user_last_modified_date: Time.now,
50
+ attributes: [
51
+ OpenStruct.new(
52
+ name: 'email',
53
+ value: email
54
+ ),
55
+ OpenStruct.new(
56
+ name: 'custom:name',
57
+ value: 'Giovanni'
58
+ )
59
+ ],
60
+ mfa_options: []
61
+ )
62
+ end
43
63
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cognito_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mònade
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-27 00:00:00.000000000 Z
11
+ date: 2023-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport