feat(server): support selfhost licenses (#8947)

This commit is contained in:
forehalo
2025-01-22 10:21:07 +00:00
parent 22e424d7de
commit 994d758c07
31 changed files with 1653 additions and 127 deletions
@@ -0,0 +1,126 @@
import {
Args,
Field,
Int,
Mutation,
ObjectType,
Parent,
ResolveField,
Resolver,
} from '@nestjs/graphql';
import { ActionForbidden, Config } from '../../base';
import { CurrentUser } from '../../core/auth';
import { Permission, PermissionService } from '../../core/permission';
import { WorkspaceType } from '../../core/workspaces';
import { SubscriptionRecurring } from '../payment/types';
import { LicenseService } from './service';
@ObjectType()
export class License {
@Field(() => Int)
quantity!: number;
@Field(() => SubscriptionRecurring)
recurring!: string;
@Field(() => Date)
installedAt!: Date;
@Field(() => Date)
validatedAt!: Date;
@Field(() => Date, { nullable: true })
expiredAt!: Date | null;
}
@Resolver(() => WorkspaceType)
export class LicenseResolver {
constructor(
private readonly config: Config,
private readonly service: LicenseService,
private readonly permission: PermissionService
) {}
@ResolveField(() => License, {
complexity: 2,
description: 'The selfhost license of the workspace',
nullable: true,
})
async license(
@CurrentUser() user: CurrentUser,
@Parent() workspace: WorkspaceType
): Promise<License | null> {
// NOTE(@forehalo):
// we can't simply disable license resolver for non-selfhosted server
// it will make the gql codegen messed up.
if (!this.config.isSelfhosted) {
return null;
}
await this.permission.checkWorkspaceIs(
workspace.id,
user.id,
Permission.Owner
);
return this.service.getLicense(workspace.id);
}
@Mutation(() => License)
async activateLicense(
@CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string,
@Args('license') license: string
) {
if (!this.config.isSelfhosted) {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
Permission.Owner
);
return this.service.activateTeamLicense(workspaceId, license);
}
@Mutation(() => Boolean)
async deactivateLicense(
@CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string
) {
if (!this.config.isSelfhosted) {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
Permission.Owner
);
return this.service.deactivateTeamLicense(workspaceId);
}
@Mutation(() => String)
async createSelfhostWorkspaceCustomerPortal(
@CurrentUser() user: CurrentUser,
@Args('workspaceId') workspaceId: string
) {
if (!this.config.isSelfhosted) {
throw new ActionForbidden();
}
await this.permission.checkWorkspaceIs(
workspaceId,
user.id,
Permission.Owner
);
const { url } = await this.service.createCustomerPortal(workspaceId);
return url;
}
}