cognito_rails 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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