Commit e0c38bc5 authored by Mikołaj Wawrzyniak's avatar Mikołaj Wawrzyniak

Merge branch '346259_manual_renewal_banner' into 'master'

Introduce manual renewal banner logic

See merge request gitlab-org/gitlab!75872
parents 2c229f97 b882a5d3
---
name: automated_email_provision
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75872
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348317
milestone: '14.6'
type: development
group: group::license
default_enabled: false
......@@ -9,6 +9,7 @@ module EE
SUBSCRIPTIONS_MANAGE_URL = ::Gitlab::SubscriptionPortal.subscriptions_manage_url.freeze
SUBSCRIPTIONS_PLANS_URL = ::Gitlab::SubscriptionPortal.subscriptions_plans_url.freeze
SUBSCRIPTIONS_GITLAB_PLANS_URL = ::Gitlab::SubscriptionPortal.subscriptions_gitlab_plans_url.freeze
SUBSCRIPTIONS_EDIT_ACCOUNT_URL = ::Gitlab::SubscriptionPortal.edit_account_url.freeze
SUBSCRIPTION_PORTAL_ADMIN_EMAIL = ::Gitlab::SubscriptionPortal.subscription_portal_admin_email.freeze
SUBSCRIPTION_PORTAL_ADMIN_TOKEN = ::Gitlab::SubscriptionPortal.subscription_portal_admin_token.freeze
CUSTOMER_SUPPORT_URL = ::Gitlab::Saas.customer_support_url.freeze
......
# frozen_string_literal: true
module Gitlab
class ManualBanner
REMINDER_DAYS = 14.days
def initialize(actionable:)
@actionable = actionable
end
def display?
return false if Gitlab::CurrentSettings.should_check_namespace_plan?
return false unless Feature.enabled?(:automated_email_provision)
require_notification?
end
def subject
return unless display?
banner_subject
end
def body
return unless display?
banner_body
end
def display_error_version?
raise NotImplementedError
end
private
attr_reader :actionable
def require_notification?
raise NotImplementedError
end
def banner_subject
raise NotImplementedError
end
def banner_body
raise NotImplementedError
end
def renewal_service_email
email = Gitlab::SubscriptionPortal::RENEWAL_SERVICE_EMAIL
"<a href='mailto:#{email}'>#{email}</a>".html_safe
end
def customers_dot_url
"<a href='#{EE::SUBSCRIPTIONS_EDIT_ACCOUNT_URL}'>Customers Portal</a>".html_safe
end
end
end
# frozen_string_literal: true
module Gitlab
class ManualRenewalBanner < Gitlab::ManualBanner
def display_error_version?
actionable.expired?
end
private
def require_notification?
return false unless actionable&.will_expire?
return false if ::License.future_dated.present?
within_notification_window?
end
def within_notification_window?
(actionable.expires_at - REMINDER_DAYS) <= Date.today
end
def banner_subject
plan = actionable.plan.titleize
expires_at = actionable.expires_at.to_s
if display_error_version?
_('Your %{plan} subscription expired on %{expiry_date}') % { plan: plan, expiry_date: expires_at }
else
_('Your %{plan} subscription expires on %{expiry_date}') % { plan: plan, expiry_date: expires_at }
end
end
def banner_body
if display_error_version?
_(
'Your subscription is now expired. To renew, export your license usage file and email it to ' \
'%{renewal_service_email}. A new license will be emailed to the email address registered in the ' \
'%{customers_dot}. You can upload this license to your instance. To use Free tier, remove your ' \
'current license.'
).html_safe % { renewal_service_email: renewal_service_email, customers_dot: customers_dot_url }
else
_(
'To renew, export your license usage file and email it to %{renewal_service_email}. ' \
'A new license will be emailed to the email address registered in the %{customers_dot}. ' \
'You can upload this license to your instance.'
).html_safe % { renewal_service_email: renewal_service_email, customers_dot: customers_dot_url }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::ManualBanner do
let(:manual_banner) { described_class.new(actionable: nil) }
describe '#display?' do
subject(:display?) { manual_banner.display? }
let(:should_check_namespace_plan?) { false } # indicates a self-managed instance
let(:feature_flag_enabled) { true }
before do
allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { should_check_namespace_plan? }
stub_feature_flags(automated_email_provision: feature_flag_enabled)
end
context 'when on GitLab.com' do
let(:should_check_namespace_plan?) { true }
it { is_expected.to eq(false) }
end
context 'when feature flag :automated_email_provision is disabled' do
let(:feature_flag_enabled) { false }
it { is_expected.to eq(false) }
end
it { expect { display? }.to raise_error(NotImplementedError) }
end
describe '#subject' do
subject(:banner_subject) { manual_banner.subject }
before do
allow(manual_banner).to receive(:display?).and_return(display)
end
context 'when banner should not be displayed' do
let(:display) { false }
it { is_expected.to eq(nil) }
end
context 'when banner should be displayed' do
let(:display) { true }
it { expect { banner_subject }.to raise_error(NotImplementedError) }
end
end
describe '#body' do
subject(:banner_body) { manual_banner.body }
before do
allow(manual_banner).to receive(:display?).and_return(display)
end
context 'when banner should not be displayed' do
let(:display) { false }
it { is_expected.to eq(nil) }
end
context 'when banner should be displayed' do
let(:display) { true }
it { expect { banner_body }.to raise_error(NotImplementedError) }
end
end
describe 'display_error_version?' do
it { expect { manual_banner.display_error_version? }.to raise_error(NotImplementedError) }
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::ManualRenewalBanner do
include ActionView::Helpers::SanitizeHelper
let(:manual_renewal_banner) { described_class.new(actionable: license) }
let(:license) { build(:license, expires_at: expires_at, plan: plan) }
let(:expires_at) { Date.current + 1.year }
let(:plan) { License::ULTIMATE_PLAN }
describe '#display?' do
subject(:display?) { manual_renewal_banner.display? }
let(:should_check_namespace_plan?) { false } # indicates a self-managed instance
let(:feature_flag_enabled) { true }
before do
allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { should_check_namespace_plan? }
stub_feature_flags(automated_email_provision: feature_flag_enabled)
end
context 'when on GitLab.com' do
let(:should_check_namespace_plan?) { true }
it { is_expected.to eq(false) }
end
context 'when feature flag :automated_email_provision is disabled' do
let(:feature_flag_enabled) { false }
it { is_expected.to eq(false) }
end
context 'when license does not expire' do
let(:expires_at) { nil }
it { is_expected.to eq(false) }
end
context 'when a future dated license is present' do
before do
allow(License).to receive(:future_dated).and_return(build(:license))
end
it { is_expected.to eq(false) }
end
context 'when expiration date is not within the notification window' do
let(:expires_at) { Date.tomorrow + described_class::REMINDER_DAYS }
it { is_expected.to eq(false) }
end
context 'when expiration date is within the notification window' do
context 'when notification window starts today' do
let(:expires_at) { Date.today + described_class::REMINDER_DAYS }
it { is_expected.to eq(true) }
end
context 'when notification window is already on going' do
let(:expires_at) { Date.yesterday + described_class::REMINDER_DAYS }
it { is_expected.to eq(true) }
end
end
end
describe '#subject' do
subject { manual_renewal_banner.subject }
before do
allow(manual_renewal_banner).to receive(:display?).and_return(display)
end
context 'when banner should not be displayed' do
let(:display) { false }
it { is_expected.to eq(nil) }
end
context 'when banner should be displayed' do
let(:display) { true }
context 'when license is not yet expired but within the notification window' do
shared_examples 'an expiring license' do
it { is_expected.to eq("Your #{plan.capitalize} subscription expires on #{license.expires_at}") }
end
context 'when notification date is today' do
let(:expires_at) { Date.today + described_class::REMINDER_DAYS }
it_behaves_like 'an expiring license'
end
context 'when notification date is within the next 14 days' do
let(:expires_at) { Date.yesterday + described_class::REMINDER_DAYS }
it_behaves_like 'an expiring license'
end
end
context 'when license is already expired' do
let(:expires_at) { Date.today }
it { is_expected.to eq("Your #{plan.capitalize} subscription expired on #{license.expires_at}") }
end
end
end
describe '#body' do
subject(:body) { strip_tags(manual_renewal_banner.body) }
before do
allow(manual_renewal_banner).to receive(:display?).and_return(display)
end
context 'when banner should not be displayed' do
let(:display) { false }
it { is_expected.to eq(nil) }
end
context 'when banner should be displayed' do
let(:display) { true }
context 'when license is not yet expired but within the notification window' do
shared_examples 'an expiring license' do
it 'returns a message to renew for an expiring license' do
expect(body).to eq(
"To renew, export your license usage file and email it to " \
"#{Gitlab::SubscriptionPortal::RENEWAL_SERVICE_EMAIL}. A new license will be emailed to the email " \
"address registered in the Customers Portal. You can upload this license to your instance."
)
end
end
context 'when notification date is today' do
let(:expires_at) { Date.today + described_class::REMINDER_DAYS }
it_behaves_like 'an expiring license'
end
context 'when notification date is within the next 14 days' do
let(:expires_at) { Date.yesterday + described_class::REMINDER_DAYS }
it_behaves_like 'an expiring license'
end
end
context 'when license is already expired' do
let(:expires_at) { Date.today }
it 'returns a message to renew for an expired license' do
expect(body).to eq(
"Your subscription is now expired. To renew, export your license usage file and email it to " \
"#{Gitlab::SubscriptionPortal::RENEWAL_SERVICE_EMAIL}. A new license will be emailed to the email " \
"address registered in the Customers Portal. You can upload this license to your instance. To use " \
"Free tier, remove your current license."
)
end
end
end
end
describe 'display_error_version?' do
subject(:display_error_version?) { manual_renewal_banner.display_error_version? }
context 'when license is not expired' do
it { is_expected.to eq(false) }
end
context 'when license is expired' do
let(:expires_at) { Date.today }
it { is_expected.to eq(true) }
end
end
end
......@@ -62,6 +62,10 @@ module Gitlab
"#{self.subscriptions_url}/gitlab/namespaces/#{group_id}/renew"
end
def self.edit_account_url
"#{self.subscriptions_url}/customers/edit"
end
def self.subscription_portal_admin_email
ENV.fetch('SUBSCRIPTION_PORTAL_ADMIN_EMAIL', 'gl_com_api@gitlab.com')
end
......@@ -69,9 +73,14 @@ module Gitlab
def self.subscription_portal_admin_token
ENV.fetch('SUBSCRIPTION_PORTAL_ADMIN_TOKEN', 'customer_admin_token')
end
def self.renewal_service_email
'renewals-support@gitlab.com'
end
end
end
Gitlab::SubscriptionPortal.prepend_mod
Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL = Gitlab::SubscriptionPortal.subscriptions_url.freeze
Gitlab::SubscriptionPortal::PAYMENT_FORM_URL = Gitlab::SubscriptionPortal.payment_form_url.freeze
Gitlab::SubscriptionPortal::RENEWAL_SERVICE_EMAIL = Gitlab::SubscriptionPortal.renewal_service_email.freeze
......@@ -36675,6 +36675,9 @@ msgstr ""
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
msgstr ""
msgid "To renew, export your license usage file and email it to %{renewal_service_email}. A new license will be emailed to the email address registered in the %{customers_dot}. You can upload this license to your instance."
msgstr ""
msgid "To resolve this, try to:"
msgstr ""
......@@ -40473,6 +40476,12 @@ msgstr ""
msgid "Your %{host} account was signed in to from a new location"
msgstr ""
msgid "Your %{plan} subscription expired on %{expiry_date}"
msgstr ""
msgid "Your %{plan} subscription expires on %{expiry_date}"
msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription expires on %{strong}%{expires_on}%{strong_close}. After that date, you cannot create issues or merge requests, or use many other features."
msgstr ""
......@@ -40764,6 +40773,9 @@ msgstr ""
msgid "Your subscription expired!"
msgstr ""
msgid "Your subscription is now expired. To renew, export your license usage file and email it to %{renewal_service_email}. A new license will be emailed to the email address registered in the %{customers_dot}. You can upload this license to your instance. To use Free tier, remove your current license."
msgstr ""
msgid "Your subscription will expire in %{remaining_days} day."
msgid_plural "Your subscription will expire in %{remaining_days} days."
msgstr[0] ""
......
......@@ -63,6 +63,7 @@ RSpec.describe ::Gitlab::SubscriptionPortal do
:subscriptions_plans_url | 'https://about.gitlab.com/pricing/'
:subscriptions_instance_review_url | 'https://customers.staging.gitlab.com/instance_review'
:subscriptions_gitlab_plans_url | 'https://customers.staging.gitlab.com/gitlab_plans'
:edit_account_url | 'https://customers.staging.gitlab.com/customers/edit'
end
with_them 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