chore(backend): convert basic RefreshToken model to TypeORM entity (#2401)

* chore: convert basic RefreshToken model to TypeORM entity

Co-authored-by: v1b3m <vibenjamin6@gmail.com>

* Fix import

Co-authored-by: v1b3m <vibenjamin6@gmail.com>

---------

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
This commit is contained in:
gitstart-twenty
2023-11-14 17:54:04 +05:45
committed by GitHub
parent 6eb4e00ce1
commit a69711429b
11 changed files with 262 additions and 6 deletions

View File

@ -207,7 +207,7 @@ export type CreateRelationInput = {
fromLabel: Scalars['String']['input'];
fromName: Scalars['String']['input'];
fromObjectMetadataId: Scalars['String']['input'];
relationType: Scalars['String']['input'];
relationType: RelationMetadataType;
toIcon?: InputMaybe<Scalars['String']['input']>;
toLabel: Scalars['String']['input'];
toName: Scalars['String']['input'];
@ -452,10 +452,10 @@ export enum FieldMetadataType {
Date = 'DATE',
Email = 'EMAIL',
Enum = 'ENUM',
Probability = 'PROBABILITY',
Money = 'MONEY',
Number = 'NUMBER',
Phone = 'PHONE',
Probability = 'PROBABILITY',
Relation = 'RELATION',
Text = 'TEXT',
Url = 'URL',
@ -527,6 +527,7 @@ export type ObjectDeleteResponse = {
id?: Maybe<Scalars['ID']['output']>;
isActive?: Maybe<Scalars['Boolean']['output']>;
isCustom?: Maybe<Scalars['Boolean']['output']>;
isSystem?: Maybe<Scalars['Boolean']['output']>;
labelPlural?: Maybe<Scalars['String']['output']>;
labelSingular?: Maybe<Scalars['String']['output']>;
namePlural?: Maybe<Scalars['String']['output']>;
@ -671,6 +672,22 @@ export type QueryRelationsArgs = {
paging?: CursorPaging;
};
export type RefreshToken = {
__typename?: 'RefreshToken';
createdAt: Scalars['DateTime']['output'];
expiresAt: Scalars['DateTime']['output'];
id: Scalars['ID']['output'];
updatedAt: Scalars['DateTime']['output'];
};
export type RefreshTokenEdge = {
__typename?: 'RefreshTokenEdge';
/** Cursor for this node. */
cursor: Scalars['ConnectionCursor']['output'];
/** The node containing the RefreshToken */
node: RefreshToken;
};
export type RelationConnection = {
__typename?: 'RelationConnection';
/** Array of edges. */
@ -681,6 +698,13 @@ export type RelationConnection = {
totalCount: Scalars['Int']['output'];
};
/** Type of the relation */
export enum RelationMetadataType {
ManyToMany = 'MANY_TO_MANY',
OneToMany = 'ONE_TO_MANY',
OneToOne = 'ONE_TO_ONE'
}
export type Support = {
__typename?: 'Support';
supportDriver: Scalars['String']['output'];
@ -850,6 +874,7 @@ export type Object = {
id: Scalars['ID']['output'];
isActive: Scalars['Boolean']['output'];
isCustom: Scalars['Boolean']['output'];
isSystem: Scalars['Boolean']['output'];
labelPlural: Scalars['String']['output'];
labelSingular: Scalars['String']['output'];
namePlural: Scalars['String']['output'];
@ -877,7 +902,7 @@ export type Relation = {
fromObjectMetadata: Object;
fromObjectMetadataId: Scalars['String']['output'];
id: Scalars['ID']['output'];
relationType: Scalars['String']['output'];
relationType: RelationMetadataType;
toFieldMetadataId: Scalars['String']['output'];
toObjectMetadata: Object;
toObjectMetadataId: Scalars['String']['output'];
@ -939,7 +964,7 @@ export type DeleteOneFieldMetadataItemMutation = { __typename?: 'Mutation', dele
export type ObjectMetadataItemsQueryVariables = Exact<{ [key: string]: never; }>;
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', totalCount: number, edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: string, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isActive: boolean, createdAt: any, updatedAt: any, fields: { __typename?: 'ObjectFieldsConnection', totalCount: number, edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, placeholder?: string | null, isCustom: boolean, isActive: boolean, isNullable: boolean, createdAt: any, updatedAt: any, fromRelationMetadata?: { __typename?: 'relation', id: string, relationType: string } | null, toRelationMetadata?: { __typename?: 'relation', id: string, relationType: string } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', totalCount: number, edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: string, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isActive: boolean, createdAt: any, updatedAt: any, fields: { __typename?: 'ObjectFieldsConnection', totalCount: number, edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, placeholder?: string | null, isCustom: boolean, isActive: boolean, isNullable: boolean, createdAt: any, updatedAt: any, fromRelationMetadata?: { __typename?: 'relation', id: string, relationType: RelationMetadataType } | null, toRelationMetadata?: { __typename?: 'relation', id: string, relationType: RelationMetadataType } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
export const CreateOneObjectMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneObjectMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<CreateOneObjectMetadataItemMutation, CreateOneObjectMetadataItemMutationVariables>;

View File

@ -1322,6 +1322,7 @@ export enum FieldMetadataType {
Money = 'MONEY',
Number = 'NUMBER',
Phone = 'PHONE',
Probability = 'PROBABILITY',
Relation = 'RELATION',
Text = 'TEXT',
Url = 'URL',
@ -1799,6 +1800,7 @@ export type ObjectDeleteResponse = {
id?: Maybe<Scalars['ID']>;
isActive?: Maybe<Scalars['Boolean']>;
isCustom?: Maybe<Scalars['Boolean']>;
isSystem?: Maybe<Scalars['Boolean']>;
labelPlural?: Maybe<Scalars['String']>;
labelSingular?: Maybe<Scalars['String']>;
namePlural?: Maybe<Scalars['String']>;
@ -2558,6 +2560,32 @@ export enum QueryMode {
Insensitive = 'insensitive'
}
export type RefreshToken = {
__typename?: 'RefreshToken';
createdAt: Scalars['DateTime'];
expiresAt: Scalars['DateTime'];
id: Scalars['ID'];
updatedAt: Scalars['DateTime'];
};
export type RefreshTokenConnection = {
__typename?: 'RefreshTokenConnection';
/** Array of edges. */
edges: Array<RefreshTokenEdge>;
/** Paging information */
pageInfo: PageInfo;
/** Fetch total count of records */
totalCount: Scalars['Int'];
};
export type RefreshTokenEdge = {
__typename?: 'RefreshTokenEdge';
/** Cursor for this node. */
cursor: Scalars['ConnectionCursor'];
/** The node containing the RefreshToken */
node: RefreshToken;
};
export type RelationConnection = {
__typename?: 'RelationConnection';
/** Array of edges. */
@ -2568,6 +2596,13 @@ export type RelationConnection = {
totalCount: Scalars['Int'];
};
/** Type of the relation */
export enum RelationMetadataType {
ManyToMany = 'MANY_TO_MANY',
OneToMany = 'ONE_TO_MANY',
OneToOne = 'ONE_TO_ONE'
}
export enum SortOrder {
Asc = 'asc',
Desc = 'desc'
@ -3151,6 +3186,7 @@ export type Object = {
id: Scalars['ID'];
isActive: Scalars['Boolean'];
isCustom: Scalars['Boolean'];
isSystem: Scalars['Boolean'];
labelPlural: Scalars['String'];
labelSingular: Scalars['String'];
namePlural: Scalars['String'];
@ -3178,7 +3214,7 @@ export type Relation = {
fromObjectMetadata: Object;
fromObjectMetadataId: Scalars['String'];
id: Scalars['ID'];
relationType: Scalars['String'];
relationType: RelationMetadataType;
toFieldMetadataId: Scalars['String'];
toObjectMetadata: Object;
toObjectMetadataId: Scalars['String'];

View File

@ -9,6 +9,7 @@ import GraphQLJSON from 'graphql-type-json';
import config from '../../ormconfig';
import { UserModule } from './userv2/user.module';
import { RefreshTokenModule } from './refresh-token/refresh-token.module';
@Module({
imports: [
@ -23,6 +24,7 @@ import { UserModule } from './userv2/user.module';
path: '/graphqlv2',
}),
UserModule,
RefreshTokenModule,
],
exports: [UserModule],
})

View File

@ -0,0 +1,11 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsDate, IsNotEmpty } from 'class-validator';
@InputType()
export class CreateRefreshTokenInput {
@IsDate()
@IsNotEmpty()
@Field()
expiresAt: Date;
}

View File

@ -0,0 +1,24 @@
import {
BeforeCreateOneHook,
CreateOneInputType,
} from '@ptc-org/nestjs-query-graphql';
import { v4 as uuidv4 } from 'uuid';
import { RefreshToken } from 'src/coreV2/refresh-token/refresh-token.entity';
export class BeforeCreateOneRefreshToken<T extends RefreshToken>
implements BeforeCreateOneHook<T, any>
{
async run(
instance: CreateOneInputType<T>,
context: any,
): Promise<CreateOneInputType<T>> {
const userId = context?.req?.user?.user?.id;
instance.input.userId = userId;
// FIXME: These fields should be autogenerated, we need to run a migration for this
instance.input.id = uuidv4();
instance.input.updatedAt = new Date();
return instance;
}
}

View File

@ -0,0 +1,41 @@
import {
AutoResolverOpts,
PagingStrategies,
ReadResolverOpts,
} from '@ptc-org/nestjs-query-graphql';
import { SortDirection } from '@ptc-org/nestjs-query-core';
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
import { RefreshToken } from './refresh-token.entity';
import { CreateRefreshTokenInput } from './dtos/create-refresh-token.input';
export const refreshTokenAutoResolverOpts: AutoResolverOpts<
any,
any,
unknown,
unknown,
ReadResolverOpts<any>,
PagingStrategies
>[] = [
{
EntityClass: RefreshToken,
DTOClass: RefreshToken,
CreateDTOClass: CreateRefreshTokenInput,
enableTotalCount: true,
pagingStrategy: PagingStrategies.CURSOR,
read: {
defaultSort: [{ field: 'id', direction: SortDirection.DESC }],
},
create: {
many: { disabled: true },
},
update: {
many: { disabled: true },
one: { disabled: true },
},
delete: { many: { disabled: true }, one: { disabled: true } },
guards: [JwtAuthGuard],
},
];

View File

@ -0,0 +1,59 @@
import { Field, ID, ObjectType } from '@nestjs/graphql';
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
JoinColumn,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
import {
Authorize,
BeforeCreateOne,
IDField,
} from '@ptc-org/nestjs-query-graphql';
import { User } from 'src/coreV2/userv2/user.entity';
import { BeforeCreateOneRefreshToken } from './hooks/before-create-one-refresh-token.hook';
@Entity('refresh_tokens')
@ObjectType('RefreshToken')
@BeforeCreateOne(BeforeCreateOneRefreshToken)
@Authorize({
authorize: (context: any) => ({
userId: { eq: context?.req?.user?.user?.id },
}),
})
export class RefreshToken {
@IDField(() => ID)
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => User, (user) => user.refreshTokens)
@JoinColumn({ name: 'userId' })
user: User;
@Column()
userId: string;
@Field()
@Column('time with time zone')
expiresAt: Date;
@Column('timestamp with time zone', { nullable: true })
deletedAt: Date | null;
@Column('timestamp with time zone', { nullable: true })
revokedAt: Date | null;
@Field()
@CreateDateColumn({ type: 'timestamp with time zone' })
createdAt: Date;
@Field()
@UpdateDateColumn({ type: 'timestamp with time zone' })
updatedAt: Date;
}

View File

@ -0,0 +1,20 @@
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])],
services: [RefreshTokenService],
resolvers: refreshTokenAutoResolverOpts,
}),
],
})
export class RefreshTokenModule {}

View File

@ -0,0 +1,28 @@
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { RefreshToken } from 'src/coreV2/refresh-token/refresh-token.entity';
import { RefreshTokenService } from './refresh-token.service';
describe('RefreshTokenService', () => {
let service: RefreshTokenService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
RefreshTokenService,
{
provide: getRepositoryToken(RefreshToken),
useValue: {},
},
],
}).compile();
service = module.get<RefreshTokenService>(RefreshTokenService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

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

View File

@ -1,4 +1,6 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import { RefreshToken } from 'src/coreV2/refresh-token/refresh-token.entity';
@Entity('users')
export class User {
@ -16,4 +18,7 @@ export class User {
@Column({ default: false })
emailVerified: boolean;
@OneToMany(() => RefreshToken, (refreshToken) => refreshToken.user)
refreshTokens: RefreshToken[];
}