Commit bc6f3b76 authored by James Lopez's avatar James Lopez

Merge branch 'async-secondary-email-devise-mailers' into 'master'

Send Devise emails triggered from the 'Email' model asynchronously

See merge request gitlab-org/gitlab!32286
parents 30ee35dc 18a96f9b
# frozen_string_literal: true
module AsyncDeviseEmail
extend ActiveSupport::Concern
private
# Added according to https://github.com/plataformatec/devise/blob/7df57d5081f9884849ca15e4fde179ef164a575f/README.md#activejob-integration
def send_devise_notification(notification, *args)
return true unless can?(:receive_notifications)
devise_mailer.__send__(notification, self, *args).deliver_later # rubocop:disable GitlabSecurity/PublicSend
end
end
......@@ -15,9 +15,14 @@ class Email < ApplicationRecord
after_commit :update_invalid_gpg_signatures, if: -> { previous_changes.key?('confirmed_at') }
devise :confirmable
# This module adds async behaviour to Devise emails
# and should be added after Devise modules are initialized.
include AsyncDeviseEmail
self.reconfirmable = false # currently email can't be changed, no need to reconfirm
delegate :username, to: :user
delegate :username, :can?, to: :user
def email=(value)
write_attribute(:email, value.downcase.strip)
......
......@@ -58,6 +58,10 @@ class User < ApplicationRecord
devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable
# This module adds async behaviour to Devise emails
# and should be added after Devise modules are initialized.
include AsyncDeviseEmail
BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \
"administrator if you think this is an error."
LOGIN_FORBIDDEN = "Your account does not have the required permission to login. Please contact your GitLab " \
......@@ -1746,13 +1750,6 @@ class User < ApplicationRecord
ApplicationSetting.current_without_cache&.usage_stats_set_by_user_id == self.id
end
# Added according to https://github.com/plataformatec/devise/blob/7df57d5081f9884849ca15e4fde179ef164a575f/README.md#activejob-integration
def send_devise_notification(notification, *args)
return true unless can?(:receive_notifications)
devise_mailer.__send__(notification, self, *args).deliver_later # rubocop:disable GitlabSecurity/PublicSend
end
def ensure_user_rights_and_limits
if external?
self.can_create_group = false
......
---
title: Send Devise emails triggered from the 'Email' model asynchronously
merge_request: 32286
author:
type: fixed
......@@ -9,6 +9,12 @@ describe Profiles::EmailsController do
sign_in(user)
end
around do |example|
perform_enqueued_jobs do
example.run
end
end
describe '#create' do
context 'when email address is valid' do
let(:email_params) { { email: "add_email@example.com" } }
......
......@@ -67,7 +67,7 @@ describe 'Profile > Emails' do
email = user.emails.create(email: 'my@email.com')
visit profile_emails_path
expect { click_link("Resend confirmation email") }.to change { ActionMailer::Base.deliveries.size }
expect { click_link("Resend confirmation email") }.to have_enqueued_job.on_queue('mailers')
expect(page).to have_content("Confirmation email sent to #{email.email}")
end
......
......@@ -3,6 +3,12 @@
require 'spec_helper'
describe Email do
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(AsyncDeviseEmail) }
end
describe 'validations' do
it_behaves_like 'an object with RFC3696 compliant email-formated attributes', :email do
subject { build(:email) }
......@@ -45,4 +51,16 @@ describe Email do
expect(build(:email, user: user).username).to eq user.username
end
end
describe 'Devise emails' do
let!(:user) { create(:user) }
describe 'behaviour' do
it 'sends emails asynchronously' do
expect do
user.emails.create!(email: 'hello@hello.com')
end.to have_enqueued_job.on_queue('mailers')
end
end
end
end
......@@ -17,6 +17,7 @@ describe User do
it { is_expected.to include_module(Sortable) }
it { is_expected.to include_module(TokenAuthenticatable) }
it { is_expected.to include_module(BlocksJsonSerialization) }
it { is_expected.to include_module(AsyncDeviseEmail) }
end
describe 'delegations' do
......@@ -165,6 +166,18 @@ describe User do
end
end
describe 'Devise emails' do
let!(:user) { create(:user) }
describe 'behaviour' do
it 'sends emails asynchronously' do
expect do
user.update!(email: 'hello@hello.com')
end.to have_enqueued_job.on_queue('mailers').exactly(:twice)
end
end
end
describe 'validations' do
describe 'password' do
let!(:user) { create(:user) }
......
......@@ -8,10 +8,10 @@ describe Emails::ConfirmService do
subject(:service) { described_class.new(user) }
describe '#execute' do
it 'sends a confirmation email again' do
it 'enqueues a background job to send confirmation email again' do
email = user.emails.create(email: 'new@email.com')
mail = service.execute(email)
expect(mail.subject).to eq('Confirmation instructions')
expect { service.execute(email) }.to have_enqueued_job.on_queue('mailers')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment