diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 73f718873..31b0bc3f7 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -39,11 +39,12 @@ def create protected def after_confirmation_success(resource) - if resource.welcome_instructions_token.present? + if resource.previous_changes.key?("email") + redirect_to new_user_session_path, notice: "Your email has been confirmed. Please sign in." + elsif resource.welcome_instructions_token.present? redirect_to user_welcome_path(resource.welcome_instructions_token) else - redirect_to new_user_session_path, - notice: "Your email has been confirmed. Please sign in." + redirect_to new_user_session_path, notice: "Your email has been confirmed. Please sign in." end end end diff --git a/app/views/welcome/show.html.erb b/app/views/welcome/show.html.erb index b9e52ff7e..0dfd16c4a 100644 --- a/app/views/welcome/show.html.erb +++ b/app/views/welcome/show.html.erb @@ -34,7 +34,7 @@ spellcheck: "false", data: { password_toggle_target: "input" } %> @@ -56,7 +56,7 @@ spellcheck: "false", data: { password_toggle_target: "input" } %> diff --git a/spec/requests/user_invitation_flow_system_spec.rb b/spec/requests/user_invitation_flow_system_spec.rb index 001634b73..f8d465087 100644 --- a/spec/requests/user_invitation_flow_system_spec.rb +++ b/spec/requests/user_invitation_flow_system_spec.rb @@ -143,19 +143,71 @@ expect(response).to redirect_to(user_welcome_path(user_with_token.welcome_instructions_token)) end - it "redirects to sign in if user has no welcome token" do - # User without welcome token - user_without_token = create(:user, confirmed_at: nil) - user_without_token.update_columns(welcome_instructions_token: nil) - user_without_token.send_confirmation_instructions + it "redirects to welcome page with existing token even if token is old" do + # User with old welcome token (tokens no longer expire) + user_with_old_token = create(:user, confirmed_at: nil) + user_with_old_token.set_welcome_instructions_token! + user_with_old_token.update_column(:welcome_instructions_created_at, 31.days.ago) + old_token = user_with_old_token.welcome_instructions_token + user_with_old_token.send_confirmation_instructions # Visit confirmation link - get user_confirmation_path(confirmation_token: user_without_token.confirmation_token) + get user_confirmation_path(confirmation_token: user_with_old_token.confirmation_token) + + # Should keep existing token and redirect to welcome page + user_with_old_token.reload + expect(user_with_old_token.welcome_instructions_token).to eq(old_token) + expect(response).to redirect_to(user_welcome_path(user_with_old_token.welcome_instructions_token)) + end + + it "redirects legacy ported users without welcome token to sign in" do + # Legacy user ported from old system — sign_in_count is 0, no welcome token + legacy_user = create(:user, confirmed_at: nil) + legacy_user.update_columns(welcome_instructions_token: nil, sign_in_count: 0) + legacy_user.send_confirmation_instructions + + get user_confirmation_path(confirmation_token: legacy_user.confirmation_token) - # Should redirect to sign in page expect(response).to redirect_to(new_user_session_path) follow_redirect! expect(response.body).to include("confirmed") end + + it "redirects to sign in on reconfirmation even with welcome token present" do + # Edge case: user has welcome token but is doing an email change + user = create(:user, confirmed_at: 1.year.ago) + user.set_welcome_instructions_token! + user.update_columns( + unconfirmed_email: "changed@example.com", + confirmation_token: Devise.friendly_token, + confirmation_sent_at: Time.current + ) + + get user_confirmation_path(confirmation_token: user.confirmation_token) + + # Reconfirmation takes priority over welcome token + expect(response).to redirect_to(new_user_session_path) + end + + it "redirects to sign in on email change reconfirmation" do + # Existing user changing their email — unconfirmed_email triggers reconfirmation detection + existing_user = create(:user, confirmed_at: 1.year.ago) + existing_user.update_columns( + unconfirmed_email: "newemail@example.com", + confirmation_token: Devise.friendly_token, + confirmation_sent_at: Time.current + ) + + get user_confirmation_path(confirmation_token: existing_user.confirmation_token) + + expect(response).to redirect_to(new_user_session_path) + follow_redirect! + expect(response.body).to include("confirmed") + + # Verify email was actually changed + existing_user.reload + expect(existing_user.email).to eq("newemail@example.com") + expect(existing_user.unconfirmed_email).to be_nil + end end end