Commit a1d583e1 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch '332592-add-state-machine-to-members' into 'master'

Add state machine for "GroupMember#state"

See merge request gitlab-org/gitlab!66916
parents 2653948a 6130374e
......@@ -477,7 +477,7 @@ module EE
def user_cap_reached?(requested_hosted_plan = nil)
return false unless ::Feature.enabled?(:saas_user_caps, self, default_enabled: :yaml)
user_cap = root_ancestor.new_user_signups_cap
user_cap = root_ancestor.namespace_settings&.new_user_signups_cap
return false unless user_cap
user_cap <= billable_members_count(requested_hosted_plan)
......
......@@ -8,6 +8,10 @@ module EE
prepended do
include UsageStatistics
STATE_CREATED = 0
STATE_AWAITING = 1
STATE_ACTIVE = 2
validate :sso_enforcement, if: :group
validate :group_domain_limitations, if: :group_has_domain_limitations?
......@@ -25,6 +29,24 @@ module EE
scope :guests, -> { where(access_level: ::Gitlab::Access::GUEST) }
scope :non_owners, -> { where("members.access_level < ?", ::Gitlab::Access::OWNER) }
scope :by_user_id, ->(user_id) { where(user_id: user_id) }
state_machine :state, initial: :created do
event :wait do
transition created: :awaiting
transition active: :awaiting
end
event :activate do
transition created: :active
transition awaiting: :active
end
state :created, value: STATE_CREATED
state :awaiting, value: STATE_AWAITING
state :active, value: STATE_ACTIVE
end
before_create :set_membership_activation
end
class_methods do
......@@ -75,6 +97,12 @@ module EE
execute_hooks_for(:destroy)
end
def set_membership_activation
return unless ::Feature.enabled?(:saas_user_caps, group, default_enabled: :yaml)
self.state = group.user_cap_reached? ? STATE_AWAITING : STATE_ACTIVE
end
def execute_hooks_for(event)
return unless self.source.feature_available?(:group_webhooks)
return unless GroupHook.where(group_id: self.source.self_and_ancestors).exists?
......
......@@ -279,6 +279,53 @@ RSpec.describe GroupMember do
end
end
context 'check if user cap has been reached' do
let_it_be(:group) { create(:group_with_plan, plan: :ultimate_plan) }
let!(:user) { create(:user) }
subject(:add_user_to_group) { group.add_developer(user) }
context 'when the :saas_user_caps feature flag is disabled' do
before do
stub_feature_flags(saas_user_caps: false)
end
it 'leaves the group member state to created' do
add_user_to_group
expect(user.group_members.last).to be_created
end
end
context 'when the :saas_user_caps feature flag is enabled' do
before do
stub_feature_flags(saas_user_caps: group)
allow(group).to receive(:user_cap_reached?).and_return(user_cap_reached)
end
context 'when the user cap for this group has not been reached' do
let(:user_cap_reached) { false }
it 'sets the group member to active' do
add_user_to_group
expect(user.group_members.last).to be_active
end
end
context 'when the user cap for this group has been reached' do
let(:user_cap_reached) { true }
it 'sets the group member to awaiting' do
add_user_to_group
expect(user.group_members.last).to be_awaiting
end
end
end
end
describe '#provisioned_by_this_group?' do
let_it_be(:group) { create(:group) }
......
......@@ -1485,13 +1485,10 @@ RSpec.describe GroupPolicy do
end
context 'when parent group has resource access token creation disabled' do
let(:parent) { create(:group_with_plan, plan: :bronze_plan) }
let(:namespace_settings) { create(:namespace_settings, resource_access_token_creation_allowed: false) }
let(:parent) { create(:group_with_plan, plan: :bronze_plan, namespace_settings: namespace_settings) }
let(:group) { create(:group, parent: parent) }
before do
parent.namespace_settings.update_column(:resource_access_token_creation_allowed, false)
end
context 'cannot create resource access tokens' do
it { is_expected.not_to be_allowed(:create_resource_access_tokens) }
end
......
......@@ -1072,7 +1072,7 @@ RSpec.describe API::MergeRequests do
end
describe "GET /groups/:id/merge_requests" do
let_it_be(:group) { create(:group, :public) }
let_it_be(:group, reload: true) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, :repository, creator: user, namespace: group, only_allow_merge_if_pipeline_succeeds: false) }
include_context 'with merge requests'
......
......@@ -6,18 +6,20 @@ RSpec.describe Groups::GroupLinks::CreateService, '#execute' do
let(:parent_group_user) { create(:user) }
let(:group_user) { create(:user) }
let(:child_group_user) { create(:user) }
let(:prevent_sharing) { false }
let_it_be(:group_parent) { create(:group, :private) }
let_it_be(:group) { create(:group, :private, parent: group_parent) }
let_it_be(:group_child) { create(:group, :private, parent: group) }
let_it_be(:shared_group_parent, refind: true) { create(:group, :private) }
let_it_be(:shared_group, refind: true) { create(:group, :private, parent: shared_group_parent) }
let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
let(:ns_for_parent) { create(:namespace_settings, prevent_sharing_groups_outside_hierarchy: prevent_sharing) }
let(:shared_group_parent) { create(:group, :private, namespace_settings: ns_for_parent) }
let(:shared_group) { create(:group, :private, parent: shared_group_parent) }
let(:shared_group_child) { create(:group, :private, parent: shared_group) }
let_it_be(:project_parent) { create(:project, group: shared_group_parent) }
let_it_be(:project) { create(:project, group: shared_group) }
let_it_be(:project_child) { create(:project, group: shared_group_child) }
let(:project_parent) { create(:project, group: shared_group_parent) }
let(:project) { create(:project, group: shared_group) }
let(:project_child) { create(:project, group: shared_group_child) }
let(:opts) do
{
......@@ -129,9 +131,7 @@ RSpec.describe Groups::GroupLinks::CreateService, '#execute' do
end
context 'sharing outside the hierarchy is disabled' do
before do
shared_group_parent.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
end
let(:prevent_sharing) { true }
it 'prevents sharing with a group outside the hierarchy' do
result = subject.execute
......
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