diff --git a/server/ormconfig.ts b/server/ormconfig.ts new file mode 100644 index 000000000..19a3d8f28 --- /dev/null +++ b/server/ormconfig.ts @@ -0,0 +1,16 @@ +import dotenv from 'dotenv'; +import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions'; +dotenv.config(); + +export default { + url: process.env.PG_DATABASE_URL, + type: 'postgres', + entities: [__dirname + '/src/coreV2/**/*.entity{.ts,.js}'], + synchronize: false, + migrationsRun: true, + migrationsTableName: '_typeorm_migrations', + migrations: [__dirname + '/migrations/**/*{.ts,.js}'], + cli: { + migrationsDir: __dirname + '/migrations', + }, +} as PostgresConnectionOptions; diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 959c97163..ae4d07121 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -12,6 +12,7 @@ import { TokenExpiredError, JsonWebTokenError, verify } from 'jsonwebtoken'; import { AppService } from './app.service'; import { CoreModule } from './core/core.module'; +import { CoreV2Module } from './coreV2/core.module'; import { IntegrationsModule } from './integrations/integrations.module'; import { PrismaModule } from './database/prisma.module'; import { HealthModule } from './health/health.module'; @@ -102,6 +103,7 @@ import { ExceptionFilter } from './filters/exception.filter'; AbilityModule, IntegrationsModule, CoreModule, + CoreV2Module, TenantModule, ], providers: [ diff --git a/server/src/coreV2/core.module.ts b/server/src/coreV2/core.module.ts new file mode 100644 index 000000000..ebd6789bd --- /dev/null +++ b/server/src/coreV2/core.module.ts @@ -0,0 +1,29 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { GraphQLModule } from '@nestjs/graphql'; + +import { YogaDriverConfig, YogaDriver } from '@graphql-yoga/nestjs'; +import GraphQLJSON from 'graphql-type-json'; + +// eslint-disable-next-line no-restricted-imports +import config from '../../ormconfig'; + +import { UserModule } from './userv2/user.module'; + +@Module({ + imports: [ + TypeOrmModule.forRoot(config), + GraphQLModule.forRoot({ + context: ({ req }) => ({ req }), + driver: YogaDriver, + autoSchemaFile: true, + include: [CoreV2Module], + resolvers: { JSON: GraphQLJSON }, + plugins: [], + path: '/graphqlv2', + }), + UserModule, + ], + exports: [UserModule], +}) +export class CoreV2Module {} diff --git a/server/src/coreV2/userv2/user.dto.ts b/server/src/coreV2/userv2/user.dto.ts new file mode 100644 index 000000000..fed9e9632 --- /dev/null +++ b/server/src/coreV2/userv2/user.dto.ts @@ -0,0 +1,19 @@ +import { Field, ID, ObjectType } from '@nestjs/graphql'; + +@ObjectType() +export class TUser { + @Field(() => ID, { nullable: false }) + id: number; + + @Field(() => String, { nullable: true }) + firstName: string | null; + + @Field(() => String, { nullable: true }) + lastName: string | null; + + @Field(() => String, { nullable: false }) + email: string; + + @Field(() => Boolean, { nullable: false, defaultValue: false }) + emailVerified: boolean; +} diff --git a/server/src/coreV2/userv2/user.entity.ts b/server/src/coreV2/userv2/user.entity.ts new file mode 100644 index 000000000..cde86c733 --- /dev/null +++ b/server/src/coreV2/userv2/user.entity.ts @@ -0,0 +1,19 @@ +import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm'; + +@Entity('users') +export class User { + @PrimaryGeneratedColumn() + id: number; + + @Column() + firstName: string; + + @Column() + lastName: string; + + @Column() + email: string; + + @Column({ default: false }) + emailVerified: boolean; +} diff --git a/server/src/coreV2/userv2/user.module.ts b/server/src/coreV2/userv2/user.module.ts new file mode 100644 index 000000000..823e38995 --- /dev/null +++ b/server/src/coreV2/userv2/user.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { AbilityModule } from 'src/ability/ability.module'; + +import { User } from './user.entity'; +import { UserResolver } from './user.resolver'; +import { UserService } from './user.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([User]), AbilityModule], + providers: [UserService, UserResolver], +}) +export class UserModule {} diff --git a/server/src/coreV2/userv2/user.resolver.ts b/server/src/coreV2/userv2/user.resolver.ts new file mode 100644 index 000000000..c2194891c --- /dev/null +++ b/server/src/coreV2/userv2/user.resolver.ts @@ -0,0 +1,28 @@ +import { Resolver, Query } from '@nestjs/graphql'; +import { UseFilters, UseGuards } from '@nestjs/common'; + +import { ExceptionFilter } from 'src/filters/exception.filter'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; +import { AbilityGuard } from 'src/guards/ability.guard'; +import { CheckAbilities } from 'src/decorators/check-abilities.decorator'; +import { ReadUserAbilityHandler } from 'src/ability/handlers/user.ability-handler'; + +import { TUser } from './user.dto'; +import { UserService } from './user.service'; +import { User } from './user.entity'; + +@UseGuards(JwtAuthGuard) +@Resolver(() => TUser) +export class UserResolver { + constructor(private readonly userService: UserService) {} + + @UseFilters(ExceptionFilter) + @Query(() => [TUser], { + nullable: false, + }) + @UseGuards(AbilityGuard) + @CheckAbilities(ReadUserAbilityHandler) + async findManyUserV2(): Promise[]> { + return this.userService.findAll(); + } +} diff --git a/server/src/coreV2/userv2/user.service.ts b/server/src/coreV2/userv2/user.service.ts new file mode 100644 index 000000000..686f27ce0 --- /dev/null +++ b/server/src/coreV2/userv2/user.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Repository } from 'typeorm'; + +import { User } from './user.entity'; + +@Injectable() +export class UserService { + constructor( + @InjectRepository(User) + private usersRepository: Repository, + ) {} + + async findAll() { + return this.usersRepository.find(); + } +}