effective_resources 2.10.1 → 2.11.1
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/README.md +37 -0
- data/app/models/concerns/effective_devise_user.rb +61 -1
- data/lib/effective_resources/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 70b3835f1e45128ade83d38d69adbcd8096fd5aecce4882028d0512dab970dae
|
|
4
|
+
data.tar.gz: 7c38e5cb62a55b4fa4924970aad1b0f45cf06b0dccedb41770f8df394e98a9c0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 50be7d9a989a25f8aa6777e85603c18b8ccc3be72e78aa35e4aa83814ca0fa74371de434c1138dc9a2331b57d79c1e032dbf987628c2b3b800b8b3819b26eb3d
|
|
7
|
+
data.tar.gz: 46e3229e7ecc0a7e989ac022afed029183b96e9a225f7a3d93edc3d9ff0a14a37682bf4d1685e1c3ebf3f8c8a5760e0cd09eafc7346eb940bf13d5aecd1752ad
|
data/README.md
CHANGED
|
@@ -392,6 +392,43 @@ def to_select2
|
|
|
392
392
|
end
|
|
393
393
|
```
|
|
394
394
|
|
|
395
|
+
## Authentication
|
|
396
|
+
Effective Resources is designed to work with Devise. It also adds support for an `alternate email`
|
|
397
|
+
for authentication. You just need to add an `alternate_email` column to your `User` model table.
|
|
398
|
+
|
|
399
|
+
After that column is added, any user would be able to log in with either their `email` or their
|
|
400
|
+
`alternate_email`.
|
|
401
|
+
|
|
402
|
+
You can also create another mailer for `devise` in order to send password reset emails to the both
|
|
403
|
+
the primary `email` and also the `alternate_email`, like this:
|
|
404
|
+
|
|
405
|
+
```ruby
|
|
406
|
+
class DeviseMailer < Devise::Mailer
|
|
407
|
+
# Overriding Devise's #headers_for to support alternate_email when present
|
|
408
|
+
def headers_for(action, opts)
|
|
409
|
+
headers = super(action, opts)
|
|
410
|
+
|
|
411
|
+
if [:reset_password_instructions].include?(action)
|
|
412
|
+
headers.merge!(
|
|
413
|
+
to: [resource.email, resource.try(:alternate_email)].compact.uniq
|
|
414
|
+
)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
headers
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
and set this new mailer to be used by `devise` in `config/initializers/devise.rb`:
|
|
423
|
+
|
|
424
|
+
```ruby
|
|
425
|
+
Devise.setup do |config|
|
|
426
|
+
# ...
|
|
427
|
+
config.mailer = 'DeviseMailer'
|
|
428
|
+
# ...
|
|
429
|
+
end
|
|
430
|
+
```
|
|
431
|
+
|
|
395
432
|
## Testing
|
|
396
433
|
|
|
397
434
|
Run tests by:
|
|
@@ -46,7 +46,7 @@ module EffectiveDeviseUser
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Devise invitable ignores model validations, so we manually check for duplicate email addresses.
|
|
49
|
-
before_save(if: -> { new_record? && invitation_sent_at.present? }) do
|
|
49
|
+
before_save(if: -> { new_record? && try(:invitation_sent_at).present? }) do
|
|
50
50
|
if email.blank?
|
|
51
51
|
self.errors.add(:email, "can't be blank")
|
|
52
52
|
raise("email can't be blank")
|
|
@@ -62,6 +62,28 @@ module EffectiveDeviseUser
|
|
|
62
62
|
before_save(if: -> { persisted? && encrypted_password_changed? }) do
|
|
63
63
|
assign_attributes(provider: nil, access_token: nil, refresh_token: nil, token_expires_at: nil)
|
|
64
64
|
end
|
|
65
|
+
|
|
66
|
+
# Uniqueness validation of emails and alternate emails across all users
|
|
67
|
+
validate(if: -> { respond_to?(:alternate_email) }) do
|
|
68
|
+
records = self.class.where.not(id: self.id) # exclude self
|
|
69
|
+
email_duplicates = records.where("lower(email) = :email OR lower(alternate_email) = :email", email: email.to_s.strip.downcase)
|
|
70
|
+
alternate_email_duplicates = records.where("lower(email) = :alternate_email OR lower(alternate_email) = :alternate_email", alternate_email: alternate_email.to_s.strip.downcase)
|
|
71
|
+
|
|
72
|
+
# Check if a uniqueness validation was already performed before triggering the exists query
|
|
73
|
+
if !self.errors.added?(:email, 'has already been taken') && email_duplicates.exists?
|
|
74
|
+
self.errors.add(:email, 'has already been taken')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Check if the alternate email is set before triggering the exists query
|
|
78
|
+
if try(:alternate_email).present? && alternate_email_duplicates.exists?
|
|
79
|
+
self.errors.add(:alternate_email, 'has already been taken')
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
with_options(if: -> { respond_to?(:alternate_email) }) do
|
|
84
|
+
validates :alternate_email, email: true, allow_blank: true
|
|
85
|
+
end
|
|
86
|
+
|
|
65
87
|
end
|
|
66
88
|
|
|
67
89
|
module ClassMethods
|
|
@@ -162,10 +184,48 @@ module EffectiveDeviseUser
|
|
|
162
184
|
recoverable
|
|
163
185
|
end
|
|
164
186
|
|
|
187
|
+
# https://github.com/heartcombo/devise/blob/f6e73e5b5c8f519f4be29ac9069c6ed8a2343ce4/lib/devise/models/authenticatable.rb#L276
|
|
188
|
+
def find_first_by_auth_conditions(tainted_conditions, opts = {})
|
|
189
|
+
conditions = devise_parameter_filter.filter(tainted_conditions).merge(opts)
|
|
190
|
+
|
|
191
|
+
user = to_adapter.find_first(conditions)
|
|
192
|
+
return user if user.present? && user.persisted?
|
|
193
|
+
|
|
194
|
+
to_adapter.find_first(alternate_email: conditions[:email]) if has_alternate_email?
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# https://github.com/heartcombo/devise/blob/f6e73e5b5c8f519f4be29ac9069c6ed8a2343ce4/lib/devise/models/database_authenticatable.rb#L216
|
|
198
|
+
def find_for_database_authentication(warden_conditions)
|
|
199
|
+
conditions = warden_conditions.dup.presence || {}
|
|
200
|
+
primary_or_alternate_email = conditions[:email]
|
|
201
|
+
conditions.delete(:email)
|
|
202
|
+
|
|
203
|
+
raise "Expected an email #{has_alternate_email? ? 'or alternate email' : ''} but got [#{primary_or_alternate_email}] instead" if primary_or_alternate_email.blank?
|
|
204
|
+
|
|
205
|
+
query = if has_alternate_email?
|
|
206
|
+
"lower(email) = :value OR lower(alternate_email) = :value"
|
|
207
|
+
else
|
|
208
|
+
"lower(email) = :value"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
all
|
|
212
|
+
.where(conditions)
|
|
213
|
+
.where(query, value: primary_or_alternate_email.strip.downcase)
|
|
214
|
+
.first
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def has_alternate_email?
|
|
218
|
+
'alternate_email'.in? column_names
|
|
219
|
+
end
|
|
220
|
+
|
|
165
221
|
end
|
|
166
222
|
|
|
167
223
|
# EffectiveDeviseUser Instance Methods
|
|
168
224
|
|
|
225
|
+
def alternate_email=(value)
|
|
226
|
+
super(value.to_s.strip.downcase.presence)
|
|
227
|
+
end
|
|
228
|
+
|
|
169
229
|
def reinvite!
|
|
170
230
|
invite!
|
|
171
231
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: effective_resources
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.11.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Code and Effect
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-09-
|
|
11
|
+
date: 2023-09-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|