diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index ab5c136fee3844aca7647dffa7e2eea9364f26bc..7136c1b4692b75e5ee5b5834d75ca31bec2c8d72 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -181,10 +181,18 @@ def edit_group_origin_location def destroy Groups::DestroyService.new(@group, current_user).async_execute + message = format(_("Group '%{group_name}' is being deleted."), group_name: @group.full_name) - flash[:toast] = format(_("Group '%{group_name}' is being deleted."), group_name: @group.full_name) + respond_to do |format| + format.html do + flash[:toast] = message + redirect_to root_path, status: :found + end - redirect_to root_path, status: :found + format.json do + render json: { message: message } + end + end end # rubocop: disable CodeReuse/ActiveRecord diff --git a/ee/app/controllers/ee/groups_controller.rb b/ee/app/controllers/ee/groups_controller.rb index 26eeb999615bb3d6476367ecce2d5c5d42c09793..d3d43a64d3f6218f30040415848015a0fee86c27 100644 --- a/ee/app/controllers/ee/groups_controller.rb +++ b/ee/app/controllers/ee/groups_controller.rb @@ -49,9 +49,31 @@ def destroy result = ::Groups::MarkForDeletionService.new(group, current_user).execute if result[:status] == :success - redirect_to group_path(group), status: :found + respond_to do |format| + format.html do + redirect_to group_path(group), status: :found + end + + format.json do + render json: { + message: format( + _("'%{group_name}' has been scheduled for deletion and will be deleted on %{date}."), + group_name: group.name, + date: permanent_deletion_date_formatted(group, group.marked_for_deletion_on) + ) + } + end + end else - redirect_to edit_group_path(group), status: :found, alert: result[:message] + respond_to do |format| + format.html do + redirect_to edit_group_path(group), status: :found, alert: result[:message] + end + + format.json do + render json: { message: result[:message] }, status: :unprocessable_entity + end + end end end @@ -71,9 +93,17 @@ def restore def check_subscription! if group.linked_to_subscription? - redirect_to edit_group_path(group), - status: :found, - alert: _('This group is linked to a subscription') + respond_to do |format| + format.html do + redirect_to edit_group_path(group), + status: :found, + alert: _('This group is linked to a subscription') + end + + format.json do + render json: { message: _('This group is linked to a subscription') }, status: :unprocessable_entity + end + end end end diff --git a/ee/spec/controllers/ee/groups_controller_spec.rb b/ee/spec/controllers/ee/groups_controller_spec.rb index bc6270278ced93e56935dd55b5a15782f2299773..cdee780de6088efeffab6096c04d18a4fc3a451f 100644 --- a/ee/spec/controllers/ee/groups_controller_spec.rb +++ b/ee/spec/controllers/ee/groups_controller_spec.rb @@ -246,7 +246,10 @@ end describe 'DELETE #destroy' do - subject { delete :destroy, params: { id: group.to_param } } + let(:format) { :html } + let(:params) { {} } + + subject { delete :destroy, format: format, params: { id: group.to_param, **params } } before do group.add_owner(user) @@ -273,10 +276,22 @@ end end - it 'redirects to group path' do - subject + context 'for a html request' do + it 'redirects to group path' do + subject - expect(response).to redirect_to(group_path(group)) + expect(response).to redirect_to(group_path(group)) + end + end + + context 'for a json request', :freeze_time do + let(:format) { :json } + + it 'returns json with message' do + subject + + expect(json_response['message']).to eq("'#{group.name}' has been scheduled for deletion and will be deleted on #{permanent_deletion_date_formatted(group, group.marked_for_deletion_on)}.") + end end end @@ -289,11 +304,23 @@ expect { subject }.not_to change { group.reload.marked_for_deletion? }.from(false) end - it 'redirects to group edit page' do - subject + context 'for a html request' do + it 'redirects to group edit page' do + subject - expect(response).to redirect_to(edit_group_path(group)) - expect(flash[:alert]).to include 'error' + expect(response).to redirect_to(edit_group_path(group)) + expect(flash[:alert]).to include 'error' + end + end + + context 'for a json request' do + let(:format) { :json } + + it 'returns json with message' do + subject + + expect(json_response['message']).to eq("error") + end end end @@ -303,39 +330,108 @@ end context 'when permanently_remove param is set' do - it 'deletes the group immediately' do - expect(GroupDestroyWorker).to receive(:perform_async) + let(:params) { { permanently_remove: true } } - delete :destroy, params: { id: group.to_param, permanently_remove: true } + context 'for a html request' do + it 'deletes the group immediately and redirects to root path' do + expect(GroupDestroyWorker).to receive(:perform_async) - expect(response).to redirect_to(root_path) - expect(flash[:toast]).to include "Group '#{group.name}' is being deleted." + subject + + expect(response).to redirect_to(root_path) + expect(flash[:toast]).to include "Group '#{group.name}' is being deleted." + end + end + + context 'for a json request' do + let(:format) { :json } + + it 'deletes the group immediately and returns json with message' do + expect(GroupDestroyWorker).to receive(:perform_async) + + subject + + expect(json_response['message']).to eq("Group '#{group.name}' is being deleted.") + end end end context 'when permanently_remove param is not set' do - it 'does nothing' do - subject + context 'for a html request' do + it 'redirects to edit path with error' do + subject - expect(response).to redirect_to(edit_group_path(group)) - expect(flash[:alert]).to include "Group has been already marked for deletion" + expect(response).to redirect_to(edit_group_path(group)) + expect(flash[:alert]).to include "Group has been already marked for deletion" + end + end + + context 'for a json request' do + let(:format) { :json } + + it 'returns json with message' do + subject + + expect(json_response['message']).to eq("Group has been already marked for deletion") + end end end end end - context 'delayed deletion feature is not available' do + context 'delayed deletion feature is not available', :sidekiq_inline do before do stub_licensed_features(adjourned_deletion_for_projects_and_groups: false) end - it 'immediately schedules a group destroy and redirects to root page with alert about immediate deletion' do - Sidekiq::Testing.fake! do - expect { subject }.to change { GroupDestroyWorker.jobs.size }.by(1) + context 'for a html request' do + it 'immediately schedules a group destroy and redirects to root page with alert about immediate deletion' do + Sidekiq::Testing.fake! do + expect { subject }.to change { GroupDestroyWorker.jobs.size }.by(1) + end + + expect(response).to redirect_to(root_path) + expect(flash[:toast]).to include "Group '#{group.name}' is being deleted." + end + end + + context 'for a json request' do + let(:format) { :json } + + it 'immediately schedules a group destroy and returns json with message' do + Sidekiq::Testing.fake! do + expect { subject }.to change { GroupDestroyWorker.jobs.size }.by(1) + end + + expect(json_response['message']).to eq("Group '#{group.name}' is being deleted.") + end + end + end + + context 'when group is linked to a subscription', :saas do + let_it_be(:group_with_plan) do + create(:group_with_plan, plan: :ultimate_plan, owners: user, organization: current_organization) + end + + let(:params) { { id: group_with_plan.to_param } } + + context 'for a html request' do + it 'redirects to edit page with alert' do + subject + + expect(response).to redirect_to(edit_group_path(group_with_plan)) + expect(flash[:alert]).to eq 'This group is linked to a subscription' end + end + + context 'for a json request' do + let(:format) { :json } - expect(response).to redirect_to(root_path) - expect(flash[:toast]).to include "Group '#{group.name}' is being deleted." + it 'returns json with message' do + subject + + expect(json_response['message']).to eq('This group is linked to a subscription') + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b082b5f0a97a228bb37b2c084365bc9a571d0a6b..2ef75e7d417e2b829c4e7dc079b322ad72d5ce32 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1639,6 +1639,9 @@ msgstr "" msgid "%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}v*%{code_tag_end} or %{code_tag_start}*-release%{code_tag_end} are supported." msgstr "" +msgid "'%{group_name}' has been scheduled for deletion and will be deleted on %{date}." +msgstr "" + msgid "'%{group_name}' has been scheduled for removal on %{removal_time}." msgstr "" diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 7a98c8eae04dd1a4b71b6ba49d7fdf85b19cb0b1..7f4d6bbf89f4b686b7d8419167ed2dc0a6851cf5 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -545,12 +545,23 @@ sign_in(user) end - it 'schedules a group destroy and redirects to the root path' do - Sidekiq::Testing.fake! do - expect { delete :destroy, params: { id: group.to_param } }.to change(GroupDestroyWorker.jobs, :size).by(1) + context 'for a html request' do + it 'schedules a group destroy and redirects to the root path' do + Sidekiq::Testing.fake! do + expect { delete :destroy, params: { id: group.to_param } }.to change(GroupDestroyWorker.jobs, :size).by(1) + end + expect(flash[:toast]).to eq(format(_("Group '%{group_name}' is being deleted."), group_name: group.full_name)) + expect(response).to redirect_to(root_path) + end + end + + context 'for a json request' do + it 'schedules a group destroy and returns message' do + Sidekiq::Testing.fake! do + expect { delete :destroy, format: :json, params: { id: group.to_param } }.to change(GroupDestroyWorker.jobs, :size).by(1) + end + expect(Gitlab::Json.parse(response.body)).to eq({ 'message' => "Group '#{group.full_name}' is being deleted." }) end - expect(flash[:toast]).to eq(format(_("Group '%{group_name}' is being deleted."), group_name: group.full_name)) - expect(response).to redirect_to(root_path) end end end