Rename refreshToken to appToken and add fields (#4691)

This commit is contained in:
martmull
2024-03-28 14:07:12 +01:00
committed by GitHub
parent a28ffee80f
commit 0cc0929bd0
20 changed files with 146 additions and 82 deletions

View File

@ -0,0 +1,39 @@
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UpdateRefreshTokenTable1711624086253
implements MigrationInterface
{
name = 'UpdateRefreshTokenTable1711624086253';
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."refreshToken" RENAME TO "appToken"`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" ADD "workspaceId" uuid`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" ADD "type" text NOT NULL DEFAULT 'REFRESH_TOKEN'`,
);
await queryRunner.query(`ALTER TABLE "core"."appToken" ADD "value" text`);
await queryRunner.query(
`ALTER TABLE "core"."appToken" ADD CONSTRAINT "FK_d6ae19a7aa2bbd4919053257772" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."appToken" DROP CONSTRAINT "FK_d6ae19a7aa2bbd4919053257772"`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" DROP COLUMN "value"`,
);
await queryRunner.query(`ALTER TABLE "core"."appToken" DROP COLUMN "type"`);
await queryRunner.query(
`ALTER TABLE "core"."appToken" DROP COLUMN "workspaceId"`,
);
await queryRunner.query(
`ALTER TABLE "core"."appToken" RENAME TO "refreshToken"`,
);
}
}

View File

@ -6,7 +6,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity'; import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
@ -28,7 +28,7 @@ export class TypeORMService implements OnModuleInit, OnModuleDestroy {
User, User,
Workspace, Workspace,
UserWorkspace, UserWorkspace,
RefreshToken, AppToken,
FeatureFlagEntity, FeatureFlagEntity,
BillingSubscription, BillingSubscription,
BillingSubscriptionItem, BillingSubscriptionItem,

View File

@ -4,13 +4,11 @@ import {
ReadResolverOpts, ReadResolverOpts,
} from '@ptc-org/nestjs-query-graphql'; } from '@ptc-org/nestjs-query-graphql';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { CreateAppTokenInput } from 'src/engine/core-modules/app-token/dtos/create-app-token.input';
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
import { RefreshToken } from './refresh-token.entity'; export const appTokenAutoResolverOpts: AutoResolverOpts<
import { CreateRefreshTokenInput } from './dtos/create-refresh-token.input';
export const refreshTokenAutoResolverOpts: AutoResolverOpts<
any, any,
any, any,
unknown, unknown,
@ -19,9 +17,9 @@ export const refreshTokenAutoResolverOpts: AutoResolverOpts<
PagingStrategies PagingStrategies
>[] = [ >[] = [
{ {
EntityClass: RefreshToken, EntityClass: AppToken,
DTOClass: RefreshToken, DTOClass: AppToken,
CreateDTOClass: CreateRefreshTokenInput, CreateDTOClass: CreateAppTokenInput,
enableTotalCount: true, enableTotalCount: true,
pagingStrategy: PagingStrategies.CURSOR, pagingStrategy: PagingStrategies.CURSOR,
read: { read: {

View File

@ -11,19 +11,22 @@ import {
} from 'typeorm'; } from 'typeorm';
import { BeforeCreateOne, IDField } from '@ptc-org/nestjs-query-graphql'; import { BeforeCreateOne, IDField } from '@ptc-org/nestjs-query-graphql';
import { BeforeCreateOneAppToken } from 'src/engine/core-modules/app-token/hooks/before-create-one-app-token.hook';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
export enum AppTokenType {
RefreshToken = 'REFRESH_TOKEN',
}
import { BeforeCreateOneRefreshToken } from './hooks/before-create-one-refresh-token.hook'; @Entity({ name: 'appToken', schema: 'core' })
@ObjectType('AppToken')
@Entity({ name: 'refreshToken', schema: 'core' }) @BeforeCreateOne(BeforeCreateOneAppToken)
@ObjectType('RefreshToken') export class AppToken {
@BeforeCreateOne(BeforeCreateOneRefreshToken)
export class RefreshToken {
@IDField(() => ID) @IDField(() => ID)
@PrimaryGeneratedColumn('uuid') @PrimaryGeneratedColumn('uuid')
id: string; id: string;
@ManyToOne(() => User, (user) => user.refreshTokens, { @ManyToOne(() => User, (user) => user.appTokens, {
onDelete: 'CASCADE', onDelete: 'CASCADE',
}) })
@JoinColumn({ name: 'userId' }) @JoinColumn({ name: 'userId' })
@ -32,6 +35,22 @@ export class RefreshToken {
@Column() @Column()
userId: string; userId: string;
@ManyToOne(() => Workspace, (workspace) => workspace.appTokens, {
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'workspaceId' })
workspace: Workspace;
@Column({ nullable: true })
workspaceId: string;
@Field()
@Column({ nullable: false, type: 'text', default: AppTokenType.RefreshToken })
type: AppTokenType;
@Column({ nullable: true, type: 'text' })
value: string;
@Field() @Field()
@Column('timestamp with time zone') @Column('timestamp with time zone')
expiresAt: Date; expiresAt: Date;

View File

@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { appTokenAutoResolverOpts } from 'src/engine/core-modules/app-token/app-token.auto-resolver-opts';
import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
@Module({
imports: [
NestjsQueryGraphQLModule.forFeature({
imports: [NestjsQueryTypeOrmModule.forFeature([AppToken], 'core')],
services: [AppTokenService],
resolvers: appTokenAutoResolverOpts,
}),
],
})
export class AppTokenModule {}

View File

@ -3,7 +3,7 @@ import { Field, InputType } from '@nestjs/graphql';
import { IsDate, IsNotEmpty } from 'class-validator'; import { IsDate, IsNotEmpty } from 'class-validator';
@InputType() @InputType()
export class CreateRefreshTokenInput { export class CreateAppTokenInput {
@IsDate() @IsDate()
@IsNotEmpty() @IsNotEmpty()
@Field() @Field()

View File

@ -4,9 +4,9 @@ import {
} from '@ptc-org/nestjs-query-graphql'; } from '@ptc-org/nestjs-query-graphql';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
export class BeforeCreateOneRefreshToken<T extends RefreshToken> export class BeforeCreateOneAppToken<T extends AppToken>
implements BeforeCreateOneHook<T, any> implements BeforeCreateOneHook<T, any>
{ {
async run( async run(

View File

@ -1,25 +1,24 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm'; import { getRepositoryToken } from '@nestjs/typeorm';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { RefreshTokenService } from './refresh-token.service'; describe('AppTokenService', () => {
let service: AppTokenService;
describe('RefreshTokenService', () => {
let service: RefreshTokenService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [ providers: [
RefreshTokenService, AppTokenService,
{ {
provide: getRepositoryToken(RefreshToken), provide: getRepositoryToken(AppToken),
useValue: {}, useValue: {},
}, },
], ],
}).compile(); }).compile();
service = module.get<RefreshTokenService>(RefreshTokenService); service = module.get<AppTokenService>(AppTokenService);
}); });
it('should be defined', () => { it('should be defined', () => {

View File

@ -0,0 +1,5 @@
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
export class AppTokenService extends TypeOrmQueryService<AppToken> {}

View File

@ -7,7 +7,7 @@ import { HttpModule } from '@nestjs/axios';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { UserModule } from 'src/engine/core-modules/user/user.module'; import { UserModule } from 'src/engine/core-modules/user/user.module';
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
@ -48,7 +48,7 @@ const jwtModule = JwtModule.registerAsync({
WorkspaceManagerModule, WorkspaceManagerModule,
TypeORMModule, TypeORMModule,
TypeOrmModule.forFeature( TypeOrmModule.forFeature(
[Workspace, User, RefreshToken, FeatureFlagEntity], [Workspace, User, AppToken, FeatureFlagEntity],
'core', 'core',
), ),
HttpModule, HttpModule,

View File

@ -10,6 +10,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { AppTokenInput } from 'src/engine/core-modules/auth/dto/app-token.input';
import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard'; import { JwtAuthGuard } from 'src/engine/guards/jwt.auth.guard';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { assert } from 'src/utils/assert'; import { assert } from 'src/utils/assert';
@ -34,7 +35,6 @@ import { ExchangeAuthCode } from 'src/engine/core-modules/auth/dto/exchange-auth
import { ApiKeyToken, AuthTokens } from './dto/token.entity'; import { ApiKeyToken, AuthTokens } from './dto/token.entity';
import { TokenService } from './services/token.service'; import { TokenService } from './services/token.service';
import { RefreshTokenInput } from './dto/refresh-token.input';
import { Verify } from './dto/verify.entity'; import { Verify } from './dto/verify.entity';
import { VerifyInput } from './dto/verify.input'; import { VerifyInput } from './dto/verify.input';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
@ -170,13 +170,13 @@ export class AuthResolver {
} }
@Mutation(() => AuthTokens) @Mutation(() => AuthTokens)
async renewToken(@Args() args: RefreshTokenInput): Promise<AuthTokens> { async renewToken(@Args() args: AppTokenInput): Promise<AuthTokens> {
if (!args.refreshToken) { if (!args.appToken) {
throw new BadRequestException('Refresh token is mendatory'); throw new BadRequestException('Refresh token is mendatory');
} }
const tokens = await this.tokenService.generateTokensFromRefreshToken( const tokens = await this.tokenService.generateTokensFromRefreshToken(
args.refreshToken, args.appToken,
); );
return { tokens: tokens }; return { tokens: tokens };

View File

@ -3,9 +3,9 @@ import { ArgsType, Field } from '@nestjs/graphql';
import { IsNotEmpty, IsString } from 'class-validator'; import { IsNotEmpty, IsString } from 'class-validator';
@ArgsType() @ArgsType()
export class RefreshTokenInput { export class AppTokenInput {
@Field(() => String) @Field(() => String)
@IsNotEmpty() @IsNotEmpty()
@IsString() @IsString()
refreshToken: string; appToken: string;
} }

View File

@ -3,7 +3,7 @@ import { JwtService } from '@nestjs/jwt';
import { getRepositoryToken } from '@nestjs/typeorm'; import { getRepositoryToken } from '@nestjs/typeorm';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { JwtAuthStrategy } from 'src/engine/core-modules/auth/strategies/jwt.auth.strategy'; import { JwtAuthStrategy } from 'src/engine/core-modules/auth/strategies/jwt.auth.strategy';
import { EmailService } from 'src/engine/integrations/email/email.service'; import { EmailService } from 'src/engine/integrations/email/email.service';
@ -39,7 +39,7 @@ describe('TokenService', () => {
useValue: {}, useValue: {},
}, },
{ {
provide: getRepositoryToken(RefreshToken, 'core'), provide: getRepositoryToken(AppToken, 'core'),
useValue: {}, useValue: {},
}, },
{ {

View File

@ -34,7 +34,10 @@ import {
} from 'src/engine/core-modules/auth/dto/token.entity'; } from 'src/engine/core-modules/auth/dto/token.entity';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service'; import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import {
AppToken,
AppTokenType,
} from 'src/engine/core-modules/app-token/app-token.entity';
import { ValidatePasswordResetToken } from 'src/engine/core-modules/auth/dto/validate-password-reset-token.entity'; import { ValidatePasswordResetToken } from 'src/engine/core-modules/auth/dto/validate-password-reset-token.entity';
import { EmailService } from 'src/engine/integrations/email/email.service'; import { EmailService } from 'src/engine/integrations/email/email.service';
import { InvalidatePassword } from 'src/engine/core-modules/auth/dto/invalidate-password.entity'; import { InvalidatePassword } from 'src/engine/core-modules/auth/dto/invalidate-password.entity';
@ -53,8 +56,8 @@ export class TokenService {
private readonly environmentService: EnvironmentService, private readonly environmentService: EnvironmentService,
@InjectRepository(User, 'core') @InjectRepository(User, 'core')
private readonly userRepository: Repository<User>, private readonly userRepository: Repository<User>,
@InjectRepository(RefreshToken, 'core') @InjectRepository(AppToken, 'core')
private readonly refreshTokenRepository: Repository<RefreshToken>, private readonly appTokenRepository: Repository<AppToken>,
@InjectRepository(Workspace, 'core') @InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>, private readonly workspaceRepository: Repository<Workspace>,
private readonly emailService: EmailService, private readonly emailService: EmailService,
@ -103,15 +106,15 @@ export class TokenService {
const refreshTokenPayload = { const refreshTokenPayload = {
userId, userId,
expiresAt, expiresAt,
type: AppTokenType.RefreshToken,
}; };
const jwtPayload = { const jwtPayload = {
sub: userId, sub: userId,
}; };
const refreshToken = const refreshToken = this.appTokenRepository.create(refreshTokenPayload);
this.refreshTokenRepository.create(refreshTokenPayload);
await this.refreshTokenRepository.save(refreshToken); await this.appTokenRepository.save(refreshToken);
return { return {
token: this.jwtService.sign(jwtPayload, { token: this.jwtService.sign(jwtPayload, {
@ -360,7 +363,7 @@ export class TokenService {
UnprocessableEntityException, UnprocessableEntityException,
); );
const token = await this.refreshTokenRepository.findOneBy({ const token = await this.appTokenRepository.findOneBy({
id: jwtPayload.jti, id: jwtPayload.jti,
}); });
@ -379,15 +382,16 @@ export class TokenService {
) { ) {
// Revoke all user refresh tokens // Revoke all user refresh tokens
await Promise.all( await Promise.all(
user.refreshTokens.map( user.appTokens.map(async ({ id, type }) => {
async ({ id }) => if (type === AppTokenType.RefreshToken) {
await this.refreshTokenRepository.update( await this.appTokenRepository.update(
{ id }, { id },
{ {
revokedAt: new Date(), revokedAt: new Date(),
}, },
), );
), }
}),
); );
throw new ForbiddenException( throw new ForbiddenException(
@ -408,7 +412,7 @@ export class TokenService {
} = await this.verifyRefreshToken(token); } = await this.verifyRefreshToken(token);
// Revoke old refresh token // Revoke old refresh token
await this.refreshTokenRepository.update( await this.appTokenRepository.update(
{ {
id, id,
}, },

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module'; import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
import { UserModule } from 'src/engine/core-modules/user/user.module'; import { UserModule } from 'src/engine/core-modules/user/user.module';
import { RefreshTokenModule } from 'src/engine/core-modules/refresh-token/refresh-token.module'; import { AppTokenModule } from 'src/engine/core-modules/app-token/app-token.module';
import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { OpenApiModule } from 'src/engine/core-modules/open-api/open-api.module'; import { OpenApiModule } from 'src/engine/core-modules/open-api/open-api.module';
@ -25,7 +25,7 @@ import { ClientConfigModule } from './client-config/client-config.module';
FeatureFlagModule, FeatureFlagModule,
FileModule, FileModule,
OpenApiModule, OpenApiModule,
RefreshTokenModule, AppTokenModule,
TimelineMessagingModule, TimelineMessagingModule,
TimelineCalendarEventModule, TimelineCalendarEventModule,
UserModule, UserModule,

View File

@ -1,20 +0,0 @@
import { Module } from '@nestjs/common';
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { RefreshToken } from './refresh-token.entity';
import { refreshTokenAutoResolverOpts } from './refresh-token.auto-resolver-opts';
import { RefreshTokenService } from './services/refresh-token.service';
@Module({
imports: [
NestjsQueryGraphQLModule.forFeature({
imports: [NestjsQueryTypeOrmModule.forFeature([RefreshToken], 'core')],
services: [RefreshTokenService],
resolvers: refreshTokenAutoResolverOpts,
}),
],
})
export class RefreshTokenModule {}

View File

@ -1,5 +0,0 @@
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity';
export class RefreshTokenService extends TypeOrmQueryService<RefreshToken> {}

View File

@ -11,7 +11,7 @@ import {
} from 'typeorm'; } from 'typeorm';
import { IDField } from '@ptc-org/nestjs-query-graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql';
import { RefreshToken } from 'src/engine/core-modules/refresh-token/refresh-token.entity'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto'; import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
@ -85,10 +85,10 @@ export class User {
@Column({ nullable: true }) @Column({ nullable: true })
passwordResetTokenExpiresAt: Date; passwordResetTokenExpiresAt: Date;
@OneToMany(() => RefreshToken, (refreshToken) => refreshToken.user, { @OneToMany(() => AppToken, (appToken) => appToken.user, {
cascade: true, cascade: true,
}) })
refreshTokens: RefreshToken[]; appTokens: AppToken[];
@Field(() => WorkspaceMember, { nullable: true }) @Field(() => WorkspaceMember, { nullable: true })
workspaceMember: WorkspaceMember; workspaceMember: WorkspaceMember;

View File

@ -15,6 +15,7 @@ import { User } from 'src/engine/core-modules/user/user.entity';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
@Entity({ name: 'workspace', schema: 'core' }) @Entity({ name: 'workspace', schema: 'core' })
@ObjectType('Workspace') @ObjectType('Workspace')
@ -55,6 +56,11 @@ export class Workspace {
@UpdateDateColumn({ type: 'timestamp with time zone' }) @UpdateDateColumn({ type: 'timestamp with time zone' })
updatedAt: Date; updatedAt: Date;
@OneToMany(() => AppToken, (appToken) => appToken.workspace, {
cascade: true,
})
appTokens: AppToken[];
@OneToMany(() => User, (user) => user.defaultWorkspace) @OneToMany(() => User, (user) => user.defaultWorkspace)
users: User[]; users: User[];

View File

@ -13,7 +13,7 @@ import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/d
const coreObjectNames = [ const coreObjectNames = [
'featureFlag', 'featureFlag',
'refreshToken', 'appToken',
'workspace', 'workspace',
'user', 'user',
'event', 'event',