Commit d39de8a3 authored by Jay Swain's avatar Jay Swain

Add subscription banner to group/subgroup pages

The subscription banner will be displayed on group/subgroup pages, as
well as project pages for subgroups.

The most significant change here is looking up to the root_ancestor when
checking for a gitlab_subscription. The decorated_subscription as well
as the subscription_message now check project  first, and group second.

Finishes: https://gitlab.com/gitlab-org/growth/product/-/issues/1550
parent d2425e6a
- breadcrumb_title _("Details") - breadcrumb_title _("Details")
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
= content_for :flash_message do
- if Feature.enabled?(:subscribable_banner_subscription)
= render_if_exists "layouts/header/ee_subscribable_banner", subscription: true
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
......
...@@ -180,25 +180,6 @@ module EE ...@@ -180,25 +180,6 @@ module EE
"The total size of this project's repository #{show_lfs} will be limited to this size. 0 for unlimited. Leave empty to inherit the group/global value." "The total size of this project's repository #{show_lfs} will be limited to this size. 0 for unlimited. Leave empty to inherit the group/global value."
end end
def subscription_message
return unless ::Gitlab.com?
::Gitlab::ExpiringSubscriptionMessage.new(
subscribable: decorated_subscription,
signed_in: signed_in?,
is_admin: can?(current_user, :owner_access, @project),
namespace: @project.namespace
).message
end
def decorated_subscription
subscription = @project.gitlab_subscription
return unless subscription
SubscriptionPresenter.new(subscription)
end
override :membership_locked? override :membership_locked?
def membership_locked? def membership_locked?
group = @project.group group = @project.group
......
...@@ -3,6 +3,29 @@ ...@@ -3,6 +3,29 @@
module SubscriptionsHelper module SubscriptionsHelper
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
def subscription_message
return unless ::Gitlab.com?
entity = @project || @group
namespace = @project&.namespace || @group
::Gitlab::ExpiringSubscriptionMessage.new(
subscribable: decorated_subscription,
signed_in: signed_in?,
is_admin: can?(current_user, :owner_access, entity),
namespace: namespace
).message
end
def decorated_subscription
entity = @project || @group
subscription = entity&.closest_gitlab_subscription
return unless subscription
SubscriptionPresenter.new(subscription)
end
def subscription_data def subscription_data
{ {
setup_for_company: (current_user.setup_for_company == true).to_s, setup_for_company: (current_user.setup_for_company == true).to_s,
......
...@@ -156,6 +156,16 @@ module EE ...@@ -156,6 +156,16 @@ module EE
end || super end || super
end end
def closest_gitlab_subscription
strong_memoize(:closest_gitlab_subscription) do
if parent_id
root_ancestor.gitlab_subscription
else
gitlab_subscription
end
end
end
def plan_name_for_upgrading def plan_name_for_upgrading
return ::Plan::FREE if trial_active? return ::Plan::FREE if trial_active?
......
...@@ -168,7 +168,7 @@ module EE ...@@ -168,7 +168,7 @@ module EE
delegate :merge_pipelines_enabled, :merge_pipelines_enabled=, :merge_pipelines_enabled?, :merge_pipelines_were_disabled?, to: :ci_cd_settings delegate :merge_pipelines_enabled, :merge_pipelines_enabled=, :merge_pipelines_enabled?, :merge_pipelines_were_disabled?, to: :ci_cd_settings
delegate :merge_trains_enabled?, to: :ci_cd_settings delegate :merge_trains_enabled?, to: :ci_cd_settings
delegate :gitlab_subscription, to: :namespace delegate :closest_gitlab_subscription, to: :namespace
validates :repository_size_limit, validates :repository_size_limit,
numericality: { only_integer: true, greater_than_or_equal_to: 0, allow_nil: true } numericality: { only_integer: true, greater_than_or_equal_to: 0, allow_nil: true }
......
---
title: Add subscription banner to group/subgroup pages
merge_request: 30883
author:
type: changed
...@@ -238,58 +238,4 @@ describe ProjectsHelper do ...@@ -238,58 +238,4 @@ describe ProjectsHelper do
end end
end end
end end
describe '#subscription_message' do
let(:gitlab_subscription) { double(:gitlab_subscription) }
let(:decorated_mock) { double(:decorated_mock) }
let(:message_mock) { double(:message_mock) }
let(:user) { double(:user_mock) }
it 'if it is not Gitlab.com? it returns nil' do
allow(Gitlab).to receive(:com?).and_return(false)
expect(helper.subscription_message).to be_nil
end
it 'calls Gitlab::ExpiringSubscriptionMessage and SubscriptionPresenter if is Gitlab.com?' do
allow(Gitlab).to receive(:com?).and_return(true)
allow(helper).to receive(:signed_in?).and_return(true)
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :owner_access, project).and_return(true)
allow(project).to receive(:gitlab_subscription).and_return(gitlab_subscription)
expect(SubscriptionPresenter).to receive(:new).with(gitlab_subscription).and_return(decorated_mock)
expect(::Gitlab::ExpiringSubscriptionMessage).to receive(:new).with(
subscribable: decorated_mock,
signed_in: true,
is_admin: true,
namespace: project.namespace
).and_return(message_mock)
expect(message_mock).to receive(:message).and_return('hey yay yay yay')
expect(helper.subscription_message).to eq('hey yay yay yay')
end
end
describe '#decorated_subscription' do
subject { helper.decorated_subscription }
context 'when a subscription exists' do
let(:gitlab_subscription) { build_stubbed(:gitlab_subscription) }
it 'returns a decorator' do
allow(project).to receive(:gitlab_subscription).and_return(gitlab_subscription)
expect(subject).to be_a(SubscriptionPresenter)
end
end
context 'when no subscription exists' do
it 'returns a nil object' do
allow(project).to receive(:gitlab_subscription).and_return(nil)
expect(subject).to be_nil
end
end
end
end end
...@@ -84,4 +84,108 @@ describe SubscriptionsHelper do ...@@ -84,4 +84,108 @@ describe SubscriptionsHelper do
it { is_expected.to eq(nil) } it { is_expected.to eq(nil) }
end end
end end
describe '#subscription_message' do
let(:gitlab_subscription) { entity.closest_gitlab_subscription }
let(:decorated_mock) { double(:decorated_mock) }
let(:message_mock) { double(:message_mock) }
let(:user) { double(:user_mock) }
it 'if it is not Gitlab.com? it returns nil' do
allow(Gitlab).to receive(:com?).and_return(false)
expect(helper.subscription_message).to be_nil
end
shared_examples 'subscription message' do
it 'calls Gitlab::ExpiringSubscriptionMessage and SubscriptionPresenter if is Gitlab.com?' do
allow(Gitlab).to receive(:com?).and_return(true)
allow(helper).to receive(:signed_in?).and_return(true)
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :owner_access, entity).and_return(true)
expect(SubscriptionPresenter).to receive(:new).with(gitlab_subscription).and_return(decorated_mock)
expect(::Gitlab::ExpiringSubscriptionMessage).to receive(:new).with(
subscribable: decorated_mock,
signed_in: true,
is_admin: true,
namespace: namespace
).and_return(message_mock)
expect(message_mock).to receive(:message).and_return('hey yay yay yay')
expect(helper.subscription_message).to eq('hey yay yay yay')
end
end
context 'when a project is present' do
let(:entity) { create(:project, namespace: namespace) }
let(:namespace) { create(:namespace_with_plan) }
before do
assign(:project, entity)
end
it_behaves_like 'subscription message'
end
context 'when a group is present' do
let(:entity) { create(:group_with_plan) }
let(:namespace) { entity }
before do
assign(:project, nil)
assign(:group, entity)
end
it_behaves_like 'subscription message'
end
end
describe '#decorated_subscription' do
subject { helper.decorated_subscription }
shared_examples 'when a subscription exists' do
let(:gitlab_subscription) { build_stubbed(:gitlab_subscription) }
it 'returns a decorator' do
allow(entity).to receive(:closest_gitlab_subscription).and_return(gitlab_subscription)
expect(subject).to be_a(SubscriptionPresenter)
end
end
context 'when a project exists' do
let(:entity) { create(:project) }
before do
assign(:project, entity)
end
it_behaves_like 'when a subscription exists'
end
context 'when a group exists' do
let(:entity) { create(:group) }
before do
assign(:group, entity)
end
it_behaves_like 'when a subscription exists'
end
context 'when no subscription exists' do
let(:entity) { create(:project) }
before do
assign(:project, entity)
end
it 'returns a nil object' do
allow(entity).to receive(:closest_gitlab_subscription).and_return(nil)
expect(subject).to be_nil
end
end
end
end end
...@@ -1458,4 +1458,38 @@ describe Namespace do ...@@ -1458,4 +1458,38 @@ describe Namespace do
end end
end end
end end
describe '#closest_gitlab_subscription' do
subject { namespace.closest_gitlab_subscription }
context 'when there is a root ancestor' do
let(:namespace) { create(:namespace, parent: root) }
context 'when root has a subscription' do
let(:root) { create(:namespace_with_plan) }
it { is_expected.to be_a(GitlabSubscription) }
end
context 'when root has no subscription' do
let(:root) { create(:namespace) }
it { is_expected.to be_nil }
end
end
context 'when there is no root ancestor' do
context 'has a subscription' do
let(:namespace) { create(:namespace_with_plan) }
it { is_expected.to be_a(GitlabSubscription) }
end
context 'it has no subscription' do
let(:namespace) { create(:namespace) }
it { is_expected.to be_nil }
end
end
end
end end
...@@ -19,6 +19,8 @@ describe Project do ...@@ -19,6 +19,8 @@ describe Project do
it { is_expected.to delegate_method(:shared_runners_minutes_used?).to(:shared_runners_limit_namespace) } it { is_expected.to delegate_method(:shared_runners_minutes_used?).to(:shared_runners_limit_namespace) }
it { is_expected.to delegate_method(:shared_runners_remaining_minutes_below_threshold?).to(:shared_runners_limit_namespace) } it { is_expected.to delegate_method(:shared_runners_remaining_minutes_below_threshold?).to(:shared_runners_limit_namespace) }
it { is_expected.to delegate_method(:closest_gitlab_subscription).to(:namespace) }
it { is_expected.to belong_to(:deleting_user) } it { is_expected.to belong_to(:deleting_user) }
it { is_expected.to have_one(:import_state).class_name('ProjectImportState') } it { is_expected.to have_one(:import_state).class_name('ProjectImportState') }
...@@ -2635,23 +2637,4 @@ describe Project do ...@@ -2635,23 +2637,4 @@ describe Project do
end end
end end
end end
describe '#gitlab_subscription' do
subject { project.gitlab_subscription }
let(:project) { create(:project, namespace: namespace) }
context 'has a gitlab subscription' do
let(:namespace) { subscription.namespace }
let(:subscription) { create(:gitlab_subscription) }
it { is_expected.to eq(subscription) }
end
context 'does not have a gitlab subscription' do
let(:namespace) { create(:namespace) }
it { is_expected.to be_nil }
end
end
end end
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