Commit e1abd2a9 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'dz/327884-add-storage-toggle-and-route' into 'master'

Add a new route for storage purchase

See merge request gitlab-org/gitlab!68834
parents 4bf37b54 25537d4c
---
name: new_route_storage_purchase
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68834
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327896
milestone: '14.3'
type: development
group: group::purchase
default_enabled: false
import mountSubscriptionsApplication from 'ee/subscriptions/buy_storage';
mountSubscriptionsApplication(document.getElementById('js-buy-storage'));
<script>
import StepOrderApp from 'ee/vue_shared/purchase_flow/components/step_order_app.vue';
export default {
components: {
StepOrderApp,
},
};
</script>
<template>
<step-order-app>
<template #checkout></template>
<template #order-summary></template>
</step-order-app>
</template>
import Vue from 'vue';
import App from './components/app.vue';
export default (el) => {
return new Vue({
el,
components: {
App,
},
render(createElement) {
return createElement(App);
},
});
};
...@@ -41,6 +41,16 @@ class SubscriptionsController < ApplicationController ...@@ -41,6 +41,16 @@ class SubscriptionsController < ApplicationController
render_404 unless Feature.enabled?(:new_route_ci_minutes_purchase, @group, default_enabled: :yaml) render_404 unless Feature.enabled?(:new_route_ci_minutes_purchase, @group, default_enabled: :yaml)
end end
def buy_storage
return render_404 unless storage_plan_data.present?
@group = find_group(plan_id: storage_plan_data["id"])
return render_404 if @group.nil?
render_404 unless Feature.enabled?(:new_route_storage_purchase, @group, default_enabled: :yaml)
end
def payment_form def payment_form
response = client.payment_form_params(params[:id]) response = client.payment_form_params(params[:id])
render json: response[:data] render json: response[:data]
...@@ -128,6 +138,14 @@ class SubscriptionsController < ApplicationController ...@@ -128,6 +138,14 @@ class SubscriptionsController < ApplicationController
end end
end end
def storage_plan_data
strong_memoize(:storage_plan_data) do
plan_response = client.get_plans(tags: ['STORAGE_PLAN'])
plan_response[:success] ? plan_response[:data].first : nil
end
end
def load_eligible_groups def load_eligible_groups
return @eligible_groups = [] unless current_user return @eligible_groups = [] unless current_user
......
...@@ -22,6 +22,12 @@ module SubscriptionsHelper ...@@ -22,6 +22,12 @@ module SubscriptionsHelper
}.merge(addon_data(group)) }.merge(addon_data(group))
end end
def buy_storage_addon_data(group)
{
redirect_after_success: group_usage_quotas_path(group, anchor: 'pipelines-quota-tab', purchased_product: _('Storage'))
}.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,
......
- page_title _('Buy Storage')
#js-buy-storage{ data: buy_storage_addon_data(@group) }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
resource :subscriptions, only: [:new, :create] do resource :subscriptions, only: [:new, :create] do
get :buy_minutes get :buy_minutes
get :buy_storage
get :payment_form get :payment_form
get :payment_method get :payment_method
......
...@@ -14,6 +14,7 @@ RSpec.describe SubscriptionsController do ...@@ -14,6 +14,7 @@ RSpec.describe SubscriptionsController do
expected_subscription_path = new_subscriptions_path(plan_id: 'bronze_id') if redirect_from == 'checkout' expected_subscription_path = new_subscriptions_path(plan_id: 'bronze_id') if redirect_from == 'checkout'
expected_subscription_path = buy_minutes_subscriptions_path(plan_id: 'bronze_id') if redirect_from == 'buy_minutes' expected_subscription_path = buy_minutes_subscriptions_path(plan_id: 'bronze_id') if redirect_from == 'buy_minutes'
expected_subscription_path = buy_storage_subscriptions_path(plan_id: 'bronze_id') if redirect_from == 'buy_storage'
expect(controller.stored_location_for(:user)).to eq(expected_subscription_path) expect(controller.stored_location_for(:user)).to eq(expected_subscription_path)
end end
...@@ -82,7 +83,6 @@ RSpec.describe SubscriptionsController do ...@@ -82,7 +83,6 @@ RSpec.describe SubscriptionsController do
context 'with authenticated user' do context 'with authenticated user' do
before do before do
group.add_owner(user) group.add_owner(user)
stub_feature_flags(new_route_ci_minutes_purchase: false)
stub_feature_flags(new_route_ci_minutes_purchase: group) stub_feature_flags(new_route_ci_minutes_purchase: group)
sign_in(user) sign_in(user)
end end
...@@ -146,6 +146,71 @@ RSpec.describe SubscriptionsController do ...@@ -146,6 +146,71 @@ RSpec.describe SubscriptionsController do
end end
end end
describe 'GET #buy_storage' do
let_it_be(:group) { create(:group) }
subject { get :buy_storage, params: { selected_group: group.id } }
context 'with authenticated user' do
before do
group.add_owner(user)
stub_feature_flags(new_route_storage_purchase: group)
sign_in(user)
end
context 'when the add-on plan cannot be found' do
let_it_be(:group) { create(:group) }
before do
group.add_owner(user)
allow(Gitlab::SubscriptionPortal::Client)
.to receive(:get_plans).with(tags: ['STORAGE_PLAN'])
.and_return({ success: false, data: [] })
end
it { is_expected.to have_gitlab_http_status(:not_found) }
end
context 'with :new_route_storage_purchase enabled' do
let_it_be(:group) { create(:group) }
before do
group.add_owner(user)
allow(Gitlab::SubscriptionPortal::Client)
.to receive(:get_plans).with(tags: ['STORAGE_PLAN'])
.and_return({ success: true, data: [{ 'id' => 'storage' }] })
allow_next_instance_of(
GitlabSubscriptions::FilterPurchaseEligibleNamespacesService,
user: user,
plan_id: 'storage',
namespaces: [group]
) do |instance|
allow(instance).to receive(:execute).and_return(instance_double(ServiceResponse, success?: true, payload: [group]))
end
end
it { is_expected.to render_template 'layouts/checkout' }
it { is_expected.to render_template :buy_storage }
end
end
context 'with :new_route_storage_purchase disabled' do
before do
allow(Gitlab::SubscriptionPortal::Client)
.to receive(:get_plans).with(tags: ['STORAGE_PLAN'])
.and_return({ success: true, data: [{ 'id' => 'ci_minutes' }] })
stub_feature_flags(new_route_ci_minutes_purchase: false)
sign_in(user)
end
it { is_expected.to have_gitlab_http_status(:not_found) }
end
end
describe 'GET #payment_form' do describe 'GET #payment_form' do
subject { get :payment_form, params: { id: 'cc' } } subject { get :payment_form, params: { id: 'cc' } }
......
...@@ -167,4 +167,22 @@ RSpec.describe SubscriptionsHelper do ...@@ -167,4 +167,22 @@ RSpec.describe SubscriptionsHelper do
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}]}) }
it { is_expected.to include(redirect_after_success: group_usage_quotas_path(group, anchor: 'pipelines-quota-tab', purchased_product: 'CI minutes')) } it { is_expected.to include(redirect_after_success: group_usage_quotas_path(group, anchor: 'pipelines-quota-tab', purchased_product: 'CI minutes')) }
end end
describe '#buy_storage_addon_data' do
subject(:buy_storage_addon_data) { helper.buy_storage_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, anchor: 'pipelines-quota-tab', purchased_product: 'Storage')) }
end
end end
...@@ -39,3 +39,23 @@ RSpec.shared_examples_for 'buy minutes addon form data' do |js_selector| ...@@ -39,3 +39,23 @@ RSpec.shared_examples_for 'buy minutes addon 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']") }
it { is_expected.to have_selector("#{js_selector}[data-redirect-after-success='/groups/my-ci-minutes-group/-/usage_quotas']") } it { is_expected.to have_selector("#{js_selector}[data-redirect-after-success='/groups/my-ci-minutes-group/-/usage_quotas']") }
end end
RSpec.shared_examples_for 'buy storage addon form data' do |js_selector|
before do
allow(view).to receive(:buy_storage_addon_data).and_return(
group_data: '[{"id":"storage_plan_id","code":"storage","price_per_year":10.0}]',
namespace_id: '2',
plan_id: 'storage_plan_id',
source: 'some_source',
redirect_after_success: '/groups/my-group/-/usage_quotas'
)
end
subject { render }
it { is_expected.to have_selector("#{js_selector}[data-group-data='[{\"id\":\"storage_plan_id\",\"code\":\"storage\",\"price_per_year\":10.0}]']") }
it { is_expected.to have_selector("#{js_selector}[data-plan-id='storage_plan_id']") }
it { is_expected.to have_selector("#{js_selector}[data-namespace-id='2']") }
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-group/-/usage_quotas']") }
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'subscriptions/buy_storage' do
it_behaves_like 'buy storage addon form data', '#js-buy-storage'
end
...@@ -5888,6 +5888,9 @@ msgstr "" ...@@ -5888,6 +5888,9 @@ msgstr ""
msgid "Buy CI Minutes" msgid "Buy CI Minutes"
msgstr "" msgstr ""
msgid "Buy Storage"
msgstr ""
msgid "Buy more Pipeline minutes" msgid "Buy more Pipeline minutes"
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