Skip to content
Snippets Groups Projects
Verified Commit 84e4d7b6 authored by Tianwen Chen's avatar Tianwen Chen :two: Committed by GitLab
Browse files

Merge branch 'ck3g-expose-list-of-available-unit-primitives-for-a-current-user' into 'master'

Expose list of Duo Chat available features

See merge request !168794



Merged-by: default avatarTianwen Chen <tchen@gitlab.com>
Approved-by: default avatarTianwen Chen <tchen@gitlab.com>
Reviewed-by: Alejandro Rodríguez's avatarAlejandro Rodríguez <alejandro@gitlab.com>
Reviewed-by: Matthias Käppler's avatarMatthias Käppler <mkaeppler@gitlab.com>
Co-authored-by: default avatarVitali Tatarintev <vtatarintev@gitlab.com>
parents b87b4554 c1b1b17f
No related branches found
No related tags found
1 merge request!168794Expose list of Duo Chat available features
Pipeline #1509920982 passed with warnings
Pipeline: E2E Omnibus GitLab EE

#1509924876

    Pipeline: E2E CNG

    #1509924873

      Pipeline: E2E GDK

      #1509923197

        +30
        ......@@ -20893,6 +20893,7 @@ The currently authenticated GitLab user.
        | <a id="currentusercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the user was created. |
        | <a id="currentuserdiscord"></a>`discord` | [`String`](#string) | Discord ID of the user. |
        | <a id="currentuserduochatavailable"></a>`duoChatAvailable` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 16.8. **Status**: Experiment. User access to AI chat feature. |
        | <a id="currentuserduochatavailablefeatures"></a>`duoChatAvailableFeatures` **{warning-solid}** | [`[String!]!`](#string) | **Introduced** in GitLab 17.6. **Status**: Experiment. List of available features for AI chat. |
        | <a id="currentuserduocodesuggestionsavailable"></a>`duoCodeSuggestionsAvailable` **{warning-solid}** | [`Boolean!`](#boolean) | **Introduced** in GitLab 16.8. **Status**: Experiment. User access to code suggestions feature. |
        | <a id="currentuseremail"></a>`email` **{warning-solid}** | [`String`](#string) | **Deprecated** in GitLab 13.7. This was renamed. Use: [`User.publicEmail`](#userpublicemail). |
        | <a id="currentuseremails"></a>`emails` | [`EmailConnection`](#emailconnection) | User's email addresses. (see [Connections](#connections)) |
        ......@@ -20,6 +20,11 @@ module CurrentUserType
        resolver: ::Resolvers::Ai::CodeSuggestionsAccessResolver,
        alpha: { milestone: '16.8' },
        description: 'User access to code suggestions feature.'
        field :duo_chat_available_features, [::GraphQL::Types::String],
        resolver: ::Resolvers::Ai::UserAvailableFeaturesResolver,
        alpha: { milestone: '17.6' },
        description: 'List of available features for AI chat.'
        end
        end
        end
        ......
        # frozen_string_literal: true
        module Resolvers
        module Ai
        class UserAvailableFeaturesResolver < BaseResolver
        type [::GraphQL::Types::String], null: false
        def resolve
        return [] unless current_user
        return [] unless duo_chat_enabled?
        ::Ai::AdditionalContext::DUO_CHAT_CONTEXT_CATEGORIES.values
        .map { |category| "include_#{category}_context" }
        .select { |service_name| current_user.allowed_to_use?(:chat, service_name: service_name.to_sym) }
        end
        private
        def duo_chat_enabled?
        # rubocop:disable Gitlab/FeatureFlagWithoutActor -- The flag is used without an actor here
        # ee/app/graphql/resolvers/ai/user_chat_access_resolver.rb we have the same pattern
        Feature.enabled?(:ai_duo_chat_switch, type: :ops) &&
        Ability.allowed?(current_user, :access_duo_chat)
        # rubocop:enable Gitlab/FeatureFlagWithoutActor
        end
        end
        end
        end
        # frozen_string_literal: true
        require 'spec_helper'
        RSpec.describe 'Querying user available features', :clean_gitlab_redis_cache, feature_category: :duo_chat do
        include GraphqlHelpers
        let(:fields) do
        <<~GRAPHQL
        duoChatAvailableFeatures
        GRAPHQL
        end
        let(:query) do
        graphql_query_for('currentUser', fields)
        end
        subject(:graphql_response) { graphql_data.dig('currentUser', 'duoChatAvailableFeatures') }
        context 'when user is not logged in' do
        let(:current_user) { nil }
        it 'returns an empty response' do
        post_graphql(query, current_user: current_user)
        expect(graphql_response).to be_nil
        end
        end
        context 'when user is logged in' do
        let_it_be(:current_user) { create(:user) }
        let(:service) { instance_double(::CloudConnector::BaseAvailableServiceData, name: :any_name) }
        let(:service_not_available) { instance_double(::CloudConnector::BaseAvailableServiceData, name: :any_name) }
        before do
        allow(Ability).to receive(:allowed?).and_call_original
        allow(Ability).to receive(:allowed?).with(current_user, :access_duo_chat).and_return(true)
        allow(::CloudConnector::AvailableServices).to receive(:find_by_name).and_return(service_not_available)
        allow(service_not_available).to receive_message_chain(:add_on_purchases, :assigned_to_user, :any?)
        .and_return(false)
        allow(service_not_available).to receive_messages({ free_access?: false })
        allow(::CloudConnector::AvailableServices).to receive(:find_by_name).with(:include_file_context)
        .and_return(service)
        allow(::CloudConnector::AvailableServices).to receive(:find_by_name).with(:include_merge_request_context)
        .and_return(service)
        allow(service).to receive_message_chain(:add_on_purchases, :assigned_to_user, :any?).and_return(true)
        end
        it 'returns a list of available features' do
        post_graphql(query, current_user: current_user)
        expect(graphql_response).to eq(%w[include_file_context include_merge_request_context])
        end
        context 'when ai_duo_chat_switch feature flag is off' do
        before do
        stub_feature_flags(ai_duo_chat_switch: false)
        end
        it 'returns an empty response' do
        post_graphql(query, current_user: current_user)
        expect(graphql_response).to eq([])
        end
        end
        context 'when user does not have access to chat' do
        before do
        allow(Ability).to receive(:allowed?).with(current_user, :access_duo_chat).and_return(false)
        end
        it 'returns an empty response' do
        post_graphql(query, current_user: current_user)
        expect(graphql_response).to eq([])
        end
        end
        end
        end
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Finish editing this message first!
        Please register or to comment