Commit 8c1d3e4a authored by Riccardo Padovani's avatar Riccardo Padovani Committed by Thong Kuah

Send a notification when a new access token is created

Changelog: added
parent 07a9a235
......@@ -58,6 +58,18 @@ module Emails
end
# rubocop: enable CodeReuse/ActiveRecord
def access_token_created_email(user, token_name)
return unless user&.active?
@user = user
@target_url = profile_personal_access_tokens_url
@token_name = token_name
Gitlab::I18n.with_locale(@user.preferred_language) do
mail(to: @user.notification_email_or_default, subject: subject(_("A new personal access token has been created")))
end
end
def access_token_about_to_expire_email(user, token_names)
return unless user
......
......@@ -65,6 +65,13 @@ class NotificationService
end
end
# Notify the owner of the account when a new personal access token is created
def access_token_created(user, token_name)
return unless user.can?(:receive_notifications)
mailer.access_token_created_email(user, token_name).deliver_later
end
# Notify the owner of the personal access token, when it is about to expire
# And mark the token with about_to_expire_delivered
def access_token_about_to_expire(user, token_names)
......
......@@ -16,6 +16,7 @@ module PersonalAccessTokens
if token.persisted?
log_event(token)
notification_service.access_token_created(target_user, token.name)
ServiceResponse.success(payload: { personal_access_token: token })
else
ServiceResponse.error(message: token.errors.full_messages.to_sentence, payload: { personal_access_token: token })
......
%p
= _('Hi %{username}!') % { username: sanitize_name(@user.name) }
%p
= html_escape(_('A new personal access token, named %{token_name}, has been created.')) % { token_name: @token_name }
%p
- pat_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: @target_url }
= html_escape(_('You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings.')) % { pat_link_start: pat_link_start, pat_link_end: '</a>'.html_safe }
<%= _('Hi %{username}!') % { username: sanitize_name(@user.name) } %>
<%= _('A new personal access token, named %{token_name}, has been created.') % { token_name: @token_name } %>
<%= _('You can check it in your in your personal access tokens settings %{pat_link}.') % { pat_link: @target_url } %>
......@@ -184,6 +184,7 @@ Users are notified of the following events:
| Password changed | User | Security email, always sent when user changes their own password. |
| Password changed by administrator | User | Security email, always sent when an administrator changes the password of another user. |
| Personal access tokens expiring soon | User | Security email, always sent. |
| Personal access tokens have been created | User | Security email, always sent. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337591) in GitLab 14.9. |
| Personal access tokens have expired | User | Security email, always sent. |
| Project access level changed | User | Sent when user project access level is changed. |
| SSH key has expired | User | Security email, always sent. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322637) in GitLab 13.12._ |
......
......@@ -1608,6 +1608,12 @@ msgstr ""
msgid "A new impersonation token has been created."
msgstr ""
msgid "A new personal access token has been created"
msgstr ""
msgid "A new personal access token, named %{token_name}, has been created."
msgstr ""
msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
msgstr ""
......@@ -41943,6 +41949,12 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
msgid "You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
msgid "You can check it in your in your personal access tokens settings %{pat_link}."
msgstr ""
msgid "You can create a new %{link}."
msgstr ""
......
......@@ -123,6 +123,39 @@ RSpec.describe Emails::Profile do
end
end
describe 'user personal access token has been created' do
let_it_be(:user) { create(:user) }
let_it_be(:token) { create(:personal_access_token, user: user) }
context 'when valid' do
subject { Notify.access_token_created_email(user, token.name) }
it_behaves_like 'an email sent from GitLab'
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 user' do
is_expected.to deliver_to user.email
end
it 'has the correct subject' do
is_expected.to have_subject /^A new personal access token has been created$/i
end
it 'provides the names of the token' do
is_expected.to have_body_text /#{token.name}/
end
it 'includes a link to personal access tokens page' do
is_expected.to have_body_text /#{profile_personal_access_tokens_path}/
end
it 'includes the email reason' do
is_expected.to have_body_text /You're receiving this email because of your account on localhost/
end
end
end
describe 'user personal access token is about to expire' do
let_it_be(:user) { create(:user) }
let_it_be(:expiring_token) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) }
......
......@@ -258,6 +258,27 @@ RSpec.describe NotificationService, :mailer do
end
describe 'AccessToken' do
describe '#access_token_created' do
let_it_be(:user) { create(:user) }
let_it_be(:pat) { create(:personal_access_token, user: user) }
subject(:notification_service) { notification.access_token_created(user, pat.name) }
it 'sends email to the token owner' do
expect { notification_service }.to have_enqueued_email(user, pat.name, mail: "access_token_created_email")
end
context 'when user is not allowed to receive notifications' do
before do
user.block!
end
it 'does not send email to the token owner' do
expect { notification_service }.not_to have_enqueued_email(user, pat.name, mail: "access_token_created_email")
end
end
end
describe '#access_token_about_to_expire' do
let_it_be(:user) { create(:user) }
let_it_be(:pat) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) }
......
......@@ -18,6 +18,14 @@ RSpec.describe PersonalAccessTokens::CreateService do
subject
end
it 'notifies the user' do
expect_next_instance_of(NotificationService) do |notification_service|
expect(notification_service).to receive(:access_token_created).with(user, params[:name])
end
subject
end
end
shared_examples_for 'an unsuccessfully created token' do
......
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