mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(server): support installable license (#12181)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for installing self-hosted team licenses via encrypted license files. - Introduced a new "Onetime" license variant for self-hosted environments. - Added a GraphQL mutation to upload and install license files. - License details now display the license variant. - **Bug Fixes** - Improved error messages for license activation and expiration, including dynamic reasons. - **Localization** - Updated and improved license-related error messages for better clarity. - **Tests** - Added comprehensive end-to-end tests for license installation scenarios. - **Chores** - Enhanced environment variable handling and public key management for license verification. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -15,17 +15,14 @@ export const passwordLimitsFragment = `fragment PasswordLimits on PasswordLimits
|
||||
minLength
|
||||
maxLength
|
||||
}`;
|
||||
export const activateLicenseMutation = {
|
||||
id: 'activateLicenseMutation' as const,
|
||||
op: 'activateLicense',
|
||||
query: `mutation activateLicense($workspaceId: String!, $license: String!) {
|
||||
activateLicense(workspaceId: $workspaceId, license: $license) {
|
||||
installedAt
|
||||
validatedAt
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const licenseFragment = `fragment license on License {
|
||||
expiredAt
|
||||
installedAt
|
||||
quantity
|
||||
recurring
|
||||
validatedAt
|
||||
variant
|
||||
}`;
|
||||
export const adminServerConfigQuery = {
|
||||
id: 'adminServerConfigQuery' as const,
|
||||
op: 'adminServerConfig',
|
||||
@@ -893,14 +890,6 @@ export const createWorkspaceMutation = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const deactivateLicenseMutation = {
|
||||
id: 'deactivateLicenseMutation' as const,
|
||||
op: 'deactivateLicense',
|
||||
query: `mutation deactivateLicense($workspaceId: String!) {
|
||||
deactivateLicense(workspaceId: $workspaceId)
|
||||
}`,
|
||||
};
|
||||
|
||||
export const deleteAccountMutation = {
|
||||
id: 'deleteAccountMutation' as const,
|
||||
op: 'deleteAccount',
|
||||
@@ -1065,22 +1054,6 @@ export const getIsOwnerQuery = {
|
||||
deprecations: ["'isOwner' is deprecated: use WorkspaceType[role] instead"],
|
||||
};
|
||||
|
||||
export const getLicenseQuery = {
|
||||
id: 'getLicenseQuery' as const,
|
||||
op: 'getLicense',
|
||||
query: `query getLicense($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
license {
|
||||
expiredAt
|
||||
installedAt
|
||||
quantity
|
||||
recurring
|
||||
validatedAt
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getMemberCountByWorkspaceIdQuery = {
|
||||
id: 'getMemberCountByWorkspaceIdQuery' as const,
|
||||
op: 'getMemberCountByWorkspaceId',
|
||||
@@ -1391,6 +1364,50 @@ export const leaveWorkspaceMutation = {
|
||||
}`,
|
||||
};
|
||||
|
||||
export const activateLicenseMutation = {
|
||||
id: 'activateLicenseMutation' as const,
|
||||
op: 'activateLicense',
|
||||
query: `mutation activateLicense($workspaceId: String!, $license: String!) {
|
||||
activateLicense(workspaceId: $workspaceId, license: $license) {
|
||||
...license
|
||||
}
|
||||
}
|
||||
${licenseFragment}`,
|
||||
};
|
||||
|
||||
export const deactivateLicenseMutation = {
|
||||
id: 'deactivateLicenseMutation' as const,
|
||||
op: 'deactivateLicense',
|
||||
query: `mutation deactivateLicense($workspaceId: String!) {
|
||||
deactivateLicense(workspaceId: $workspaceId)
|
||||
}`,
|
||||
};
|
||||
|
||||
export const getLicenseQuery = {
|
||||
id: 'getLicenseQuery' as const,
|
||||
op: 'getLicense',
|
||||
query: `query getLicense($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
license {
|
||||
...license
|
||||
}
|
||||
}
|
||||
}
|
||||
${licenseFragment}`,
|
||||
};
|
||||
|
||||
export const installLicenseMutation = {
|
||||
id: 'installLicenseMutation' as const,
|
||||
op: 'installLicense',
|
||||
query: `mutation installLicense($workspaceId: String!, $license: Upload!) {
|
||||
installLicense(workspaceId: $workspaceId, license: $license) {
|
||||
...license
|
||||
}
|
||||
}
|
||||
${licenseFragment}`,
|
||||
file: true,
|
||||
};
|
||||
|
||||
export const listNotificationsQuery = {
|
||||
id: 'listNotificationsQuery' as const,
|
||||
op: 'listNotifications',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#import './license.gql'
|
||||
|
||||
mutation activateLicense($workspaceId: String!, $license: String!) {
|
||||
activateLicense(workspaceId: $workspaceId, license: $license) {
|
||||
installedAt
|
||||
validatedAt
|
||||
...license
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
#import './license.gql'
|
||||
|
||||
query getLicense($workspaceId: String!) {
|
||||
workspace(id: $workspaceId) {
|
||||
license {
|
||||
expiredAt
|
||||
installedAt
|
||||
quantity
|
||||
recurring
|
||||
validatedAt
|
||||
...license
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#import './license.gql'
|
||||
|
||||
mutation installLicense($workspaceId: String!, $license: Upload!) {
|
||||
installLicense(workspaceId: $workspaceId, license: $license) {
|
||||
...license
|
||||
}
|
||||
}
|
||||
8
packages/common/graphql/src/graphql/license/license.gql
Normal file
8
packages/common/graphql/src/graphql/license/license.gql
Normal file
@@ -0,0 +1,8 @@
|
||||
fragment license on License {
|
||||
expiredAt
|
||||
installedAt
|
||||
quantity
|
||||
recurring
|
||||
validatedAt
|
||||
variant
|
||||
}
|
||||
@@ -598,6 +598,7 @@ export type ErrorDataUnion =
|
||||
| HttpRequestErrorDataType
|
||||
| InvalidEmailDataType
|
||||
| InvalidHistoryTimestampDataType
|
||||
| InvalidLicenseToActivateDataType
|
||||
| InvalidLicenseUpdateParamsDataType
|
||||
| InvalidOauthCallbackCodeDataType
|
||||
| InvalidPasswordLengthDataType
|
||||
@@ -622,7 +623,6 @@ export type ErrorDataUnion =
|
||||
| UnsupportedSubscriptionPlanDataType
|
||||
| ValidationErrorDataType
|
||||
| VersionRejectedDataType
|
||||
| WorkspaceMembersExceedLimitToDowngradeDataType
|
||||
| WorkspacePermissionNotFoundDataType
|
||||
| WrongSignInCredentialsDataType;
|
||||
|
||||
@@ -701,6 +701,7 @@ export enum ErrorNames {
|
||||
INVALID_PASSWORD_LENGTH = 'INVALID_PASSWORD_LENGTH',
|
||||
INVALID_RUNTIME_CONFIG_TYPE = 'INVALID_RUNTIME_CONFIG_TYPE',
|
||||
INVALID_SUBSCRIPTION_PARAMETERS = 'INVALID_SUBSCRIPTION_PARAMETERS',
|
||||
LICENSE_EXPIRED = 'LICENSE_EXPIRED',
|
||||
LICENSE_NOT_FOUND = 'LICENSE_NOT_FOUND',
|
||||
LICENSE_REVEALED = 'LICENSE_REVEALED',
|
||||
LINK_EXPIRED = 'LINK_EXPIRED',
|
||||
@@ -749,7 +750,6 @@ export enum ErrorNames {
|
||||
WORKSPACE_ID_REQUIRED_FOR_TEAM_SUBSCRIPTION = 'WORKSPACE_ID_REQUIRED_FOR_TEAM_SUBSCRIPTION',
|
||||
WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION = 'WORKSPACE_ID_REQUIRED_TO_UPDATE_TEAM_SUBSCRIPTION',
|
||||
WORKSPACE_LICENSE_ALREADY_EXISTS = 'WORKSPACE_LICENSE_ALREADY_EXISTS',
|
||||
WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE = 'WORKSPACE_MEMBERS_EXCEED_LIMIT_TO_DOWNGRADE',
|
||||
WORKSPACE_PERMISSION_NOT_FOUND = 'WORKSPACE_PERMISSION_NOT_FOUND',
|
||||
WRONG_SIGN_IN_CREDENTIALS = 'WRONG_SIGN_IN_CREDENTIALS',
|
||||
WRONG_SIGN_IN_METHOD = 'WRONG_SIGN_IN_METHOD',
|
||||
@@ -837,6 +837,11 @@ export interface InvalidHistoryTimestampDataType {
|
||||
timestamp: Scalars['String']['output'];
|
||||
}
|
||||
|
||||
export interface InvalidLicenseToActivateDataType {
|
||||
__typename?: 'InvalidLicenseToActivateDataType';
|
||||
reason: Scalars['String']['output'];
|
||||
}
|
||||
|
||||
export interface InvalidLicenseUpdateParamsDataType {
|
||||
__typename?: 'InvalidLicenseUpdateParamsDataType';
|
||||
reason: Scalars['String']['output'];
|
||||
@@ -1029,6 +1034,7 @@ export interface License {
|
||||
quantity: Scalars['Int']['output'];
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: Scalars['DateTime']['output'];
|
||||
variant: Maybe<SubscriptionVariant>;
|
||||
}
|
||||
|
||||
export interface LimitedUserType {
|
||||
@@ -1166,6 +1172,7 @@ export interface Mutation {
|
||||
grantMember: Scalars['Boolean']['output'];
|
||||
/** import users */
|
||||
importUsers: Array<UserImportResultType>;
|
||||
installLicense: License;
|
||||
/** @deprecated use [inviteMembers] instead */
|
||||
inviteBatch: Array<InviteResult>;
|
||||
inviteMembers: Array<InviteResult>;
|
||||
@@ -1391,6 +1398,11 @@ export interface MutationImportUsersArgs {
|
||||
input: ImportUsersInput;
|
||||
}
|
||||
|
||||
export interface MutationInstallLicenseArgs {
|
||||
license: Scalars['Upload']['input'];
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}
|
||||
|
||||
export interface MutationInviteBatchArgs {
|
||||
emails: Array<Scalars['String']['input']>;
|
||||
sendInviteMail?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
@@ -2291,11 +2303,6 @@ export enum WorkspaceMemberStatus {
|
||||
UnderReview = 'UnderReview',
|
||||
}
|
||||
|
||||
export interface WorkspaceMembersExceedLimitToDowngradeDataType {
|
||||
__typename?: 'WorkspaceMembersExceedLimitToDowngradeDataType';
|
||||
limit: Scalars['Int']['output'];
|
||||
}
|
||||
|
||||
export interface WorkspacePermissionNotFoundDataType {
|
||||
__typename?: 'WorkspacePermissionNotFoundDataType';
|
||||
spaceId: Scalars['String']['output'];
|
||||
@@ -2474,20 +2481,6 @@ export interface TokenType {
|
||||
token: Scalars['String']['output'];
|
||||
}
|
||||
|
||||
export type ActivateLicenseMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
license: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type ActivateLicenseMutation = {
|
||||
__typename?: 'Mutation';
|
||||
activateLicense: {
|
||||
__typename?: 'License';
|
||||
installedAt: string;
|
||||
validatedAt: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type AdminServerConfigQueryVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type AdminServerConfigQuery = {
|
||||
@@ -3495,15 +3488,6 @@ export type CreateWorkspaceMutation = {
|
||||
};
|
||||
};
|
||||
|
||||
export type DeactivateLicenseMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type DeactivateLicenseMutation = {
|
||||
__typename?: 'Mutation';
|
||||
deactivateLicense: boolean;
|
||||
};
|
||||
|
||||
export type DeleteAccountMutationVariables = Exact<{ [key: string]: never }>;
|
||||
|
||||
export type DeleteAccountMutation = {
|
||||
@@ -3693,25 +3677,6 @@ export type GetIsOwnerQueryVariables = Exact<{
|
||||
|
||||
export type GetIsOwnerQuery = { __typename?: 'Query'; isOwner: boolean };
|
||||
|
||||
export type GetLicenseQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetLicenseQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
license: {
|
||||
__typename?: 'License';
|
||||
expiredAt: string | null;
|
||||
installedAt: string;
|
||||
quantity: number;
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: string;
|
||||
} | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type GetMemberCountByWorkspaceIdQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
@@ -4059,6 +4024,81 @@ export type LeaveWorkspaceMutation = {
|
||||
leaveWorkspace: boolean;
|
||||
};
|
||||
|
||||
export type ActivateLicenseMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
license: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type ActivateLicenseMutation = {
|
||||
__typename?: 'Mutation';
|
||||
activateLicense: {
|
||||
__typename?: 'License';
|
||||
expiredAt: string | null;
|
||||
installedAt: string;
|
||||
quantity: number;
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: string;
|
||||
variant: SubscriptionVariant | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type DeactivateLicenseMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type DeactivateLicenseMutation = {
|
||||
__typename?: 'Mutation';
|
||||
deactivateLicense: boolean;
|
||||
};
|
||||
|
||||
export type GetLicenseQueryVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type GetLicenseQuery = {
|
||||
__typename?: 'Query';
|
||||
workspace: {
|
||||
__typename?: 'WorkspaceType';
|
||||
license: {
|
||||
__typename?: 'License';
|
||||
expiredAt: string | null;
|
||||
installedAt: string;
|
||||
quantity: number;
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: string;
|
||||
variant: SubscriptionVariant | null;
|
||||
} | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type InstallLicenseMutationVariables = Exact<{
|
||||
workspaceId: Scalars['String']['input'];
|
||||
license: Scalars['Upload']['input'];
|
||||
}>;
|
||||
|
||||
export type InstallLicenseMutation = {
|
||||
__typename?: 'Mutation';
|
||||
installLicense: {
|
||||
__typename?: 'License';
|
||||
expiredAt: string | null;
|
||||
installedAt: string;
|
||||
quantity: number;
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: string;
|
||||
variant: SubscriptionVariant | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type LicenseFragment = {
|
||||
__typename?: 'License';
|
||||
expiredAt: string | null;
|
||||
installedAt: string;
|
||||
quantity: number;
|
||||
recurring: SubscriptionRecurring;
|
||||
validatedAt: string;
|
||||
variant: SubscriptionVariant | null;
|
||||
};
|
||||
|
||||
export type ListNotificationsQueryVariables = Exact<{
|
||||
pagination: PaginationInput;
|
||||
}>;
|
||||
@@ -4795,11 +4835,6 @@ export type Queries =
|
||||
variables: GetIsOwnerQueryVariables;
|
||||
response: GetIsOwnerQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getLicenseQuery';
|
||||
variables: GetLicenseQueryVariables;
|
||||
response: GetLicenseQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getMemberCountByWorkspaceIdQuery';
|
||||
variables: GetMemberCountByWorkspaceIdQueryVariables;
|
||||
@@ -4895,6 +4930,11 @@ export type Queries =
|
||||
variables: InvoicesQueryVariables;
|
||||
response: InvoicesQuery;
|
||||
}
|
||||
| {
|
||||
name: 'getLicenseQuery';
|
||||
variables: GetLicenseQueryVariables;
|
||||
response: GetLicenseQuery;
|
||||
}
|
||||
| {
|
||||
name: 'listNotificationsQuery';
|
||||
variables: ListNotificationsQueryVariables;
|
||||
@@ -4952,11 +4992,6 @@ export type Queries =
|
||||
};
|
||||
|
||||
export type Mutations =
|
||||
| {
|
||||
name: 'activateLicenseMutation';
|
||||
variables: ActivateLicenseMutationVariables;
|
||||
response: ActivateLicenseMutation;
|
||||
}
|
||||
| {
|
||||
name: 'createChangePasswordUrlMutation';
|
||||
variables: CreateChangePasswordUrlMutationVariables;
|
||||
@@ -5162,11 +5197,6 @@ export type Mutations =
|
||||
variables: CreateWorkspaceMutationVariables;
|
||||
response: CreateWorkspaceMutation;
|
||||
}
|
||||
| {
|
||||
name: 'deactivateLicenseMutation';
|
||||
variables: DeactivateLicenseMutationVariables;
|
||||
response: DeactivateLicenseMutation;
|
||||
}
|
||||
| {
|
||||
name: 'deleteAccountMutation';
|
||||
variables: DeleteAccountMutationVariables;
|
||||
@@ -5192,6 +5222,21 @@ export type Mutations =
|
||||
variables: LeaveWorkspaceMutationVariables;
|
||||
response: LeaveWorkspaceMutation;
|
||||
}
|
||||
| {
|
||||
name: 'activateLicenseMutation';
|
||||
variables: ActivateLicenseMutationVariables;
|
||||
response: ActivateLicenseMutation;
|
||||
}
|
||||
| {
|
||||
name: 'deactivateLicenseMutation';
|
||||
variables: DeactivateLicenseMutationVariables;
|
||||
response: DeactivateLicenseMutation;
|
||||
}
|
||||
| {
|
||||
name: 'installLicenseMutation';
|
||||
variables: InstallLicenseMutationVariables;
|
||||
response: InstallLicenseMutation;
|
||||
}
|
||||
| {
|
||||
name: 'mentionUserMutation';
|
||||
variables: MentionUserMutationVariables;
|
||||
|
||||
Reference in New Issue
Block a user