Skip to content

Commit a476e74

Browse files
committed
Allow update_with_email to use new reconfirmation flow
1 parent 8b812cc commit a476e74

3 files changed

Lines changed: 123 additions & 78 deletions

File tree

app/views/graphql_devise/mailer/confirmation_instructions.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
<% if message['schema_url'].present? %>
77
<%= link_to t('.confirm_account_link'), "#{message['schema_url']}?#{confirmation_query(resource_name: @resource.class.to_s, redirect_url: message['redirect-url'], token: @token).to_query}" %>
88
<% else %>
9-
<%= link_to t('.confirm_account_link'), "#{message['redirect-url'].to_s}?#{{ confirmationToken: @token }.to_query}" %>
9+
<%= link_to t('.confirm_account_link'), "#{CGI.escape(message['redirect-url'].to_s)}?#{{ confirmationToken: @token }.to_query}" %>
1010
<% end %>
1111
</p>

lib/graphql_devise/model/with_email_updater.rb

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def initialize(resource, attributes)
99
end
1010

1111
def call
12-
resource_attributes = @attributes.except(:schema_url, :confirmation_success_url)
12+
resource_attributes = @attributes.except(:schema_url, :confirmation_success_url, :confirmation_url)
1313
return @resource.update(resource_attributes) unless requires_reconfirmation?(resource_attributes)
1414

1515
@resource.assign_attributes(resource_attributes)
@@ -27,16 +27,27 @@ def call
2727
else
2828
raise(
2929
GraphqlDevise::Error,
30-
'Method `update_with_email` requires attributes `confirmation_success_url` and `schema_url` for email reconfirmation to work'
30+
'Method `update_with_email` requires attribute `confirmation_url` for email reconfirmation to work'
3131
)
3232
end
3333
end
3434

3535
private
3636

3737
def required_reconfirm_attributes?
38-
@attributes[:schema_url].present? &&
39-
(@attributes[:confirmation_success_url].present? || DeviseTokenAuth.default_confirm_success_url.present?)
38+
if @attributes[:schema_url].present?
39+
ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
40+
Providing `schema_url` and `confirmation_success_url` to `update_with_email` is deprecated and will be
41+
removed in a future version of this gem.
42+
43+
Now you must only provide `confirmation_url` and the email will contain the new format of the confirmation
44+
url that needs to be used with the new `confirmAccountWithToken` on the client application.
45+
DEPRECATION
46+
47+
[@attributes[:confirmation_success_url], DeviseTokenAuth.default_confirm_success_url].any?(&:present?)
48+
else
49+
[@attributes[:confirmation_url], DeviseTokenAuth.default_confirm_success_url].any?(&:present?)
50+
end
4051
end
4152

4253
def requires_reconfirmation?(resource_attributes)
@@ -60,13 +71,22 @@ def email_in_database
6071
end
6172
end
6273

74+
def confirmation_method_params
75+
if @attributes[:schema_url].present?
76+
{
77+
redirect_url: @attributes[:confirmation_success_url] || DeviseTokenAuth.default_confirm_success_url,
78+
schema_url: @attributes[:schema_url]
79+
}
80+
else
81+
{ redirect_url: @attributes[:confirmation_url] || DeviseTokenAuth.default_confirm_success_url, }
82+
end
83+
end
84+
6385
def send_confirmation_instructions(saved)
6486
return unless saved
6587

6688
@resource.send_confirmation_instructions(
67-
redirect_url: @attributes[:confirmation_success_url] || DeviseTokenAuth.default_confirm_success_url,
68-
template_path: ['graphql_devise/mailer'],
69-
schema_url: @attributes[:schema_url]
89+
confirmation_method_params.merge(template_path: ['graphql_devise/mailer'])
7090
)
7191
end
7292
end

spec/graphql_devise/model/with_email_updater_spec.rb

Lines changed: 95 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,57 @@
44

55
RSpec.describe GraphqlDevise::Model::WithEmailUpdater do
66
describe '#call' do
7+
shared_examples 'all required arguments are provided' do |base_attributes|
8+
let(:attributes) { base_attributes.merge(email: 'new@gmail.com', name: 'Updated Name') }
9+
10+
it 'postpones email update' do
11+
expect do
12+
updater
13+
resource.reload
14+
end.to not_change(resource, :email).from(resource.email).and(
15+
not_change(resource, :uid).from(resource.uid)
16+
).and(
17+
change(resource, :unconfirmed_email).from(nil).to('new@gmail.com')
18+
).and(
19+
change(resource, :name).from(resource.name).to('Updated Name')
20+
)
21+
end
22+
23+
it 'sends out a confirmation email to the unconfirmed_email' do
24+
expect { updater }.to change(ActionMailer::Base.deliveries, :count).by(1)
25+
26+
email = ActionMailer::Base.deliveries.first
27+
expect(email.to).to contain_exactly('new@gmail.com')
28+
end
29+
30+
context 'when email value is the same on the DB' do
31+
let(:attributes) { base_attributes.merge(email: resource.email, name: 'changed') }
32+
33+
it 'updates attributes and does not send confirmation email' do
34+
expect do
35+
updater
36+
resource.reload
37+
end.to change(resource, :name).from(resource.name).to('changed').and(
38+
not_change(resource, :email).from(resource.email)
39+
).and(
40+
not_change(ActionMailer::Base.deliveries, :count).from(0)
41+
)
42+
end
43+
end
44+
45+
context 'when provided params are invalid' do
46+
let(:attributes) { base_attributes.merge(email: 'newgmail.com', name: '') }
47+
48+
it 'returns false and adds errors to the model' do
49+
expect(updater).to be_falsey
50+
expect(resource.errors.full_messages).to contain_exactly(
51+
'Email is not an email',
52+
"Name can't be blank"
53+
)
54+
end
55+
end
56+
end
57+
758
subject(:updater) { described_class.new(resource, attributes).call }
859

960
context 'when the model does not have an unconfirmed_email column' do
@@ -38,90 +89,64 @@
3889
end
3990

4091
context 'when attributes contain email' do
41-
context 'when schema_url is missing' do
42-
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name' } }
43-
44-
it 'raises an error' do
45-
expect { updater }.to raise_error(
46-
GraphqlDevise::Error,
47-
'Method `update_with_email` requires attributes `confirmation_success_url` and `schema_url` for email reconfirmation to work'
48-
)
49-
end
92+
context 'when confirmation_success_url is used' do
93+
it_behaves_like 'all required arguments are provided', schema_url: 'http://localhost/test', confirmation_success_url: 'https://google.com'
5094

51-
context 'when email will not change' do
52-
let(:attributes) { { email: resource.email, name: 'changed' } }
53-
54-
it 'updates name and does not raise an error' do
55-
expect do
56-
updater
57-
resource.reload
58-
end.to change(resource, :name).from(resource.name).to('changed').and(
59-
not_change(resource, :email).from(resource.email)
60-
).and(
61-
not_change(ActionMailer::Base.deliveries, :count).from(0)
62-
)
63-
end
64-
end
65-
end
95+
context 'when confirmation_success_url is missing and no default is set' do
96+
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name', schema_url: 'http://localhost/test' } }
6697

67-
context 'when only confirmation_success_url is missing' do
68-
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name', schema_url: 'http://localhost/test' } }
98+
before { allow(DeviseTokenAuth).to receive(:default_confirm_success_url).and_return(nil) }
6999

70-
it 'uses DTA default_confirm_success_url on the email' do
71-
expect { updater }.to change(ActionMailer::Base.deliveries, :count).by(1)
100+
it 'raises an error' do
101+
expect { updater }.to raise_error(
102+
GraphqlDevise::Error,
103+
'Method `update_with_email` requires attribute `confirmation_url` for email reconfirmation to work'
104+
)
105+
end
72106

73-
email = ActionMailer::Base.deliveries.first
74-
expect(email.body.decoded).to include(CGI.escape('https://google.com'))
107+
context 'when email will not change' do
108+
let(:attributes) { { email: resource.email, name: 'changed', confirmation_success_url: 'https://google.com' } }
109+
110+
it 'updates name and does not raise an error' do
111+
expect do
112+
updater
113+
resource.reload
114+
end.to change(resource, :name).from(resource.name).to('changed').and(
115+
not_change(resource, :email).from(resource.email)
116+
).and(
117+
not_change(ActionMailer::Base.deliveries, :count).from(0)
118+
)
119+
end
120+
end
75121
end
76122
end
77123

78-
context 'when both required urls are provided' do
79-
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name', schema_url: 'http://localhost/test', confirmation_success_url: 'https://google.com' } }
80-
81-
it 'postpones email update' do
82-
expect do
83-
updater
84-
resource.reload
85-
end.to not_change(resource, :email).from(resource.email).and(
86-
not_change(resource, :uid).from(resource.uid)
87-
).and(
88-
change(resource, :unconfirmed_email).from(nil).to('new@gmail.com')
89-
).and(
90-
change(resource, :name).from(resource.name).to('Updated Name')
91-
)
92-
end
124+
context 'when confirm_url is used' do
125+
it_behaves_like 'all required arguments are provided', confirmation_url: 'https://google.com'
126+
end
93127

94-
it 'sends out a confirmation email to the unconfirmed_email' do
95-
expect { updater }.to change(ActionMailer::Base.deliveries, :count).by(1)
128+
context 'when no confirmation url is provided is provided' do
129+
context 'when schema_url is provided' do
130+
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name', schema_url: 'http://localhost/test' } }
96131

97-
email = ActionMailer::Base.deliveries.first
98-
expect(email.to).to contain_exactly('new@gmail.com')
99-
end
132+
it 'uses DTA default_confirm_success_url on the email with redirect flow' do
133+
expect { updater }.to change(ActionMailer::Base.deliveries, :count).by(1)
100134

101-
context 'when email value is the same on the DB' do
102-
let(:attributes) { { email: resource.email, name: 'changed', schema_url: 'http://localhost/test', confirmation_success_url: 'https://google.com' } }
103-
104-
it 'updates attributes and does not send confirmation email' do
105-
expect do
106-
updater
107-
resource.reload
108-
end.to change(resource, :name).from(resource.name).to('changed').and(
109-
not_change(resource, :email).from(resource.email)
110-
).and(
111-
not_change(ActionMailer::Base.deliveries, :count).from(0)
112-
)
135+
email = ActionMailer::Base.deliveries.first
136+
expect(email.body.decoded).to include(CGI.escape('https://google.com'))
137+
expect(email.body.decoded).to include(CGI.escape('ConfirmAccount('))
113138
end
114139
end
115140

116-
context 'when provided params are invalid' do
117-
let(:attributes) { { email: 'newgmail.com', name: '', schema_url: 'http://localhost/test', confirmation_success_url: 'https://google.com' } }
141+
context 'when schema_url is not provided' do
142+
let(:attributes) { { email: 'new@gmail.com', name: 'Updated Name' } }
118143

119-
it 'returns false and adds errors to the model' do
120-
expect(updater).to be_falsey
121-
expect(resource.errors.full_messages).to contain_exactly(
122-
'Email is not an email',
123-
"Name can't be blank"
124-
)
144+
it 'uses DTA default_confirm_success_url on the email and new confirmation flow' do
145+
expect { updater }.to change(ActionMailer::Base.deliveries, :count).by(1)
146+
147+
email = ActionMailer::Base.deliveries.first
148+
expect(email.body.decoded).to include(CGI.escape('https://google.com'))
149+
expect(email.body.decoded).to include('?confirmationToken=')
125150
end
126151
end
127152
end

0 commit comments

Comments
 (0)