Commit f9f46722 authored by Brett Walker's avatar Brett Walker

Send a confirmation email when the user adds a secondary email address....

Send a confirmation email when the user adds a secondary email address. Utilizes the Devise `confirmable` capabilities. Issue #37385
parent b1464157
...@@ -11,11 +11,12 @@ class ConfirmationsController < Devise::ConfirmationsController ...@@ -11,11 +11,12 @@ class ConfirmationsController < Devise::ConfirmationsController
end end
def after_confirmation_path_for(resource_name, resource) def after_confirmation_path_for(resource_name, resource)
if signed_in?(resource_name) # incoming resource can either be a :user or an :email
if signed_in?(:user)
after_sign_in_path_for(resource) after_sign_in_path_for(resource)
else else
flash[:notice] += " Please sign in." flash[:notice] += " Please sign in."
new_session_path(resource_name) new_session_path(:user)
end end
end end
end end
...@@ -6,10 +6,7 @@ class Profiles::EmailsController < Profiles::ApplicationController ...@@ -6,10 +6,7 @@ class Profiles::EmailsController < Profiles::ApplicationController
def create def create
@email = Emails::CreateService.new(current_user, email_params).execute @email = Emails::CreateService.new(current_user, email_params).execute
unless @email.errors.blank?
if @email.errors.blank?
NotificationService.new.new_email(@email)
else
flash[:alert] = @email.errors.full_messages.first flash[:alert] = @email.errors.full_messages.first
end end
......
...@@ -7,12 +7,6 @@ module Emails ...@@ -7,12 +7,6 @@ module Emails
mail(to: @user.notification_email, subject: subject("Account was created for you")) mail(to: @user.notification_email, subject: subject("Account was created for you"))
end end
def new_email_email(email_id)
@email = Email.find(email_id)
@current_user = @user = @email.user
mail(to: @user.notification_email, subject: subject("Email was added to your account"))
end
def new_ssh_key_email(key_id) def new_ssh_key_email(key_id)
@key = Key.find_by(id: key_id) @key = Key.find_by(id: key_id)
......
...@@ -7,6 +7,9 @@ class Email < ActiveRecord::Base ...@@ -7,6 +7,9 @@ class Email < ActiveRecord::Base
validates :email, presence: true, uniqueness: true, email: true validates :email, presence: true, uniqueness: true, email: true
validate :unique_email, if: ->(email) { email.email_changed? } validate :unique_email, if: ->(email) { email.email_changed? }
devise :confirmable
self.reconfirmable = false # currently email can't be changed, no need to reconfirm
def email=(value) def email=(value)
write_attribute(:email, value.downcase.strip) write_attribute(:email, value.downcase.strip)
end end
......
...@@ -31,13 +31,6 @@ class NotificationService ...@@ -31,13 +31,6 @@ class NotificationService
end end
end end
# Always notify user about email added to profile
def new_email(email)
if email.user&.can?(:receive_notifications)
mailer.new_email_email(email.id).deliver_later
end
end
# When create an issue we should send an email to: # When create an issue we should send an email to:
# #
# * issue assignee if their notification level is not Disabled # * issue assignee if their notification level is not Disabled
......
#content
= email_default_heading("#{@resource.user.name}, you've added a secondary email!")
%p Click the link below to confirm your email address (#{@resource.email})
#cta
= link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
%p
If this email was added in error, you can remove it here:
= link_to "Emails", profile_emails_url
Hi <%= @user.name %>! <%= @resource.user.name %>, you've added a secondary email!
A new email was added to your account: You can confirm your email (<%= @resource.email %>) through the link below:
email.................. <%= @email.email %> <%= confirmation_url(@resource, confirmation_token: @token) %>
If this email was added in error, you can remove it here: <%= profile_emails_url %> If this email was added in error, you can remove it here: <%= profile_emails_url %>
- if @resource.unconfirmed_email.present? - if @resource.is_a?(Email)
#content = render partial: 'confirmation_instructions_secondary'
= email_default_heading(@resource.unconfirmed_email)
%p Click the link below to confirm your email address.
#cta
= link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
- else - else
#content - if @resource.unconfirmed_email.present?
- if Gitlab.com? #content
= email_default_heading('Thanks for signing up to GitLab!') = email_default_heading(@resource.unconfirmed_email)
- else %p Click the link below to confirm your email address.
= email_default_heading("Welcome, #{@resource.name}!") #cta
%p To get started, click the link below to confirm your account. = link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
#cta - else
= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token) #content
- if Gitlab.com?
= email_default_heading('Thanks for signing up to GitLab!')
- else
= email_default_heading("Welcome, #{@resource.name}!")
%p To get started, click the link below to confirm your account.
#cta
= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
<% if @resource.is_a?(Email) %>
<%= render partial: 'confirmation_instructions_secondary' %>
<% else %>
Welcome, <%= @resource.name %>! Welcome, <%= @resource.name %>!
<% if @resource.unconfirmed_email.present? %> <% if @resource.unconfirmed_email.present? %>
...@@ -7,3 +10,4 @@ You can confirm your account through the link below: ...@@ -7,3 +10,4 @@ You can confirm your account through the link below:
<% end %> <% end %>
<%= confirmation_url(@resource, confirmation_token: @token) %> <%= confirmation_url(@resource, confirmation_token: @token) %>
<% end %>
%p
Hi #{@user.name}!
%p
A new email was added to your account:
%p
email:
%code= @email.email
%p
If this email was added in error, you can remove it here:
= link_to "Emails", profile_emails_url
...@@ -47,4 +47,6 @@ ...@@ -47,4 +47,6 @@
%span.label.label-info Public email %span.label.label-info Public email
- if email.email === current_user.notification_email - if email.email === current_user.notification_email
%span.label.label-info Notification email %span.label.label-info Notification email
- if !email.confirmed?
%span.label.label-warning Unconfirmed
= link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-warning prepend-left-10' = link_to 'Remove', profile_email_path(email), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-sm btn-warning prepend-left-10'
---
title: A confirmation email is now sent when adding a secondary email address
merge_request:
author: digitalmoksha
type: added
...@@ -11,6 +11,11 @@ devise_scope :user do ...@@ -11,6 +11,11 @@ devise_scope :user do
get '/users/almost_there' => 'confirmations#almost_there' get '/users/almost_there' => 'confirmations#almost_there'
end end
# for secondary email confirmations
devise_for :emails, controllers: { confirmations: :confirmations }
devise_scope :email do
end
scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) do scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) do
scope(path: 'users/:username', scope(path: 'users/:username',
as: :user, as: :user,
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddEmailConfirmation < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
# When a migration requires downtime you **must** uncomment the following
# constant and define a short and easy to understand explanation as to why the
# migration requires downtime.
# DOWNTIME_REASON = ''
# When using the methods "add_concurrent_index", "remove_concurrent_index" or
# "add_column_with_default" you must disable the use of transactions
# as these methods can not run in an existing transaction.
# When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
# that either of them is the _only_ method called in the migration,
# any other changes should go in a separate migration.
# This ensures that upon failure _only_ the index creation or removing fails
# and can be retried or reverted easily.
#
# To disable transactions uncomment the following line and remove these
# comments:
# disable_ddl_transaction!
def change
add_column :emails, :confirmation_token, :string
add_column :emails, :confirmed_at, :datetime
add_column :emails, :confirmation_sent_at, :datetime
add_index :emails, :confirmation_token, unique: true
end
end
...@@ -329,7 +329,6 @@ module API ...@@ -329,7 +329,6 @@ module API
email = Emails::CreateService.new(user, declared_params(include_missing: false)).execute email = Emails::CreateService.new(user, declared_params(include_missing: false)).execute
if email.errors.blank? if email.errors.blank?
NotificationService.new.new_email(email)
present email, with: Entities::Email present email, with: Entities::Email
else else
render_validation_error!(email) render_validation_error!(email)
...@@ -675,7 +674,6 @@ module API ...@@ -675,7 +674,6 @@ module API
email = Emails::CreateService.new(current_user, declared_params).execute email = Emails::CreateService.new(current_user, declared_params).execute
if email.errors.blank? if email.errors.blank?
NotificationService.new.new_email(email)
present email, with: Entities::Email present email, with: Entities::Email
else else
render_validation_error!(email) render_validation_error!(email)
......
require 'spec_helper'
describe Profiles::EmailsController do
let(:user) { create(:user) }
before do
sign_in(user)
end
describe '#create' do
let(:email_params) { {email: "add_email@example.com" } }
it 'sends an email confirmation' do
expect {post(:create, { email: email_params })}.to change { ActionMailer::Base.deliveries.size }
expect(ActionMailer::Base.deliveries.last.to).to eq [email_params[:email]]
expect(ActionMailer::Base.deliveries.last.subject).to match "Confirmation instructions"
end
end
end
...@@ -120,29 +120,4 @@ describe Emails::Profile do ...@@ -120,29 +120,4 @@ describe Emails::Profile do
it { expect { Notify.new_gpg_key_email('foo') }.not_to raise_error } it { expect { Notify.new_gpg_key_email('foo') }.not_to raise_error }
end end
end end
describe 'user added email' do
let(:email) { create(:email) }
subject { Notify.new_email_email(email.id) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'is sent to the new user' do
is_expected.to deliver_to email.user.email
end
it 'has the correct subject' do
is_expected.to have_subject /^Email was added to your account$/i
end
it 'contains the new email address' do
is_expected.to have_body_text /#{email.email}/
end
it 'includes a link to emails page' do
is_expected.to have_body_text /#{profile_emails_path}/
end
end
end end
...@@ -105,18 +105,6 @@ describe NotificationService, :mailer do ...@@ -105,18 +105,6 @@ describe NotificationService, :mailer do
end end
end end
describe 'Email' do
describe '#new_email' do
let!(:email) { create(:email) }
it { expect(notification.new_email(email)).to be_truthy }
it 'sends email to email owner' do
expect { notification.new_email(email) }.to change { ActionMailer::Base.deliveries.size }.by(1)
end
end
end
describe 'Notes' do describe 'Notes' do
context 'issue note' do context 'issue note' do
let(:project) { create(:project, :private) } let(:project) { create(:project, :private) }
......
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