diff --git a/ee/app/models/ee/user.rb b/ee/app/models/ee/user.rb index f9d7ebe4ee18b453d4e60288be0d2a49a6fb5d24..721e42dd6610caf804854ffc9c658df220215a18 100644 --- a/ee/app/models/ee/user.rb +++ b/ee/app/models/ee/user.rb @@ -608,7 +608,9 @@ def namespaces_ids_with_code_suggestions_enabled end def code_suggestions_add_on_available? - code_suggestions_add_on_available_namespace_ids.any? + return code_suggestions_add_on_available_namespace_ids.any? if gitlab_saas? + + GitlabSubscriptions::UserAddOnAssignment.by_user(self).any? end def eligible_for_self_managed_code_suggestions? diff --git a/ee/app/policies/ee/global_policy.rb b/ee/app/policies/ee/global_policy.rb index 5fd1e63305b6fe4888b46583485ae88d68d3e555..da18d2fa19d340b92b8fe4aa751c08f7f948c360 100644 --- a/ee/app/policies/ee/global_policy.rb +++ b/ee/app/policies/ee/global_policy.rb @@ -59,10 +59,15 @@ module GlobalPolicy ::License.feature_available?(:code_suggestions) end - condition(:code_suggestions_enabled_by_instance) do + condition(:code_suggestions_enabled_for_user) do next true if ::Gitlab.org_or_com? - ::Gitlab::CurrentSettings.instance_level_code_suggestions_enabled + if ::CodeSuggestions::SelfManaged::SERVICE_START_DATE.past? + @user.code_suggestions_add_on_available? + else # Before service start date + # TODO: Remove this else branch after the service start date + ::Gitlab::CurrentSettings.instance_level_code_suggestions_enabled + end end condition(:code_suggestions_enabled_by_user) do @@ -151,7 +156,7 @@ module GlobalPolicy enable :admin_instance_external_audit_events end - rule { code_suggestions_licensed & code_suggestions_enabled_by_user & code_suggestions_enabled_by_instance } + rule { code_suggestions_licensed & code_suggestions_enabled_by_user & code_suggestions_enabled_for_user } .enable :access_code_suggestions rule { code_suggestions_disabled_by_group }.prevent :access_code_suggestions diff --git a/ee/spec/models/ee/user_spec.rb b/ee/spec/models/ee/user_spec.rb index 001a295da47d952ccb3c511f48aee9848f0c1b76..6fd4f88ca23d9b6c77930a044a782cff6806a419 100644 --- a/ee/spec/models/ee/user_spec.rb +++ b/ee/spec/models/ee/user_spec.rb @@ -3048,16 +3048,43 @@ describe '#code_suggestions_add_on_available?' do subject { user.code_suggestions_add_on_available? } - it 'returns true when the user belongs to a namespace with add on subscription' do - allow(user).to receive(:code_suggestions_add_on_available_namespace_ids).and_return([1]) + context 'on saas', :saas do + it 'returns true when the user belongs to a namespace with an add-on subscription' do + allow(user).to receive(:code_suggestions_add_on_available_namespace_ids).and_return([1]) - is_expected.to eq(true) + is_expected.to eq(true) + end + + it 'returns false when the user does not belong to a namespace with add-on subscription' do + allow(user).to receive(:code_suggestions_add_on_available_namespace_ids).and_return([]) + + is_expected.to eq(false) + end end - it 'returns false when the user does not belong to a namespace with add on subscription' do - allow(user).to receive(:code_suggestions_add_on_available_namespace_ids).and_return([]) + context 'on self-managed' do + let(:user) { create(:user) } + let_it_be(:code_suggestions) { create(:gitlab_subscription_add_on) } + + let_it_be(:add_on_purchase) do + create(:gitlab_subscription_add_on_purchase, namespace: nil, add_on: code_suggestions) + end + + context "when the user is assigned" do + before do + create(:gitlab_subscription_user_add_on_assignment, user: user, add_on_purchase: add_on_purchase) + end - is_expected.to eq(false) + it 'return true' do + expect(user.code_suggestions_add_on_available?).to be_truthy + end + end + + context "when the user is not assigned" do + it 'return false' do + expect(user.code_suggestions_add_on_available?).to be_falsey + end + end end end diff --git a/ee/spec/policies/global_policy_spec.rb b/ee/spec/policies/global_policy_spec.rb index ed0f44d84cd670995924d7c72b2383e6909d91ba..ac371ffa5b714752fd7ba90cf47477c8b30d947f 100644 --- a/ee/spec/policies/global_policy_spec.rb +++ b/ee/spec/policies/global_policy_spec.rb @@ -602,25 +602,67 @@ end context 'when not on .org or .com' do - where(:licensed, :instance_level_code_suggestions_enabled, :cs_matcher) do - true | false | be_disallowed(:access_code_suggestions) - true | true | be_allowed(:access_code_suggestions) - true | false | be_disallowed(:access_code_suggestions) - true | true | be_allowed(:access_code_suggestions) - false | false | be_disallowed(:access_code_suggestions) - false | true | be_disallowed(:access_code_suggestions) - false | false | be_disallowed(:access_code_suggestions) - false | true | be_disallowed(:access_code_suggestions) + context 'when it is before the code suggestions service start date' do + # TODO: When CS service start date has passed, we can remove this + around do |example| + travel_to(::CodeSuggestions::SelfManaged::SERVICE_START_DATE - 1.second) do + example.run + end + end + + # :cs_seat_assigned should be ignored by the code here + where(:licensed, :instance_level_code_suggestions_enabled, :cs_seat_assigned, :cs_matcher) do + true | false | true | be_disallowed(:access_code_suggestions) + true | false | false | be_disallowed(:access_code_suggestions) + true | true | true | be_allowed(:access_code_suggestions) + true | true | false | be_allowed(:access_code_suggestions) + false | false | true | be_disallowed(:access_code_suggestions) + false | false | false | be_disallowed(:access_code_suggestions) + false | true | true | be_disallowed(:access_code_suggestions) + false | true | false | be_disallowed(:access_code_suggestions) + end + + with_them do + before do + allow(::Gitlab).to receive(:org_or_com?).and_return(false) + stub_ee_application_setting( + instance_level_code_suggestions_enabled: instance_level_code_suggestions_enabled + ) + stub_licensed_features(code_suggestions: licensed) + end + + it { is_expected.to cs_matcher } + end end - with_them do - before do - allow(::Gitlab).to receive(:org_or_com?).and_return(false) - stub_ee_application_setting(instance_level_code_suggestions_enabled: instance_level_code_suggestions_enabled) - stub_licensed_features(code_suggestions: licensed) + context 'when it is past the code suggestions service start date' do + around do |example| + travel_to(::CodeSuggestions::SelfManaged::SERVICE_START_DATE + 1.second) do + example.run + end end - it { is_expected.to cs_matcher } + # :instance_level_code_suggestions_enabled should be ignored by the code here + where(:licensed, :instance_level_code_suggestions_enabled, :cs_seat_assigned, :cs_matcher) do + true | false | true | be_allowed(:access_code_suggestions) + true | false | false | be_disallowed(:access_code_suggestions) + true | true | true | be_allowed(:access_code_suggestions) + true | true | false | be_disallowed(:access_code_suggestions) + false | false | true | be_disallowed(:access_code_suggestions) + false | false | false | be_disallowed(:access_code_suggestions) + false | true | true | be_disallowed(:access_code_suggestions) + false | true | false | be_disallowed(:access_code_suggestions) + end + + with_them do + before do + allow(::Gitlab).to receive(:org_or_com?).and_return(false) + stub_licensed_features(code_suggestions: licensed) + allow(current_user).to receive(:code_suggestions_add_on_available?).and_return(cs_seat_assigned) + end + + it { is_expected.to cs_matcher } + end end end end