Commit f83b68da authored by Thong Kuah's avatar Thong Kuah

Merge branch 'notification-personal-token-creation' into 'master'

Send a notification when a new access token is created

See merge request gitlab-org/gitlab!81340
parents d7cb0c41 8c1d3e4a
...@@ -58,6 +58,18 @@ module Emails ...@@ -58,6 +58,18 @@ module Emails
end end
# rubocop: enable CodeReuse/ActiveRecord # 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) def access_token_about_to_expire_email(user, token_names)
return unless user return unless user
......
...@@ -65,6 +65,13 @@ class NotificationService ...@@ -65,6 +65,13 @@ class NotificationService
end end
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 # Notify the owner of the personal access token, when it is about to expire
# And mark the token with about_to_expire_delivered # And mark the token with about_to_expire_delivered
def access_token_about_to_expire(user, token_names) def access_token_about_to_expire(user, token_names)
......
...@@ -16,6 +16,7 @@ module PersonalAccessTokens ...@@ -16,6 +16,7 @@ module PersonalAccessTokens
if token.persisted? if token.persisted?
log_event(token) log_event(token)
notification_service.access_token_created(target_user, token.name)
ServiceResponse.success(payload: { personal_access_token: token }) ServiceResponse.success(payload: { personal_access_token: token })
else else
ServiceResponse.error(message: token.errors.full_messages.to_sentence, payload: { personal_access_token: token }) 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: ...@@ -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 | 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. | | 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 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. | | Personal access tokens have expired | User | Security email, always sent. |
| Project access level changed | User | Sent when user project access level is changed. | | 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._ | | 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 "" ...@@ -1608,6 +1608,12 @@ msgstr ""
msgid "A new impersonation token has been created." msgid "A new impersonation token has been created."
msgstr "" 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" msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
msgstr "" msgstr ""
...@@ -41979,6 +41985,12 @@ msgstr "" ...@@ -41979,6 +41985,12 @@ msgstr ""
msgid "You can always edit this later" msgid "You can always edit this later"
msgstr "" 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}." msgid "You can create a new %{link}."
msgstr "" msgstr ""
......
...@@ -123,6 +123,39 @@ RSpec.describe Emails::Profile do ...@@ -123,6 +123,39 @@ RSpec.describe Emails::Profile do
end end
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 describe 'user personal access token is about to expire' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:expiring_token) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) } 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 ...@@ -258,6 +258,27 @@ RSpec.describe NotificationService, :mailer do
end end
describe 'AccessToken' do 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 describe '#access_token_about_to_expire' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:pat) { create(:personal_access_token, user: user, expires_at: 5.days.from_now) } 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 ...@@ -18,6 +18,14 @@ RSpec.describe PersonalAccessTokens::CreateService do
subject subject
end 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 end
shared_examples_for 'an unsuccessfully created token' do 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