Skip to content
Snippets Groups Projects
Commit 5799e083 authored by Rémy Coutable's avatar Rémy Coutable
Browse files

Merge branch 'banned-user-admin-email' into 'master'

Add email to send to admin when a user is auto banned

See merge request gitlab-org/gitlab!88057
parents 35f817d6 43fe701c
No related branches found
No related tags found
No related merge requests found
Showing
with 159 additions and 76 deletions
Loading
Loading
@@ -15,5 +15,18 @@ def send_unsubscribed_notification(user_id)
email = user.notification_email_or_default
mail to: email, subject: "Unsubscribed from GitLab administrator notifications"
end
def user_auto_banned_email(admin_id, user_id, max_project_downloads:, within_seconds:)
admin = User.find(admin_id)
@user = User.find(user_id)
@max_project_downloads = max_project_downloads
@within_minutes = within_seconds / 60
Gitlab::I18n.with_locale(admin.preferred_language) do
email_with_layout(
to: admin.notification_email_or_default,
subject: subject(_("We've detected unusual activity")))
end
end
end
end
Loading
Loading
@@ -8,11 +8,9 @@ def autodevops_disabled_email(pipeline, recipient)
 
add_project_headers
 
mail(to: recipient,
subject: auto_devops_disabled_subject(@project.name)) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: recipient,
subject: auto_devops_disabled_subject(@project.name))
end
 
private
Loading
Loading
Loading
Loading
@@ -94,10 +94,9 @@ def import_issues_csv_email(user_id, project_id, results)
@project = Project.find(project_id)
@results = results
 
mail(to: @user.notification_email_for(@project.group), subject: subject('Imported issues')) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: @user.notification_email_for(@project.group),
subject: subject('Imported issues'))
end
 
def issues_csv_email(user, project, csv_data, export_status)
Loading
Loading
@@ -110,10 +109,9 @@ def issues_csv_email(user, project, csv_data, export_status)
 
filename = "#{project.full_path.parameterize}_issues_#{Date.today.iso8601}.csv"
attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
mail(to: user.notification_email_for(@project.group), subject: subject("Exported issues")) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: user.notification_email_for(@project.group),
subject: subject("Exported issues"))
end
 
private
Loading
Loading
Loading
Loading
@@ -21,7 +21,7 @@ def member_access_requested_email(member_source_type, member_id, recipient_id)
 
user = User.find(recipient_id)
 
member_email_with_layout(
email_with_layout(
to: user.notification_email_for(notification_group),
subject: subject("Request to join the #{member_source.human_name} #{member_source.model_name.singular}"))
end
Loading
Loading
@@ -32,7 +32,7 @@ def member_access_granted_email(member_source_type, member_id)
 
return unless member_exists?
 
member_email_with_layout(
email_with_layout(
to: member.user.notification_email_for(notification_group),
subject: subject("Access to the #{member_source.human_name} #{member_source.model_name.singular} was granted"))
end
Loading
Loading
@@ -47,7 +47,7 @@ def member_access_denied_email(member_source_type, source_id, user_id)
 
human_name = @source_hidden ? 'Hidden' : member_source.human_name
 
member_email_with_layout(
email_with_layout(
to: user.notification_email_for(notification_group),
subject: subject("Access to the #{human_name} #{member_source.model_name.singular} was denied"))
end
Loading
Loading
@@ -83,7 +83,7 @@ def member_invited_reminder_email(member_source_type, member_id, token, reminder
 
subject_line = subjects[reminder_index] % { inviter: member.created_by.name }
 
member_email_with_layout(
email_with_layout(
layout: 'unknown_user_mailer',
to: member.invite_email,
subject: subject(subject_line)
Loading
Loading
@@ -97,7 +97,7 @@ def member_invite_accepted_email(member_source_type, member_id)
return unless member_exists?
return unless member.created_by
 
member_email_with_layout(
email_with_layout(
to: member.created_by.notification_email_for(notification_group),
subject: subject('Invitation accepted'))
end
Loading
Loading
@@ -111,7 +111,7 @@ def member_invite_declined_email(member_source_type, source_id, invite_email, cr
 
user = User.find(created_by_id)
 
member_email_with_layout(
email_with_layout(
to: user.notification_email_for(notification_group),
subject: subject('Invitation declined'))
end
Loading
Loading
@@ -128,7 +128,7 @@ def member_expiration_date_updated_email(member_source_type, member_id)
_('Group membership expiration date removed')
end
 
member_email_with_layout(
email_with_layout(
to: member.user.notification_email_for(notification_group),
subject: subject(subject))
end
Loading
Loading
@@ -176,13 +176,6 @@ def member_exists?
def member_source_class
@member_source_type.classify.constantize
end
def member_email_with_layout(to:, subject:, layout: 'mailer')
mail(to: to, subject: subject) do |format|
format.html { render layout: layout }
format.text { render layout: layout }
end
end
end
end
 
Loading
Loading
Loading
Loading
@@ -149,10 +149,9 @@ def merge_requests_csv_email(user, project, csv_data, export_status)
 
filename = "#{project.full_path.parameterize}_merge_requests_#{Date.current.iso8601}.csv"
attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
mail(to: user.notification_email_for(@project.group), subject: subject("Exported merge requests")) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: user.notification_email_for(@project.group),
subject: subject("Exported merge requests"))
end
 
def approved_merge_request_email(recipient_id, merge_request_id, approved_by_user_id, reason = nil)
Loading
Loading
Loading
Loading
@@ -30,11 +30,9 @@ def pipeline_mail(pipeline, recipient, status)
 
add_headers
 
mail(to: recipient,
subject: subject(pipeline_subject(status))) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: recipient,
subject: subject(pipeline_subject(status)))
end
 
def add_headers
Loading
Loading
Loading
Loading
@@ -13,7 +13,7 @@ def instance_access_request_email(user, recipient)
@user = user
@recipient = recipient
 
profile_email_with_layout(
email_with_layout(
to: recipient.notification_email_or_default,
subject: subject(_("GitLab Account Request")))
end
Loading
Loading
@@ -21,7 +21,7 @@ def instance_access_request_email(user, recipient)
def user_admin_rejection_email(name, email)
@name = name
 
profile_email_with_layout(
email_with_layout(
to: email,
subject: subject(_("GitLab account request rejected")))
end
Loading
Loading
@@ -29,7 +29,7 @@ def user_admin_rejection_email(name, email)
def user_deactivated_email(name, email)
@name = name
 
profile_email_with_layout(
email_with_layout(
to: email,
subject: subject(_('Your account has been deactivated')))
end
Loading
Loading
@@ -125,7 +125,7 @@ def unknown_sign_in_email(user, ip, time)
@target_url = edit_profile_password_url
 
Gitlab::I18n.with_locale(@user.preferred_language) do
profile_email_with_layout(
email_with_layout(
to: @user.notification_email_or_default,
subject: subject(_("%{host} sign-in from new location") % { host: Gitlab.config.gitlab.host }))
end
Loading
Loading
@@ -151,15 +151,6 @@ def new_email_address_added_email(user, email)
mail(to: @user.notification_email_or_default, subject: subject(_("New email address added")))
end
end
private
def profile_email_with_layout(to:, subject:, layout: 'mailer')
mail(to: to, subject: subject) do |format|
format.html { render layout: layout }
format.text { render layout: layout }
end
end
end
end
 
Loading
Loading
Loading
Loading
@@ -75,11 +75,9 @@ def inactive_project_deletion_warning_email(project, user, deletion_date)
subject_text = "Action required: Project #{project.name} is scheduled to be deleted on " \
"#{deletion_date} due to inactivity"
 
mail(to: user.notification_email_for(project.group),
subject: subject(subject_text)) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: user.notification_email_for(project.group),
subject: subject(subject_text))
end
 
private
Loading
Loading
Loading
Loading
@@ -222,6 +222,13 @@ def add_unsubscription_headers_and_links
headers['List-Unsubscribe'] = list_unsubscribe_methods.map { |e| "<#{e}>" }.join(',')
@unsubscribe_url = unsubscribe_sent_notification_url(@sent_notification)
end
def email_with_layout(to:, subject:, layout: 'mailer')
mail(to: to, subject: subject) do |format|
format.html { render layout: layout }
format.text { render layout: layout }
end
end
end
 
Notify.prepend_mod_with('Notify')
Loading
Loading
@@ -205,6 +205,10 @@ def inactive_project_deletion_warning
Notify.inactive_project_deletion_warning_email(project, user, '2022-04-22').message
end
 
def user_auto_banned_email
::Notify.user_auto_banned_email(user.id, user.id, max_project_downloads: 5, within_seconds: 600).message
end
private
 
def project
Loading
Loading
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe
- link_end = '</a>'.html_safe
= email_default_heading(_("We've detected some unusual activity"))
%p
= _('We want to let you know %{username} has been banned from your GitLab instance due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes.') % { username: sanitize_name(@user.name), max_project_downloads: @max_project_downloads, within_minutes: @within_minutes }
%p
= _('If this is a mistake, you can %{link_start}unban them%{link_end}.').html_safe % { link_start: link_start % { url: admin_users_url(filter: 'banned') }, link_end: link_end }
%p
= _('You can adjust rules on auto-banning %{link_start}here%{link_end}.').html_safe % { link_start: link_start % { url: network_admin_application_settings_url(anchor: 'js-ip-limits-settings') }, link_end: link_end }
<%= _("We've detected some unusual activity") %>
<%= _('We want to let you know %{username} has been banned from your GitLab instance due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes.') % { username: sanitize_name(@user.name), max_project_downloads: @max_project_downloads, within_minutes: @within_minutes } %>
<%= _('If this is a mistake, you can unban them: %{url}.') % { url: admin_users_url(filter: 'banned') } %>
<%= _('You can adjust rules on auto-banning here: %{url}.') % { url: network_admin_application_settings_url(anchor: 'js-ip-limits-settings') } %>
Loading
Loading
@@ -10,7 +10,7 @@ def provisioned_member_access_granted_email(member_id)
 
@user = member.user
 
member_email_with_layout(
email_with_layout(
to: member.user.email,
subject: subject("Welcome to GitLab"))
end
Loading
Loading
Loading
Loading
@@ -36,10 +36,9 @@ def user_escalation_rule_deleted_email(user, project, rules, recipient)
@project = project
@rules = rules
 
mail(to: recipient.notification_email_for(@project.group), subject: subject('User removed from escalation policy')) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: recipient.notification_email_for(@project.group),
subject: subject('User removed from escalation policy'))
end
 
def incident_escalation_fired_email(project, user, issue)
Loading
Loading
Loading
Loading
@@ -7,10 +7,9 @@ def memberships_export_email(csv_data:, requested_by:, group:)
 
filename = "#{group.full_path.parameterize}_group_memberships_#{Date.current.iso8601}.csv"
attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
mail(to: requested_by.notification_email_for(group), subject: "Exported group membership list") do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: requested_by.notification_email_for(group),
subject: "Exported group membership list")
end
end
end
Loading
Loading
@@ -10,10 +10,9 @@ def user_removed_from_rotation_email(user, rotation, recipients)
@schedule = rotation.schedule
@project = rotation.project
 
mail(to: recipients.map(&:email), subject: subject('User removed from On-call rotation')) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: recipients.map(&:email),
subject: subject('User removed from On-call rotation'))
end
end
end
Loading
Loading
@@ -7,7 +7,9 @@ def import_requirements_csv_email(user_id, project_id, results)
@project = Project.find(project_id)
@results = results
 
requirement_email_with_layout(@user, @project.group, _('Imported requirements'))
email_with_layout(
to: @user.notification_email_for(@project.group),
subject: subject(_('Imported requirements')))
end
 
def requirements_csv_email(user, project, csv_data, export_status)
Loading
Loading
@@ -18,14 +20,9 @@ def requirements_csv_email(user, project, csv_data, export_status)
filename = "#{project.full_path.parameterize}_requirements_#{Date.current.iso8601}.csv"
attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
 
requirement_email_with_layout(user, @project.group, _('Exported requirements'))
end
def requirement_email_with_layout(user, group, subj)
mail(to: user.notification_email_for(group), subject: subject(subj)) do |format|
format.html { render layout: 'mailer' }
format.text { render layout: 'mailer' }
end
email_with_layout(
to: user.notification_email_for(@project.group),
subject: subject(_('Exported requirements')))
end
end
end
Loading
Loading
@@ -19162,6 +19162,12 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
 
msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
msgstr ""
msgid "If this is a mistake, you can unban them: %{url}."
msgstr ""
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
 
Loading
Loading
@@ -42469,6 +42475,9 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
 
msgid "We want to let you know %{username} has been banned from your GitLab instance due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr ""
 
Loading
Loading
@@ -42484,6 +42493,12 @@ msgstr ""
msgid "We're experiencing difficulties and this tab content is currently unavailable."
msgstr ""
 
msgid "We've detected some unusual activity"
msgstr ""
msgid "We've detected unusual activity"
msgstr ""
msgid "We've found no vulnerabilities"
msgstr ""
 
Loading
Loading
@@ -43304,6 +43319,12 @@ msgstr ""
msgid "You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
 
msgid "You can adjust rules on auto-banning %{link_start}here%{link_end}."
msgstr ""
msgid "You can adjust rules on auto-banning here: %{url}."
msgstr ""
msgid "You can also create a project from the command line."
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -3,9 +3,62 @@
require 'spec_helper'
 
RSpec.describe Emails::AdminNotification do
include EmailSpec::Matchers
include_context 'gitlab email notification'
it 'adds email methods to Notify' do
subject.instance_methods.each do |email_method|
expect(Notify).to be_respond_to(email_method)
end
end
describe 'user_auto_banned_email' do
let_it_be(:admin) { create(:user) }
let_it_be(:user) { create(:user) }
let(:max_project_downloads) { 5 }
let(:time_period) { 600 }
subject do
Notify.user_auto_banned_email(
admin.id, user.id,
max_project_downloads: max_project_downloads,
within_seconds: time_period
)
end
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_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
it 'is sent to the administrator' do
is_expected.to deliver_to admin.email
end
it 'has the correct subject' do
is_expected.to have_subject "We've detected unusual activity"
end
it 'includes the name of the user' do
is_expected.to have_body_text user.name
end
it 'includes the reason' do
is_expected.to have_body_text "due to them downloading more than 5 project repositories within 10 minutes"
end
it 'includes a link to unban the user' do
is_expected.to have_body_text admin_users_url(filter: 'banned')
end
it 'includes a link to change the settings' do
is_expected.to have_body_text network_admin_application_settings_url(anchor: 'js-ip-limits-settings')
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment