Commit 91b056ee authored by Mark Chao's avatar Mark Chao Committed by Stan Hu

Add subscription future entry type

This is similar to LicenseHistoryEntry type
parent 07df96fd
...@@ -398,6 +398,16 @@ four standard [pagination arguments](#connection-pagination-arguments): ...@@ -398,6 +398,16 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="querysnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. | | <a id="querysnippetstype"></a>`type` | [`TypeEnum`](#typeenum) | Type of snippet. |
| <a id="querysnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. | | <a id="querysnippetsvisibility"></a>`visibility` | [`VisibilityScopesEnum`](#visibilityscopesenum) | Visibility of the snippet. |
### `Query.subscriptionFutureEntries`
Fields related to entries in future subscriptions.
Returns [`SubscriptionFutureEntryConnection`](#subscriptionfutureentryconnection).
This field returns a [connection](#connections). It accepts the
four standard [pagination arguments](#connection-pagination-arguments):
`before: String`, `after: String`, `first: Int`, `last: Int`.
### `Query.timelogs` ### `Query.timelogs`
Find timelogs visible to the current user. Find timelogs visible to the current user.
...@@ -7566,6 +7576,29 @@ The edge type for [`Submodule`](#submodule). ...@@ -7566,6 +7576,29 @@ The edge type for [`Submodule`](#submodule).
| <a id="submoduleedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | | <a id="submoduleedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="submoduleedgenode"></a>`node` | [`Submodule`](#submodule) | The item at the end of the edge. | | <a id="submoduleedgenode"></a>`node` | [`Submodule`](#submodule) | The item at the end of the edge. |
#### `SubscriptionFutureEntryConnection`
The connection type for [`SubscriptionFutureEntry`](#subscriptionfutureentry).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="subscriptionfutureentryconnectionedges"></a>`edges` | [`[SubscriptionFutureEntryEdge]`](#subscriptionfutureentryedge) | A list of edges. |
| <a id="subscriptionfutureentryconnectionnodes"></a>`nodes` | [`[SubscriptionFutureEntry]`](#subscriptionfutureentry) | A list of nodes. |
| <a id="subscriptionfutureentryconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
#### `SubscriptionFutureEntryEdge`
The edge type for [`SubscriptionFutureEntry`](#subscriptionfutureentry).
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="subscriptionfutureentryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="subscriptionfutureentryedgenode"></a>`node` | [`SubscriptionFutureEntry`](#subscriptionfutureentry) | The item at the end of the edge. |
#### `TerraformStateConnection` #### `TerraformStateConnection`
The connection type for [`TerraformState`](#terraformstate). The connection type for [`TerraformState`](#terraformstate).
...@@ -14739,6 +14772,23 @@ Represents the Geo sync and verification state of a snippet repository. ...@@ -14739,6 +14772,23 @@ Represents the Geo sync and verification state of a snippet repository.
| <a id="submoduletype"></a>`type` | [`EntryType!`](#entrytype) | Type of tree entry. | | <a id="submoduletype"></a>`type` | [`EntryType!`](#entrytype) | Type of tree entry. |
| <a id="submoduleweburl"></a>`webUrl` | [`String`](#string) | Web URL for the sub-module. | | <a id="submoduleweburl"></a>`webUrl` | [`String`](#string) | Web URL for the sub-module. |
### `SubscriptionFutureEntry`
Represents an entry from the future subscriptions.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="subscriptionfutureentrycompany"></a>`company` | [`String`](#string) | Company of the licensee. |
| <a id="subscriptionfutureentryemail"></a>`email` | [`String`](#string) | Email of the licensee. |
| <a id="subscriptionfutureentryexpiresat"></a>`expiresAt` | [`Date`](#date) | Date when the license expires. |
| <a id="subscriptionfutureentryname"></a>`name` | [`String`](#string) | Name of the licensee. |
| <a id="subscriptionfutureentryplan"></a>`plan` | [`String!`](#string) | Name of the subscription plan. |
| <a id="subscriptionfutureentrystartsat"></a>`startsAt` | [`Date`](#date) | Date when the license started. |
| <a id="subscriptionfutureentrytype"></a>`type` | [`String!`](#string) | Type of license the subscription will yield. |
| <a id="subscriptionfutureentryusersinlicensecount"></a>`usersInLicenseCount` | [`Int`](#int) | Number of paid user seats. |
### `TaskCompletionStatus` ### `TaskCompletionStatus`
Completion status of tasks. Completion status of tasks.
...@@ -63,6 +63,11 @@ module EE ...@@ -63,6 +63,11 @@ module EE
resolver: ::Resolvers::Admin::CloudLicenses::LicenseHistoryEntriesResolver, resolver: ::Resolvers::Admin::CloudLicenses::LicenseHistoryEntriesResolver,
description: 'Fields related to entries in the license history.' description: 'Fields related to entries in the license history.'
field :subscription_future_entries, ::Types::Admin::CloudLicenses::SubscriptionFutureEntryType.connection_type,
null: true,
resolver: ::Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolver,
description: 'Fields related to entries in future subscriptions.'
field :ci_minutes_usage, ::Types::Ci::Minutes::NamespaceMonthlyUsageType.connection_type, field :ci_minutes_usage, ::Types::Ci::Minutes::NamespaceMonthlyUsageType.connection_type,
null: true, null: true,
description: 'Monthly CI minutes usage data for the current user.' description: 'Monthly CI minutes usage data for the current user.'
......
# frozen_string_literal: true
module Resolvers
module Admin
module CloudLicenses
class SubscriptionFutureEntriesResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
type [::Types::Admin::CloudLicenses::SubscriptionFutureEntryType], null: true
def resolve
authorize!
::Gitlab::CurrentSettings.future_subscriptions.each do |subscription|
subscription['type'] = subscription['cloud_license_enabled'] ? License::CLOUD_LICENSE_TYPE : License::LICENSE_FILE_TYPE
end
end
private
def authorize!
Ability.allowed?(context[:current_user], :read_licenses) || raise_resource_not_available_error!
end
end
end
end
end
# frozen_string_literal: true
module Types
module Admin
module CloudLicenses
# rubocop: disable Graphql/AuthorizeTypes
class SubscriptionFutureEntryType < BaseObject
field :type, GraphQL::Types::String, null: false,
description: 'Type of license the subscription will yield.'
field :plan, GraphQL::Types::String, null: false,
description: 'Name of the subscription plan.'
field :name, GraphQL::Types::String, null: true,
description: 'Name of the licensee.'
field :email, GraphQL::Types::String, null: true,
description: 'Email of the licensee.'
field :company, GraphQL::Types::String, null: true,
description: 'Company of the licensee.'
field :starts_at, ::Types::DateType, null: true,
description: 'Date when the license started.'
field :expires_at, ::Types::DateType, null: true,
description: 'Date when the license expires.'
field :users_in_license_count, GraphQL::Types::Int, null: true,
description: 'Number of paid user seats.'
graphql_name 'SubscriptionFutureEntry'
description 'Represents an entry from the future subscriptions'
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::Admin::CloudLicenses::SubscriptionFutureEntriesResolver do
include GraphqlHelpers
describe '#resolve' do
subject(:result) { resolve_entries }
let_it_be(:admin) { create(:admin) }
def resolve_entries(current_user: admin)
resolve(described_class, ctx: { current_user: current_user })
end
context 'when current user is unauthorized' do
it 'raises error' do
unauthorized_user = create(:user)
expect do
resolve_entries(current_user: unauthorized_user)
end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'when no subscriptions exist' do
it 'returns an empty array', :enable_admin_mode do
allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([])
expect(result).to eq([])
end
end
context 'when future subscriptions exist' do
let(:cloud_license_enabled) { true }
let(:subscription) do
{
'cloud_license_enabled' => cloud_license_enabled,
'plan' => 'ultimate',
'name' => 'User Example',
'email' => 'user@example.com',
'company' => 'Example Inc.',
'starts_at' => '2021-12-08',
'expires_at' => '2022-12-08',
'users_in_license_count' => 25
}
end
before do
allow(::Gitlab::CurrentSettings).to receive(:future_subscriptions).and_return([subscription])
end
it 'returns the subscription future entries', :enable_admin_mode do
expect(result).to match(
[
hash_including(
'type' => 'cloud',
'plan' => 'ultimate',
'name' => 'User Example',
'email' => 'user@example.com',
'company' => 'Example Inc.',
'starts_at' => '2021-12-08',
'expires_at' => '2022-12-08',
'users_in_license_count' => 25
)
]
)
end
context 'cloud_license_enabled is false' do
let(:cloud_license_enabled) { false }
it 'returns type as license_file', :enable_admin_mode do
expect(result.first).to include('type' => 'license_file')
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SubscriptionFutureEntry'], :enable_admin_mode do
include GraphqlHelpers
let_it_be(:admin) { create(:admin) }
def query(field_name)
%(
{
subscriptionFutureEntries {
nodes {
#{field_name}
}
}
}
)
end
def query_field(field_name)
GitlabSchema.execute(query(field_name), context: { current_user: admin }).as_json
end
it { expect(described_class.graphql_name).to eq('SubscriptionFutureEntry') }
context 'with fields' do
let(:fields) do
%w[plan name email company starts_at expires_at users_in_license_count]
end
it { expect(described_class).to include_graphql_fields(*fields) }
describe 'field values' do
let_it_be(:starts_at) { Date.current - 3.months }
let_it_be(:expires_at) { Date.current + 9.months }
let_it_be(:subscription) do
{
'type' => License::CLOUD_LICENSE_TYPE,
'plan' => 'ultimate',
'name' => 'User Example',
'email' => 'user@example.com',
'company' => 'Example Inc.',
'starts_at' => starts_at,
'expires_at' => expires_at,
'users_in_license_count' => 25
}
end
subject { resolve_field(field_name, subscription) }
describe 'type' do
let(:field_name) { :type }
it { is_expected.to eq(License::CLOUD_LICENSE_TYPE) }
end
describe 'plan' do
let(:field_name) { :plan }
it { is_expected.to eq('ultimate') }
end
describe 'name' do
let(:field_name) { :name }
it { is_expected.to eq('User Example') }
end
describe 'email' do
let(:field_name) { :email }
it { is_expected.to eq('user@example.com') }
end
describe 'company' do
let(:field_name) { :company }
it { is_expected.to eq('Example Inc.') }
end
describe 'starts_at' do
let(:field_name) { :starts_at }
it { is_expected.to eq(starts_at) }
end
describe 'expires_at' do
let(:field_name) { :expires_at }
it { is_expected.to eq(expires_at) }
end
describe 'users_in_license_count' do
let(:field_name) { :users_in_license_count }
it { is_expected.to eq(25) }
end
end
end
end
...@@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['Query'] do ...@@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['Query'] do
:instance_security_dashboard, :instance_security_dashboard,
:iteration, :iteration,
:license_history_entries, :license_history_entries,
:subscription_future_entries,
:vulnerabilities, :vulnerabilities,
:vulnerabilities_count_by_day, :vulnerabilities_count_by_day,
:vulnerability :vulnerability
......
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