Commit 172fed32 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch 'georgekoltsov/add-group-export-email-nofitication' into 'master'

Add email notification on group export complete

See merge request gitlab-org/gitlab!30522
parents 06827800 365b5da3
...@@ -146,7 +146,7 @@ class GroupsController < Groups::ApplicationController ...@@ -146,7 +146,7 @@ class GroupsController < Groups::ApplicationController
export_service = Groups::ImportExport::ExportService.new(group: @group, user: current_user) export_service = Groups::ImportExport::ExportService.new(group: @group, user: current_user)
if export_service.async_execute if export_service.async_execute
redirect_to edit_group_path(@group), notice: _('Group export started.') redirect_to edit_group_path(@group), notice: _('Group export started. A download link will be sent by email.')
else else
redirect_to edit_group_path(@group), alert: _('Group export could not be started.') redirect_to edit_group_path(@group), alert: _('Group export could not be started.')
end end
......
# frozen_string_literal: true
module Emails
module Groups
def group_was_exported_email(current_user, group)
group_email(current_user, group, _('Group was exported'))
end
def group_was_not_exported_email(current_user, group, errors)
group_email(current_user, group, _('Group export error'), errors: errors)
end
def group_email(current_user, group, subj, errors: nil)
@group = group
@errors = errors
mail(to: current_user.notification_email_for(@group), subject: subject(subj))
end
end
end
...@@ -17,6 +17,7 @@ class Notify < ApplicationMailer ...@@ -17,6 +17,7 @@ class Notify < ApplicationMailer
include Emails::AutoDevops include Emails::AutoDevops
include Emails::RemoteMirrors include Emails::RemoteMirrors
include Emails::Releases include Emails::Releases
include Emails::Groups
helper MilestonesHelper helper MilestonesHelper
helper MergeRequestsHelper helper MergeRequestsHelper
......
...@@ -96,6 +96,8 @@ module Groups ...@@ -96,6 +96,8 @@ module Groups
group_name: @group.name, group_name: @group.name,
message: 'Group Import/Export: Export succeeded' message: 'Group Import/Export: Export succeeded'
) )
notification_service.group_was_exported(@group, @current_user)
end end
def notify_error def notify_error
...@@ -105,6 +107,12 @@ module Groups ...@@ -105,6 +107,12 @@ module Groups
error: @shared.errors.join(', '), error: @shared.errors.join(', '),
message: 'Group Import/Export: Export failed' message: 'Group Import/Export: Export failed'
) )
notification_service.group_was_not_exported(@group, @current_user, @shared.errors)
end
def notification_service
@notification_service ||= NotificationService.new
end end
end end
end end
......
...@@ -545,6 +545,18 @@ class NotificationService ...@@ -545,6 +545,18 @@ class NotificationService
end end
end end
def group_was_exported(group, current_user)
return true unless notifiable?(current_user, :mention, group: group)
mailer.group_was_exported_email(current_user, group).deliver_later
end
def group_was_not_exported(group, current_user, errors)
return true unless notifiable?(current_user, :mention, group: group)
mailer.group_was_not_exported_email(current_user, group, errors).deliver_later
end
protected protected
def new_resource_email(target, method) def new_resource_email(target, method)
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
%li= _('Projects') %li= _('Projects')
%li= _('Runner tokens') %li= _('Runner tokens')
%li= _('SAML discovery tokens') %li= _('SAML discovery tokens')
%p= _('Once the exported file is ready you can download it from this page.') %p= _('Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page.')
- if group.export_file_exists? - if group.export_file_exists?
= link_to _('Regenerate export'), export_group_path(group), = link_to _('Regenerate export'), export_group_path(group),
method: :post, class: 'btn btn-default', data: { qa_selector: 'regenerate_export_group_link' } method: :post, class: 'btn btn-default', data: { qa_selector: 'regenerate_export_group_link' }
......
%p
= _('Group %{group_name} was exported successfully.') % { group_name: @group.name }
%p
= _('The group export can be downloaded from:')
= link_to download_export_group_url(@group), rel: 'nofollow', download: '' do
#{@group.full_name} export
%p
= _('The download link will expire in 24 hours.')
<%= _('Group %{group_name} was exported successfully.') % { group_name: @group.name } %>
<%= _('The group export can be downloaded from:') %>
<%= download_export_group_url(@group) %>
<%= _('The download link will expire in 24 hours.') %>
%p
= _("Group %{group_name} couldn't be exported.") % { group_name: @group.name }
%p
= _('The errors we encountered were:')
%ul
- @errors.each do |error|
%li
#{error}
<%= _("Group %{group_name} couldn't be exported.") % { group_name: @group.name } %>
<%= _('The errors we encountered were:') %>
<% @errors.each do |error| -%>
- <%= error %>
<% end -%>
---
title: Add email notification on group export complete
merge_request: 30522
author:
type: added
...@@ -63,8 +63,11 @@ For more details on the specific data persisted in a group export, see the ...@@ -63,8 +63,11 @@ For more details on the specific data persisted in a group export, see the
![Export group panel](img/export_panel.png) ![Export group panel](img/export_panel.png)
1. Once the export is generated, you can click **Download export** to download the [exported contents](#exported-contents) 1. Once the export is generated, you should receive an e-mail with a link to the [exported contents](#exported-contents)
in a compressed tar archive, with contents in JSON format. You can also return to this page to regenerate the export data. in a compressed tar archive, with contents in JSON format.
1. Alternatively, you can come back to the project settings and download the
file from there by clicking **Download export**, or generate a new file by clicking **Regenerate export**.
## Rate Limits ## Rate Limits
......
...@@ -10496,6 +10496,12 @@ msgstr "" ...@@ -10496,6 +10496,12 @@ msgstr ""
msgid "Group" msgid "Group"
msgstr "" msgstr ""
msgid "Group %{group_name} couldn't be exported."
msgstr ""
msgid "Group %{group_name} was exported successfully."
msgstr ""
msgid "Group %{group_name} was scheduled for deletion." msgid "Group %{group_name} was scheduled for deletion."
msgstr "" msgstr ""
...@@ -10547,10 +10553,13 @@ msgstr "" ...@@ -10547,10 +10553,13 @@ msgstr ""
msgid "Group export could not be started." msgid "Group export could not be started."
msgstr "" msgstr ""
msgid "Group export error"
msgstr ""
msgid "Group export link has expired. Please generate a new export from your group settings." msgid "Group export link has expired. Please generate a new export from your group settings."
msgstr "" msgstr ""
msgid "Group export started." msgid "Group export started. A download link will be sent by email."
msgstr "" msgstr ""
msgid "Group has been already marked for deletion" msgid "Group has been already marked for deletion"
...@@ -10595,6 +10604,9 @@ msgstr "" ...@@ -10595,6 +10604,9 @@ msgstr ""
msgid "Group variables (inherited)" msgid "Group variables (inherited)"
msgstr "" msgstr ""
msgid "Group was exported"
msgstr ""
msgid "Group was successfully updated." msgid "Group was successfully updated."
msgstr "" msgstr ""
...@@ -14492,9 +14504,6 @@ msgstr "" ...@@ -14492,9 +14504,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source." msgid "Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source."
msgstr "" msgstr ""
msgid "Once the exported file is ready you can download it from this page."
msgstr ""
msgid "Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page." msgid "Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page."
msgstr "" msgstr ""
...@@ -21027,9 +21036,15 @@ msgstr "" ...@@ -21027,9 +21036,15 @@ msgstr ""
msgid "The domain you entered is not allowed." msgid "The domain you entered is not allowed."
msgstr "" msgstr ""
msgid "The download link will expire in 24 hours."
msgstr ""
msgid "The entered user map is not a valid JSON user map." msgid "The entered user map is not a valid JSON user map."
msgstr "" msgstr ""
msgid "The errors we encountered were:"
msgstr ""
msgid "The file has been successfully created." msgid "The file has been successfully created."
msgstr "" msgstr ""
...@@ -21068,6 +21083,9 @@ msgstr "" ...@@ -21068,6 +21083,9 @@ msgstr ""
msgid "The group can be fully restored" msgid "The group can be fully restored"
msgstr "" msgstr ""
msgid "The group export can be downloaded from:"
msgstr ""
msgid "The group has already been shared with this group" msgid "The group has already been shared with this group"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
require 'email_spec'
describe Emails::Groups do
include EmailSpec::Matchers
let(:group) { create(:group) }
let(:user) { create(:user) }
before do
group.add_owner(user)
end
describe '#group_was_exported_email' do
subject { Notify.group_was_exported_email(user, group) }
it 'sends success email' do
expect(subject).to have_subject "#{group.name} | Group was exported"
expect(subject).to have_body_text 'The download link will expire in 24 hours.'
expect(subject).to have_body_text "groups/#{group.path}/-/download_export"
end
end
describe '#group_was_not_exported_email' do
let(:shared) { Gitlab::ImportExport::Shared.new(group) }
let(:error) { Gitlab::ImportExport::Error.new('Error!') }
before do
shared.error(error)
end
subject { Notify.group_was_not_exported_email(user, group, shared.errors) }
it 'sends failure email' do
expect(subject).to have_subject "#{group.name} | Group export error"
expect(subject).to have_body_text "Group #{group.name} couldn't be exported."
end
end
end
...@@ -71,6 +71,14 @@ describe Groups::ImportExport::ExportService do ...@@ -71,6 +71,14 @@ describe Groups::ImportExport::ExportService do
service.execute service.execute
end end
it 'notifies the user' do
expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:group_was_exported)
end
service.execute
end
context 'when saver succeeds' do context 'when saver succeeds' do
it 'saves the group in the file system' do it 'saves the group in the file system' do
service.execute service.execute
...@@ -114,16 +122,26 @@ describe Groups::ImportExport::ExportService do ...@@ -114,16 +122,26 @@ describe Groups::ImportExport::ExportService do
context 'when export fails' do context 'when export fails' do
context 'when file saver fails' do context 'when file saver fails' do
it 'removes the remaining exported data' do before do
allow_next_instance_of(Gitlab::ImportExport::Saver) do |saver| allow_next_instance_of(Gitlab::ImportExport::Saver) do |saver|
allow(saver).to receive(:save).and_return(false) allow(saver).to receive(:save).and_return(false)
end end
end
it 'removes the remaining exported data' do
expect { service.execute }.to raise_error(Gitlab::ImportExport::Error) expect { service.execute }.to raise_error(Gitlab::ImportExport::Error)
expect(group.import_export_upload).to be_nil expect(group.import_export_upload).to be_nil
expect(File.exist?(shared.archive_path)).to eq(false) expect(File.exist?(shared.archive_path)).to eq(false)
end end
it 'notifies the user about failed group export' do
expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:group_was_not_exported)
end
expect { service.execute }.to raise_error(Gitlab::ImportExport::Error)
end
end end
context 'when file compression fails' do context 'when file compression fails' 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