Commit 9f93fd4d authored by Vitaly Slobodin's avatar Vitaly Slobodin Committed by Mark Chao

Add banner for new user signups cap alert

Add banner for notyfing admins about reached
cap for new user signups.
parent ee4f77bc
......@@ -7,6 +7,7 @@ const PERSISTENT_USER_CALLOUTS = [
'.js-buy-pipeline-minutes-notification-callout',
'.js-token-expiry-callout',
'.js-registration-enabled-callout',
'.js-new-user-signups-cap-reached',
];
const initCallouts = () => {
......
......@@ -26,7 +26,8 @@ class UserCallout < ApplicationRecord
suggest_pipeline: 22,
customize_homepage: 23,
feature_flags_new_version: 24,
registration_enabled_callout: 25
registration_enabled_callout: 25,
new_user_signups_cap_reached: 26 # EE-only
}
validates :user, presence: true
......
......@@ -17,6 +17,7 @@
= render_account_recovery_regular_check
= render_if_exists "layouts/header/ee_subscribable_banner"
= render_if_exists "shared/namespace_storage_limit_alert"
= render_if_exists "shared/new_user_signups_cap_reached_alert"
= yield :customize_homepage_banner
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
......
......@@ -4,15 +4,16 @@ module EE
module UserCalloutsHelper
extend ::Gitlab::Utils::Override
GEO_ENABLE_HASHED_STORAGE = 'geo_enable_hashed_storage'
GEO_MIGRATE_HASHED_STORAGE = 'geo_migrate_hashed_storage'
CANARY_DEPLOYMENT = 'canary_deployment'
GOLD_TRIAL = 'gold_trial'
GOLD_TRIAL_BILLINGS = 'gold_trial_billings'
THREAT_MONITORING_INFO = 'threat_monitoring_info'
ACCOUNT_RECOVERY_REGULAR_CHECK = 'account_recovery_regular_check'
ACTIVE_USER_COUNT_THRESHOLD = 'active_user_count_threshold'
PERSONAL_ACCESS_TOKEN_EXPIRY = 'personal_access_token_expiry'
ACTIVE_USER_COUNT_THRESHOLD = 'active_user_count_threshold'
CANARY_DEPLOYMENT = 'canary_deployment'
GEO_ENABLE_HASHED_STORAGE = 'geo_enable_hashed_storage'
GEO_MIGRATE_HASHED_STORAGE = 'geo_migrate_hashed_storage'
GOLD_TRIAL = 'gold_trial'
GOLD_TRIAL_BILLINGS = 'gold_trial_billings'
NEW_USER_SIGNUPS_CAP_REACHED = 'new_user_signups_cap_reached'
PERSONAL_ACCESS_TOKEN_EXPIRY = 'personal_access_token_expiry'
THREAT_MONITORING_INFO = 'threat_monitoring_info'
def show_canary_deployment_callout?(project)
!user_dismissed?(CANARY_DEPLOYMENT) &&
......@@ -89,6 +90,17 @@ module EE
!user_dismissed?(PERSONAL_ACCESS_TOKEN_EXPIRY, 1.week.ago)
end
def show_new_user_signups_cap_reached?
return false unless ::Feature.enabled?(:admin_new_user_signups_cap)
return false unless current_user&.admin?
return false if user_dismissed?(NEW_USER_SIGNUPS_CAP_REACHED)
new_user_signups_cap = ::Gitlab::CurrentSettings.current_application_settings.new_user_signups_cap
return false if new_user_signups_cap.nil?
new_user_signups_cap.to_i <= ::User.billable.count
end
private
def hashed_storage_enabled?
......@@ -132,5 +144,8 @@ module EE
def token_expiration_enforced?
::PersonalAccessToken.expiration_enforced?
end
def current_settings
end
end
end
- return unless show_new_user_signups_cap_reached?
- user_cap_help_url = help_page_path('user/admin_area/settings/sign_up_restrictions.md')
- help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: user_cap_help_url }
- help_link_end = '</a>'.html_safe
%div{ class: [container_class, @content_class, 'gl-pt-5!'] }
.gl-alert.gl-alert-warning.js-new-user-signups-cap-reached{ role: 'alert', data: { feature_id: ::EE::UserCalloutsHelper::NEW_USER_SIGNUPS_CAP_REACHED, dismiss_endpoint: user_callouts_path, defer_links: "true" } }
= sprite_icon('warning', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
%button.js-close.gl-alert-dismiss.gl-cursor-pointer{ type: 'button', 'aria-label' => _('Dismiss') }
= sprite_icon('close', css_class: 'gl-icon')
.gl-alert-body
%h4.gl-alert-title= s_('Admin|Your instance has reached its user cap')
= s_('Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}.').html_safe % { help_link_start: help_link_start, help_link_end: help_link_end }
- if User.blocked_pending_approval.count > 0
.gl-alert-actions
= link_to s_('Admin|View pending user approvals'), admin_users_path({ filter: 'blocked_pending_approval' }), class: 'btn gl-alert-action btn-info gl-button'
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'displays new user signups cap alert', :js do
let_it_be(:admin) { create(:admin) }
let(:help_page_href) { help_page_path('user/admin_area/settings/sign_up_restrictions.md') }
let(:expected_content) { 'Your instance has reached its user cap' }
context 'when reached active users cap' do
before do
allow(User).to receive(:billable).and_return((0..9))
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:new_user_signups_cap).and_return(9)
gitlab_sign_in(admin)
end
it 'displays and dismiss alert' do
expect(page).to have_content(expected_content)
expect(page).to have_link('usage caps', href: help_page_href)
visit root_dashboard_path
find('.js-new-user-signups-cap-reached .gl-alert-dismiss').click
expect(page).not_to have_content(expected_content)
expect(page).not_to have_link('usage caps', href: help_page_href)
end
end
end
......@@ -368,4 +368,56 @@ RSpec.describe EE::UserCalloutsHelper do
end
end
end
describe '.show_new_user_signups_cap_reached?' do
subject { helper.show_new_user_signups_cap_reached? }
let(:user) { create(:user) }
let(:admin) { create(:user, admin: true) }
context 'when user is anonymous' do
before do
allow(helper).to receive(:current_user).and_return(nil)
end
it { is_expected.to eq(false) }
end
context 'when user is not an admin' do
before do
allow(helper).to receive(:current_user).and_return(user)
end
it { is_expected.to eq(false) }
end
context 'when feature flag is disabled' do
before do
allow(helper).to receive(:current_user).and_return(admin)
stub_feature_flags(admin_new_user_signups_cap: false)
end
it { is_expected.to eq(false) }
end
context 'when feature flag is enabled' do
where(:new_user_signups_cap, :active_user_count, :result) do
nil | 10 | false
10 | 9 | false
0 | 10 | true
1 | 1 | true
end
with_them do
before do
allow(helper).to receive(:current_user).and_return(admin)
allow(User.billable).to receive(:count).and_return(active_user_count)
allow(Gitlab::CurrentSettings.current_application_settings)
.to receive(:new_user_signups_cap).and_return(new_user_signups_cap)
end
it { is_expected.to eq(result) }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'callout alerts' do
include Capybara::RSpecMatchers
describe 'new_user_signups_cap_reached' do
let_it_be(:user) { create(:admin) }
let(:enabled) { true }
let(:billable_users) { [double(:billable_user)] }
let(:help_page_href) { help_page_path('user/admin_area/settings/sign_up_restrictions.md') }
let(:expected_content) { 'Your instance has reached its user cap' }
shared_examples_for 'a visible alert' do
it 'shows the alert' do
get root_dashboard_path
expect(response.body).to include(expected_content)
expect(response.body).to have_link('usage caps', href: help_page_href)
end
end
shared_examples_for 'a hidden alert' do
it 'does not show the alert' do
get root_dashboard_path
expect(response.body).not_to include(expected_content)
end
end
before do
stub_feature_flags(admin_new_user_signups_cap: enabled)
stub_application_setting(new_user_signups_cap: 1)
allow(User).to receive(:billable).and_return(billable_users)
login_as(user)
end
context 'when cap reached' do
it_behaves_like 'a visible alert'
end
context 'when cap not reached' do
let(:billable_users) { [] }
it_behaves_like 'a hidden alert'
end
context 'when feature disabled' do
let(:enabled) { false }
it_behaves_like 'a hidden alert'
end
context 'when user is not admin' do
let_it_be(:user) { create(:user) }
it_behaves_like 'a hidden alert'
end
end
end
......@@ -2272,6 +2272,15 @@ msgstr ""
msgid "Administration"
msgstr ""
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
msgid "Admin|View pending user approvals"
msgstr ""
msgid "Admin|Your instance has reached its user cap"
msgstr ""
msgid "Advanced"
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