Commit 524564af authored by Markus Koller's avatar Markus Koller

Merge branch 'ag/321645-ci-minutes-create-a-banner-backend' into 'master'

[CI Minutes] Add success banner

See merge request gitlab-org/gitlab!66901
parents 702ecb2a eddabbbe
# frozen_string_literal: true # frozen_string_literal: true
class SubscriptionsController < ApplicationController class SubscriptionsController < ApplicationController
include InternalRedirect
layout 'checkout' layout 'checkout'
skip_before_action :authenticate_user!, only: [:new] skip_before_action :authenticate_user!, only: [:new]
...@@ -62,16 +64,8 @@ class SubscriptionsController < ApplicationController ...@@ -62,16 +64,8 @@ class SubscriptionsController < ApplicationController
).execute ).execute
if response[:success] if response[:success]
plan_id, quantity = subscription_params.values_at(:plan_id, :quantity)
redirect_location = if params[:selected_group]
group_path(group, plan_id: plan_id, purchased_quantity: quantity)
else
edit_subscriptions_group_path(group.path, plan_id: plan_id, quantity: quantity, new_user: params[:new_user])
end
experiment(:force_company_trial, user: current_user).track(:create_subscription, namespace: group, user: current_user) experiment(:force_company_trial, user: current_user).track(:create_subscription, namespace: group, user: current_user)
response[:data] = { location: redirect_location(group) }
response[:data] = { location: redirect_location }
end end
render json: response[:data] render json: response[:data]
...@@ -79,6 +73,15 @@ class SubscriptionsController < ApplicationController ...@@ -79,6 +73,15 @@ class SubscriptionsController < ApplicationController
private private
def redirect_location(group)
return safe_redirect_path(params[:redirect_after_success]) if params[:redirect_after_success]
plan_id, quantity = subscription_params.values_at(:plan_id, :quantity)
return group_path(group, plan_id: plan_id, purchased_quantity: quantity) if params[:selected_group]
edit_subscriptions_group_path(group.path, plan_id: plan_id, quantity: quantity, new_user: params[:new_user])
end
def customer_params def customer_params
params.require(:customer).permit(:country, :address_1, :address_2, :city, :state, :zip_code, :company) params.require(:customer).permit(:country, :address_1, :address_2, :city, :state, :zip_code, :company)
end end
......
...@@ -105,6 +105,10 @@ module EE ...@@ -105,6 +105,10 @@ module EE
group.licensed_feature_available?(:adjourned_deletion_for_projects_and_groups) group.licensed_feature_available?(:adjourned_deletion_for_projects_and_groups)
end end
def show_product_purchase_success_alert?
!params[:purchased_product].blank?
end
private private
def get_group_sidebar_links def get_group_sidebar_links
......
...@@ -16,6 +16,12 @@ module SubscriptionsHelper ...@@ -16,6 +16,12 @@ module SubscriptionsHelper
} }
end end
def buy_minutes_addon_data(group)
{
redirect_after_success: group_usage_quotas_path(group, purchased_product: _('CI minutes'))
}.merge(addon_data(group))
end
def addon_data(group) def addon_data(group)
{ {
group_data: [present_group(group)].to_json, group_data: [present_group(group)].to_json,
......
= render 'shared/global_alert',
title: _('Thanks for your purchase!'),
variant: :success,
close_button_data: { testid: 'close-product-purchase-success' } do
.gl-alert-body
= _('You have successfully purchased %{product}. You\'ll receive a receipt by mail.') % { product: product_name }
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
- url_to_purchase_storage = purchase_storage_url if purchase_storage_link_enabled?(@group) - url_to_purchase_storage = purchase_storage_url if purchase_storage_link_enabled?(@group)
- other_storage_enabled = Feature.enabled?(:other_storage_tab, @group) - other_storage_enabled = Feature.enabled?(:other_storage_tab, @group)
- if show_product_purchase_success_alert?
= render 'product_purchase_success_alert', product_name: params[:purchased_product]
%h3.page-title %h3.page-title
= s_('UsageQuota|Usage Quotas') = s_('UsageQuota|Usage Quotas')
......
- page_title _('Buy CI Minutes') - page_title _('Buy CI Minutes')
#js-buy-minutes{ data: addon_data(@group) } #js-buy-minutes{ data: buy_minutes_addon_data(@group) }
...@@ -272,10 +272,13 @@ RSpec.describe SubscriptionsController do ...@@ -272,10 +272,13 @@ RSpec.describe SubscriptionsController do
{ {
selected_group: selected_group.id, selected_group: selected_group.id,
customer: { country: 'NL' }, customer: { country: 'NL' },
subscription: { plan_id: 'x', quantity: 1, source: 'another_source' } subscription: { plan_id: 'x', quantity: 1, source: 'another_source' },
redirect_after_success: redirect_after_success
} }
end end
let_it_be(:redirect_after_success) { nil }
context 'when the selected group is eligible for a new subscription' do context 'when the selected group is eligible for a new subscription' do
let_it_be(:selected_group) { create(:group) } let_it_be(:selected_group) { create(:group) }
...@@ -311,6 +314,18 @@ RSpec.describe SubscriptionsController do ...@@ -311,6 +314,18 @@ RSpec.describe SubscriptionsController do
subject subject
end end
context 'when having an explicit redirect' do
let_it_be(:redirect_after_success) { '/-/path/to/redirect' }
it { is_expected.to have_gitlab_http_status(:ok) }
it 'returns the provided redirect path as location' do
subject
expect(response.body).to eq({ location: redirect_after_success }.to_json)
end
end
end end
context 'when the selected group is ineligible for a new subscription' do context 'when the selected group is ineligible for a new subscription' do
......
...@@ -95,6 +95,20 @@ RSpec.describe 'Groups > Usage Quotas' do ...@@ -95,6 +95,20 @@ RSpec.describe 'Groups > Usage Quotas' do
end end
end end
context 'when successfully purchasing CI Minutes' do
let(:group) { create(:group, :with_build_minutes) }
let!(:project) { create(:project, namespace: group, shared_runners_enabled: true) }
it 'does show a banner' do
visit group_usage_quotas_path(group, purchased_product: 'CI minutes')
page.within('#content-body') do
expect(page).to have_content('Thanks for your purchase!')
expect(page).to have_content('You have successfully purchased CI minutes.')
end
end
end
context 'minutes under quota' do context 'minutes under quota' do
let(:group) { create(:group, :with_not_used_build_minutes_limit) } let(:group) { create(:group, :with_not_used_build_minutes_limit) }
...@@ -162,7 +176,7 @@ RSpec.describe 'Groups > Usage Quotas' do ...@@ -162,7 +176,7 @@ RSpec.describe 'Groups > Usage Quotas' do
end end
end end
context 'when accesing root group' do context 'when accessing root group' do
let!(:subgroup) { create(:group, parent: group) } let!(:subgroup) { create(:group, parent: group) }
let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) } let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) }
......
...@@ -380,4 +380,26 @@ RSpec.describe GroupsHelper do ...@@ -380,4 +380,26 @@ RSpec.describe GroupsHelper do
it { expect(helper.show_delayed_project_removal_setting?(group)).to be result } it { expect(helper.show_delayed_project_removal_setting?(group)).to be result }
end end
end end
describe '#show_product_purchase_success_alert?' do
describe 'when purchased_product is present' do
before do
allow(controller).to receive(:params) { { purchased_product: product } }
end
where(:product, :result) do
'product' | true
'' | false
nil | false
end
with_them do
it { expect(helper.show_product_purchase_success_alert?).to be result }
end
end
describe 'when purchased_product is not present' do
it { expect(helper.show_product_purchase_success_alert?).to be false }
end
end
end end
...@@ -149,4 +149,22 @@ RSpec.describe SubscriptionsHelper do ...@@ -149,4 +149,22 @@ RSpec.describe SubscriptionsHelper do
it { is_expected.to include(source: 'some_source') } it { is_expected.to include(source: 'some_source') }
it { is_expected.to include(group_data: %Q{[{"id":#{group.id},"name":"My Namespace","users":1,"guests":0}]}) } it { is_expected.to include(group_data: %Q{[{"id":#{group.id},"name":"My Namespace","users":1,"guests":0}]}) }
end end
describe '#buy_minutes_addon_data' do
subject(:buy_minutes_addon_data) { helper.buy_minutes_addon_data(group) }
let_it_be(:user) { create(:user, name: 'First Last') }
let_it_be(:group) { create(:group, name: 'My Namespace') }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:params).and_return({ selected_group: group.id.to_s, source: 'some_source' })
group.add_owner(user)
end
it { is_expected.to include(namespace_id: group.id.to_s) }
it { is_expected.to include(source: 'some_source') }
it { is_expected.to include(group_data: %Q{[{"id":#{group.id},"name":"My Namespace","users":1,"guests":0}]}) }
it { is_expected.to include(redirect_after_success: group_usage_quotas_path(group, purchased_product: 'CI minutes')) }
end
end end
...@@ -20,20 +20,22 @@ RSpec.shared_examples_for 'subscription form data' do |js_selector| ...@@ -20,20 +20,22 @@ RSpec.shared_examples_for 'subscription form data' do |js_selector|
it { is_expected.to have_selector("#{js_selector}[data-source='some_source']") } it { is_expected.to have_selector("#{js_selector}[data-source='some_source']") }
end end
RSpec.shared_examples_for 'addon form data' do |js_selector| RSpec.shared_examples_for 'buy minutes addon form data' do |js_selector|
before do before do
allow(view).to receive(:addon_data).and_return( allow(view).to receive(:buy_minutes_addon_data).and_return(
plan_data: '[{"id":"ci_minutes_plan_id","code":"ci_minutes","price_per_year":10.0}]', group_data: '[{"id":"ci_minutes_plan_id","code":"ci_minutes","price_per_year":10.0}]',
namespace_id: '1', namespace_id: '1',
plan_id: 'ci_minutes_plan_id', plan_id: 'ci_minutes_plan_id',
source: 'some_source' source: 'some_source',
redirect_after_success: '/groups/my-ci-minutes-group/-/usage_quotas'
) )
end end
subject { render } subject { render }
it { is_expected.to have_selector("#{js_selector}[data-plan-data='[{\"id\":\"ci_minutes_plan_id\",\"code\":\"ci_minutes\",\"price_per_year\":10.0}]']") } it { is_expected.to have_selector("#{js_selector}[data-group-data='[{\"id\":\"ci_minutes_plan_id\",\"code\":\"ci_minutes\",\"price_per_year\":10.0}]']") }
it { is_expected.to have_selector("#{js_selector}[data-plan-id='ci_minutes_plan_id']") } it { is_expected.to have_selector("#{js_selector}[data-plan-id='ci_minutes_plan_id']") }
it { is_expected.to have_selector("#{js_selector}[data-namespace-id='1']") } it { is_expected.to have_selector("#{js_selector}[data-namespace-id='1']") }
it { is_expected.to have_selector("#{js_selector}[data-source='some_source']") } it { is_expected.to have_selector("#{js_selector}[data-source='some_source']") }
it { is_expected.to have_selector("#{js_selector}[data-redirect-after-success='/groups/my-ci-minutes-group/-/usage_quotas']") }
end end
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'subscriptions/buy_minutes' do RSpec.describe 'subscriptions/buy_minutes' do
it_behaves_like 'addon form data', '#js-buy-minutes' it_behaves_like 'buy minutes addon form data', '#js-buy-minutes'
end end
...@@ -5787,6 +5787,9 @@ msgstr "" ...@@ -5787,6 +5787,9 @@ msgstr ""
msgid "CI configuration validated, including all configuration added with the %{codeStart}includes%{codeEnd} keyword. %{link}" msgid "CI configuration validated, including all configuration added with the %{codeStart}includes%{codeEnd} keyword. %{link}"
msgstr "" msgstr ""
msgid "CI minutes"
msgstr ""
msgid "CI settings" msgid "CI settings"
msgstr "" msgstr ""
...@@ -37732,6 +37735,9 @@ msgstr "" ...@@ -37732,6 +37735,9 @@ msgstr ""
msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}." msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}."
msgstr "" msgstr ""
msgid "You have successfully purchased %{product}. You'll receive a receipt by mail."
msgstr ""
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email." msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
msgstr "" msgstr ""
......
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