Commit 3a1cd93c authored by Matija Čupić's avatar Matija Čupić

Create UserCallout create mutation

Creates the UserCallout Create mutation for dismissing user callouts.
parent 9df63f66
# frozen_string_literal: true
module Mutations
module UserCallouts
class Create < ::Mutations::BaseMutation
graphql_name 'UserCalloutCreate'
argument :feature_name,
GraphQL::STRING_TYPE,
required: true,
description: "The feature name you want to dismiss the callout for."
field :user_callout, Types::UserCalloutType,
null: false,
description: 'The user callout dismissed.'
def resolve(feature_name:)
user_callout = find_callout(feature_name)
user_callout.update(dismissed_at: Time.current) if user_callout.valid?
errors = errors_on_object(user_callout)
{
user_callout: user_callout,
errors: errors
}
end
private
def find_callout(feature_name)
current_user.callouts.find_or_initialize_by(feature_name: ::UserCallout.feature_names[feature_name]) # rubocop:disable CodeReuse/ActiveRecord
end
end
end
end
......@@ -97,6 +97,7 @@ module Types
mount_mutation Mutations::Ci::Pipeline::Retry
mount_mutation Mutations::Ci::CiCdSettingsUpdate
mount_mutation Mutations::Namespace::PackageSettings::Update
mount_mutation Mutations::UserCallouts::Create
end
end
......
......@@ -3,10 +3,10 @@
module Types
class UserCalloutFeatureNameEnum < BaseEnum
graphql_name 'UserCalloutFeatureNameEnum'
description 'Name of the feature that the callout is for'
description 'Name of the feature that the callout is for.'
::UserCallout.feature_names.keys.each do |feature_name|
value feature_name.upcase, value: feature_name
value feature_name.upcase, value: feature_name, description: "Callout feature name for #{feature_name}."
end
end
end
# frozen_string_literal: true
module Types
# rubocop:disable Graphql/AuthorizeTypes
class UserCalloutType < BaseObject
class UserCalloutType < BaseObject # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'UserCallout'
field :feature_name, UserCalloutFeatureNameEnum, null: false,
......@@ -10,5 +9,4 @@ module Types
field :dismissed_at, Types::TimeType, null: true,
description: 'Date when the callout was dismissed.'
end
# rubocop:enable Graphql/AuthorizeTypes
end
......@@ -4530,6 +4530,16 @@ Represents a recorded measurement (object count) for the Admins.
| `dismissedAt` | Time | Date when the callout was dismissed. |
| `featureName` | UserCalloutFeatureNameEnum! | Name of the feature that the callout is for. |
### `UserCalloutCreatePayload`
Autogenerated return type of UserCalloutCreate.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `userCallout` | UserCallout! | The user callout dismissed. |
### `UserPermissions`
| Field | Type | Description |
......@@ -5932,32 +5942,32 @@ Name of the feature that the callout is for.
| Value | Description |
| ----- | ----------- |
| `ACCOUNT_RECOVERY_REGULAR_CHECK` | |
| `ACTIVE_USER_COUNT_THRESHOLD` | |
| `ADMIN_INTEGRATIONS_MOVED` | |
| `BUY_PIPELINE_MINUTES_NOTIFICATION_DOT` | |
| `CANARY_DEPLOYMENT` | |
| `CLUSTER_SECURITY_WARNING` | |
| `CUSTOMIZE_HOMEPAGE` | |
| `EOA_BRONZE_PLAN_BANNER` | |
| `FEATURE_FLAGS_NEW_VERSION` | |
| `GCP_SIGNUP_OFFER` | |
| `GEO_ENABLE_HASHED_STORAGE` | |
| `GEO_MIGRATE_HASHED_STORAGE` | |
| `GKE_CLUSTER_INTEGRATION` | |
| `GOLD_TRIAL_BILLINGS` | |
| `NEW_USER_SIGNUPS_CAP_REACHED` | |
| `PERSONAL_ACCESS_TOKEN_EXPIRY` | |
| `REGISTRATION_ENABLED_CALLOUT` | |
| `SERVICE_TEMPLATES_DEPRECATED` | |
| `SUGGEST_PIPELINE` | |
| `SUGGEST_POPOVER_DISMISSED` | |
| `TABS_POSITION_HIGHLIGHT` | |
| `THREAT_MONITORING_INFO` | |
| `ULTIMATE_TRIAL` | |
| `UNFINISHED_TAG_CLEANUP_CALLOUT` | |
| `WEBHOOKS_MOVED` | |
| `WEB_IDE_ALERT_DISMISSED` | |
| `ACCOUNT_RECOVERY_REGULAR_CHECK` | Callout feature name for account_recovery_regular_check. |
| `ACTIVE_USER_COUNT_THRESHOLD` | Callout feature name for active_user_count_threshold. |
| `ADMIN_INTEGRATIONS_MOVED` | Callout feature name for admin_integrations_moved. |
| `BUY_PIPELINE_MINUTES_NOTIFICATION_DOT` | Callout feature name for buy_pipeline_minutes_notification_dot. |
| `CANARY_DEPLOYMENT` | Callout feature name for canary_deployment. |
| `CLUSTER_SECURITY_WARNING` | Callout feature name for cluster_security_warning. |
| `CUSTOMIZE_HOMEPAGE` | Callout feature name for customize_homepage. |
| `EOA_BRONZE_PLAN_BANNER` | Callout feature name for eoa_bronze_plan_banner. |
| `FEATURE_FLAGS_NEW_VERSION` | Callout feature name for feature_flags_new_version. |
| `GCP_SIGNUP_OFFER` | Callout feature name for gcp_signup_offer. |
| `GEO_ENABLE_HASHED_STORAGE` | Callout feature name for geo_enable_hashed_storage. |
| `GEO_MIGRATE_HASHED_STORAGE` | Callout feature name for geo_migrate_hashed_storage. |
| `GKE_CLUSTER_INTEGRATION` | Callout feature name for gke_cluster_integration. |
| `GOLD_TRIAL_BILLINGS` | Callout feature name for gold_trial_billings. |
| `NEW_USER_SIGNUPS_CAP_REACHED` | Callout feature name for new_user_signups_cap_reached. |
| `PERSONAL_ACCESS_TOKEN_EXPIRY` | Callout feature name for personal_access_token_expiry. |
| `REGISTRATION_ENABLED_CALLOUT` | Callout feature name for registration_enabled_callout. |
| `SERVICE_TEMPLATES_DEPRECATED` | Callout feature name for service_templates_deprecated. |
| `SUGGEST_PIPELINE` | Callout feature name for suggest_pipeline. |
| `SUGGEST_POPOVER_DISMISSED` | Callout feature name for suggest_popover_dismissed. |
| `TABS_POSITION_HIGHLIGHT` | Callout feature name for tabs_position_highlight. |
| `THREAT_MONITORING_INFO` | Callout feature name for threat_monitoring_info. |
| `ULTIMATE_TRIAL` | Callout feature name for ultimate_trial. |
| `UNFINISHED_TAG_CLEANUP_CALLOUT` | Callout feature name for unfinished_tag_cleanup_callout. |
| `WEBHOOKS_MOVED` | Callout feature name for webhooks_moved. |
| `WEB_IDE_ALERT_DISMISSED` | Callout feature name for web_ide_alert_dismissed. |
### `UserState`
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::UserCallouts::Create do
let(:current_user) { create(:user) }
let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) }
describe '#resolve' do
subject(:resolve) { mutation.resolve(feature_name: feature_name) }
context 'when feature name is not supported' do
let(:feature_name) { 'not_supported' }
it 'does not create a user callout' do
expect { resolve }.not_to change(UserCallout, :count).from(0)
end
it 'returns error about feature name not being supported' do
expect(resolve[:errors]).to include("Feature name is not included in the list")
end
end
context 'when feature name is supported' do
let(:feature_name) { UserCallout.feature_names.each_key.first.to_s }
it 'creates a user callout' do
expect { resolve }.to change(UserCallout, :count).from(0).to(1)
end
it 'sets dismissed_at for the user callout' do
freeze_time do
expect(resolve[:user_callout].dismissed_at).to eq(Time.current)
end
end
it 'has no errors' do
expect(resolve[:errors]).to be_empty
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Create a user callout' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let(:feature_name) { ::UserCallout.feature_names.keys.first }
let(:input) do
{
'featureName' => feature_name
}
end
let(:mutation) { graphql_mutation(:userCalloutCreate, input) }
let(:mutation_response) { graphql_mutation_response(:userCalloutCreate) }
it 'creates user callout' do
freeze_time do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['userCallout']['featureName']).to eq(feature_name.upcase)
expect(mutation_response['userCallout']['dismissedAt']).to eq(Time.current.iso8601)
end
end
end
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